Blender  V3.3
readfile.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2001-2002 NaN Holding BV. All rights reserved. */
3 
8 #include <ctype.h> /* for isdigit. */
9 #include <fcntl.h> /* for open flags (O_BINARY, O_RDONLY). */
10 #include <limits.h>
11 #include <stdarg.h> /* for va_start/end. */
12 #include <stddef.h> /* for offsetof. */
13 #include <stdlib.h> /* for atoi. */
14 #include <time.h> /* for gmtime. */
15 
16 #include "BLI_utildefines.h"
17 #ifndef WIN32
18 # include <unistd.h> /* for read close */
19 #else
20 # include "BLI_winstuff.h"
21 # include "winsock2.h"
22 # include <io.h> /* for open close read */
23 #endif
24 
25 #include "CLG_log.h"
26 
27 /* allow readfile to use deprecated functionality */
28 #define DNA_DEPRECATED_ALLOW
29 
30 #include "DNA_anim_types.h"
31 #include "DNA_asset_types.h"
32 #include "DNA_cachefile_types.h"
33 #include "DNA_collection_types.h"
34 #include "DNA_fileglobal_types.h"
35 #include "DNA_genfile.h"
36 #include "DNA_key_types.h"
37 #include "DNA_layer_types.h"
38 #include "DNA_node_types.h"
39 #include "DNA_packedFile_types.h"
40 #include "DNA_sdna_types.h"
41 #include "DNA_sound_types.h"
42 #include "DNA_vfont_types.h"
43 #include "DNA_volume_types.h"
44 #include "DNA_workspace_types.h"
45 
46 #include "MEM_guardedalloc.h"
47 
48 #include "BLI_blenlib.h"
49 #include "BLI_endian_defines.h"
50 #include "BLI_endian_switch.h"
51 #include "BLI_ghash.h"
52 #include "BLI_linklist.h"
53 #include "BLI_math.h"
54 #include "BLI_memarena.h"
55 #include "BLI_mempool.h"
56 #include "BLI_threads.h"
57 
58 #include "PIL_time.h"
59 
60 #include "BLT_translation.h"
61 
62 #include "BKE_anim_data.h"
63 #include "BKE_animsys.h"
64 #include "BKE_asset.h"
65 #include "BKE_blender_version.h"
66 #include "BKE_collection.h"
67 #include "BKE_global.h" /* for G */
68 #include "BKE_idprop.h"
69 #include "BKE_idtype.h"
70 #include "BKE_layer.h"
71 #include "BKE_lib_id.h"
72 #include "BKE_lib_override.h"
73 #include "BKE_lib_query.h"
74 #include "BKE_main.h" /* for Main */
75 #include "BKE_main_idmap.h"
76 #include "BKE_material.h"
77 #include "BKE_modifier.h"
78 #include "BKE_node.h" /* for tree type defines */
79 #include "BKE_object.h"
80 #include "BKE_packedFile.h"
81 #include "BKE_report.h"
82 #include "BKE_scene.h"
83 #include "BKE_screen.h"
84 #include "BKE_undo_system.h"
85 #include "BKE_workspace.h"
86 
87 #include "DRW_engine.h"
88 
89 #include "DEG_depsgraph.h"
90 
91 #include "BLO_blend_defs.h"
92 #include "BLO_blend_validate.h"
93 #include "BLO_read_write.h"
94 #include "BLO_readfile.h"
95 #include "BLO_undofile.h"
96 
97 #include "SEQ_clipboard.h"
98 #include "SEQ_iterator.h"
99 #include "SEQ_modifier.h"
100 #include "SEQ_sequencer.h"
101 #include "SEQ_utils.h"
102 
103 #include "readfile.h"
104 
105 #include <errno.h>
106 
107 /* Make preferences read-only. */
108 #define U (*((const UserDef *)&U))
109 
167 #define USE_BHEAD_READ_ON_DEMAND
168 
170 #define USE_GHASH_BHEAD
171 
173 #define USE_GHASH_RESTORE_POINTER
174 
175 static CLG_LogRef LOG = {"blo.readfile"};
176 static CLG_LogRef LOG_UNDO = {"blo.readfile.undo"};
177 
178 /* local prototypes */
179 static void read_libraries(FileData *basefd, ListBase *mainlist);
180 static void *read_struct(FileData *fd, BHead *bh, const char *blockname);
181 static BHead *find_bhead_from_code_name(FileData *fd, const short idcode, const char *name);
182 static BHead *find_bhead_from_idname(FileData *fd, const char *idname);
183 
184 typedef struct BHeadN {
185  struct BHeadN *next, *prev;
186 #ifdef USE_BHEAD_READ_ON_DEMAND
188  off64_t file_offset;
190  bool has_data;
191 #endif
193  struct BHead bhead;
195 
196 #define BHEADN_FROM_BHEAD(bh) ((BHeadN *)POINTER_OFFSET(bh, -(int)offsetof(BHeadN, bhead)))
197 
202 #define BHEAD_USE_READ_ON_DEMAND(bhead) ((bhead)->code == DATA)
203 
204 void BLO_reportf_wrap(BlendFileReadReport *reports, eReportType type, const char *format, ...)
205 {
206  char fixed_buf[1024]; /* should be long enough */
207 
208  va_list args;
209 
210  va_start(args, format);
211  vsnprintf(fixed_buf, sizeof(fixed_buf), format, args);
212  va_end(args);
213 
214  fixed_buf[sizeof(fixed_buf) - 1] = '\0';
215 
216  BKE_report(reports->reports, type, fixed_buf);
217 
218  if (G.background == 0) {
219  printf("%s: %s\n", BKE_report_type_str(type), fixed_buf);
220  }
221 }
222 
223 /* for reporting linking messages */
224 static const char *library_parent_filepath(Library *lib)
225 {
226  return lib->parent ? lib->parent->filepath_abs : "<direct>";
227 }
228 
229 /* -------------------------------------------------------------------- */
233 typedef struct OldNew {
234  const void *oldp;
235  void *newp;
236  /* `nr` is "user count" for data, and ID code for libdata. */
237  int nr;
239 
240 typedef struct OldNewMap {
241  /* Array that stores the actual entries. */
243  int nentries;
244  /* Hash-map that stores indices into the `entries` array. */
246 
249 
250 #define ENTRIES_CAPACITY(onm) (1ll << (onm)->capacity_exp)
251 #define MAP_CAPACITY(onm) (1ll << ((onm)->capacity_exp + 1))
252 #define SLOT_MASK(onm) (MAP_CAPACITY(onm) - 1)
253 #define DEFAULT_SIZE_EXP 6
254 #define PERTURB_SHIFT 5
255 
256 /* based on the probing algorithm used in Python dicts. */
257 #define ITER_SLOTS(onm, KEY, SLOT_NAME, INDEX_NAME) \
258  uint32_t hash = BLI_ghashutil_ptrhash(KEY); \
259  uint32_t mask = SLOT_MASK(onm); \
260  uint perturb = hash; \
261  int SLOT_NAME = mask & hash; \
262  int INDEX_NAME = onm->map[SLOT_NAME]; \
263  for (;; SLOT_NAME = mask & ((5 * SLOT_NAME) + 1 + perturb), \
264  perturb >>= PERTURB_SHIFT, \
265  INDEX_NAME = onm->map[SLOT_NAME])
266 
267 static void oldnewmap_insert_index_in_map(OldNewMap *onm, const void *ptr, int index)
268 {
269  ITER_SLOTS (onm, ptr, slot, stored_index) {
270  if (stored_index == -1) {
271  onm->map[slot] = index;
272  break;
273  }
274  }
275 }
276 
278 {
279  ITER_SLOTS (onm, entry.oldp, slot, index) {
280  if (index == -1) {
281  onm->entries[onm->nentries] = entry;
282  onm->map[slot] = onm->nentries;
283  onm->nentries++;
284  break;
285  }
286  if (onm->entries[index].oldp == entry.oldp) {
287  onm->entries[index] = entry;
288  break;
289  }
290  }
291 }
292 
293 static OldNew *oldnewmap_lookup_entry(const OldNewMap *onm, const void *addr)
294 {
295  ITER_SLOTS (onm, addr, slot, index) {
296  if (index >= 0) {
297  OldNew *entry = &onm->entries[index];
298  if (entry->oldp == addr) {
299  return entry;
300  }
301  }
302  else {
303  return NULL;
304  }
305  }
306 }
307 
309 {
310  memset(onm->map, 0xFF, MAP_CAPACITY(onm) * sizeof(*onm->map));
311 }
312 
314 {
315  onm->capacity_exp++;
316  onm->entries = MEM_reallocN(onm->entries, sizeof(*onm->entries) * ENTRIES_CAPACITY(onm));
317  onm->map = MEM_reallocN(onm->map, sizeof(*onm->map) * MAP_CAPACITY(onm));
318  oldnewmap_clear_map(onm);
319  for (int i = 0; i < onm->nentries; i++) {
320  oldnewmap_insert_index_in_map(onm, onm->entries[i].oldp, i);
321  }
322 }
323 
324 /* Public OldNewMap API */
325 
326 static void oldnewmap_init_data(OldNewMap *onm, const int capacity_exp)
327 {
328  memset(onm, 0x0, sizeof(*onm));
329 
330  onm->capacity_exp = capacity_exp;
331  onm->entries = MEM_malloc_arrayN(
332  ENTRIES_CAPACITY(onm), sizeof(*onm->entries), "OldNewMap.entries");
333  onm->map = MEM_malloc_arrayN(MAP_CAPACITY(onm), sizeof(*onm->map), "OldNewMap.map");
334  oldnewmap_clear_map(onm);
335 }
336 
338 {
339  OldNewMap *onm = MEM_mallocN(sizeof(*onm), "OldNewMap");
340 
342 
343  return onm;
344 }
345 
346 static void oldnewmap_insert(OldNewMap *onm, const void *oldaddr, void *newaddr, int nr)
347 {
348  if (oldaddr == NULL || newaddr == NULL) {
349  return;
350  }
351 
352  if (UNLIKELY(onm->nentries == ENTRIES_CAPACITY(onm))) {
354  }
355 
356  OldNew entry;
357  entry.oldp = oldaddr;
358  entry.newp = newaddr;
359  entry.nr = nr;
360  oldnewmap_insert_or_replace(onm, entry);
361 }
362 
363 static void oldnewmap_lib_insert(FileData *fd, const void *oldaddr, ID *newaddr, int nr)
364 {
365  oldnewmap_insert(fd->libmap, oldaddr, newaddr, nr);
366 }
367 
368 void blo_do_versions_oldnewmap_insert(OldNewMap *onm, const void *oldaddr, void *newaddr, int nr)
369 {
370  oldnewmap_insert(onm, oldaddr, newaddr, nr);
371 }
372 
373 static void *oldnewmap_lookup_and_inc(OldNewMap *onm, const void *addr, bool increase_users)
374 {
375  OldNew *entry = oldnewmap_lookup_entry(onm, addr);
376  if (entry == NULL) {
377  return NULL;
378  }
379  if (increase_users) {
380  entry->nr++;
381  }
382  return entry->newp;
383 }
384 
385 /* for libdata, OldNew.nr has ID code, no increment */
386 static void *oldnewmap_liblookup(OldNewMap *onm, const void *addr, const void *lib)
387 {
388  if (addr == NULL) {
389  return NULL;
390  }
391 
392  ID *id = oldnewmap_lookup_and_inc(onm, addr, false);
393  if (id == NULL) {
394  return NULL;
395  }
396  if (!lib || id->lib) {
397  return id;
398  }
399  return NULL;
400 }
401 
402 static void oldnewmap_clear(OldNewMap *onm)
403 {
404  /* Free unused data. */
405  for (int i = 0; i < onm->nentries; i++) {
406  OldNew *entry = &onm->entries[i];
407  if (entry->nr == 0) {
408  MEM_freeN(entry->newp);
409  entry->newp = NULL;
410  }
411  }
412 
413  MEM_freeN(onm->entries);
414  MEM_freeN(onm->map);
415 
417 }
418 
419 static void oldnewmap_free(OldNewMap *onm)
420 {
421  MEM_freeN(onm->entries);
422  MEM_freeN(onm->map);
423  MEM_freeN(onm);
424 }
425 
426 #undef ENTRIES_CAPACITY
427 #undef MAP_CAPACITY
428 #undef SLOT_MASK
429 #undef DEFAULT_SIZE_EXP
430 #undef PERTURB_SHIFT
431 #undef ITER_SLOTS
432 
435 /* -------------------------------------------------------------------- */
439 static void add_main_to_main(Main *mainvar, Main *from)
440 {
441  ListBase *lbarray[INDEX_ID_MAX], *fromarray[INDEX_ID_MAX];
442  int a;
443 
444  if (from->is_read_invalid) {
445  mainvar->is_read_invalid = true;
446  }
447 
448  set_listbasepointers(mainvar, lbarray);
449  a = set_listbasepointers(from, fromarray);
450  while (a--) {
451  BLI_movelisttolist(lbarray[a], fromarray[a]);
452  }
453 }
454 
455 void blo_join_main(ListBase *mainlist)
456 {
457  Main *tojoin, *mainl;
458 
459  mainl = mainlist->first;
460 
461  if (mainl->id_map != NULL) {
462  /* Cannot keep this since we add some IDs from joined mains. */
464  mainl->id_map = NULL;
465  }
466 
467  while ((tojoin = mainl->next)) {
468  add_main_to_main(mainl, tojoin);
469  BLI_remlink(mainlist, tojoin);
470  tojoin->next = tojoin->prev = NULL;
471  BKE_main_free(tojoin);
472  }
473 }
474 
475 static void split_libdata(ListBase *lb_src, Main **lib_main_array, const uint lib_main_array_len)
476 {
477  for (ID *id = lb_src->first, *idnext; id; id = idnext) {
478  idnext = id->next;
479 
480  if (id->lib) {
481  if (((uint)id->lib->temp_index < lib_main_array_len) &&
482  /* this check should never fail, just in case 'id->lib' is a dangling pointer. */
483  (lib_main_array[id->lib->temp_index]->curlib == id->lib)) {
484  Main *mainvar = lib_main_array[id->lib->temp_index];
485  ListBase *lb_dst = which_libbase(mainvar, GS(id->name));
486  BLI_remlink(lb_src, id);
487  BLI_addtail(lb_dst, id);
488  }
489  else {
490  CLOG_ERROR(&LOG, "Invalid library for '%s'", id->name);
491  }
492  }
493  }
494 }
495 
496 void blo_split_main(ListBase *mainlist, Main *main)
497 {
498  mainlist->first = mainlist->last = main;
499  main->next = NULL;
500 
501  if (BLI_listbase_is_empty(&main->libraries)) {
502  return;
503  }
504 
505  if (main->id_map != NULL) {
506  /* Cannot keep this since we remove some IDs from given main. */
507  BKE_main_idmap_destroy(main->id_map);
508  main->id_map = NULL;
509  }
510 
511  /* (Library.temp_index -> Main), lookup table */
512  const uint lib_main_array_len = BLI_listbase_count(&main->libraries);
513  Main **lib_main_array = MEM_malloc_arrayN(lib_main_array_len, sizeof(*lib_main_array), __func__);
514 
515  int i = 0;
516  for (Library *lib = main->libraries.first; lib; lib = lib->id.next, i++) {
517  Main *libmain = BKE_main_new();
518  libmain->curlib = lib;
519  libmain->versionfile = lib->versionfile;
520  libmain->subversionfile = lib->subversionfile;
523  BLI_addtail(mainlist, libmain);
524  lib->temp_index = i;
525  lib_main_array[i] = libmain;
526  }
527 
528  ListBase *lbarray[INDEX_ID_MAX];
529  i = set_listbasepointers(main, lbarray);
530  while (i--) {
531  ID *id = lbarray[i]->first;
532  if (id == NULL || GS(id->name) == ID_LI) {
533  /* No ID_LI data-block should ever be linked anyway, but just in case, better be explicit. */
534  continue;
535  }
536  split_libdata(lbarray[i], lib_main_array, lib_main_array_len);
537  }
538 
539  MEM_freeN(lib_main_array);
540 }
541 
542 /* Hot-fix file minversion for a specific range of versions.
543  *
544  * This is needed for newer LTS releases of 3.6 to be able to properly open files from early
545  * development versions of 4.0. */
547 {
548  if ((fg->minversion > BLENDER_FILE_VERSION) ||
550  if (fg->minversion < 306 || (fg->minversion == 306 && fg->minsubversion <= 11)) {
553  }
554  }
555 }
556 
558 {
559  BHead *bhead;
560 
561  for (bhead = blo_bhead_first(fd); bhead; bhead = blo_bhead_next(fd, bhead)) {
562  if (bhead->code == GLOB) {
563  FileGlobal *fg = read_struct(fd, bhead, "Global");
564  if (fg) {
566 
567  main->subversionfile = fg->subversion;
568  main->minversionfile = fg->minversion;
569  main->minsubversionfile = fg->minsubversion;
570  MEM_freeN(fg);
571  }
572  else if (bhead->code == ENDB) {
573  break;
574  }
575  }
576  }
577  if (main->curlib) {
578  main->curlib->versionfile = main->versionfile;
579  main->curlib->subversionfile = main->subversionfile;
580  }
581 }
582 
583 static bool blo_bhead_is_id(const BHead *bhead)
584 {
585  /* BHead codes are four bytes (like 'ENDB', 'TEST', etc.), but if the two most-significant bytes
586  * are zero, the values actually indicate an ID type. */
587  return bhead->code <= 0xFFFF;
588 }
589 
590 static bool blo_bhead_is_id_valid_type(const BHead *bhead)
591 {
592  if (!blo_bhead_is_id(bhead)) {
593  return false;
594  }
595 
596  const short id_type_code = bhead->code & 0xFFFF;
597  return BKE_idtype_idcode_is_valid(id_type_code);
598 }
599 
600 #ifdef USE_GHASH_BHEAD
602 {
603  BHead *bhead;
604 
605  /* dummy values */
606  bool is_link = false;
607  int code_prev = ENDB;
608  uint reserve = 0;
609 
610  for (bhead = blo_bhead_first(fd); bhead; bhead = blo_bhead_next(fd, bhead)) {
611  if (code_prev != bhead->code) {
612  code_prev = bhead->code;
613  is_link = blo_bhead_is_id_valid_type(bhead) ?
614  BKE_idtype_idcode_is_linkable((short)code_prev) :
615  false;
616  }
617 
618  if (is_link) {
619  reserve += 1;
620  }
621  }
622 
624 
625  fd->bhead_idname_hash = BLI_ghash_str_new_ex(__func__, reserve);
626 
627  for (bhead = blo_bhead_first(fd); bhead; bhead = blo_bhead_next(fd, bhead)) {
628  if (code_prev != bhead->code) {
629  code_prev = bhead->code;
630  is_link = blo_bhead_is_id_valid_type(bhead) ?
631  BKE_idtype_idcode_is_linkable((short)code_prev) :
632  false;
633  }
634 
635  if (is_link) {
636  BLI_ghash_insert(fd->bhead_idname_hash, (void *)blo_bhead_id_name(fd, bhead), bhead);
637  }
638  }
639 }
640 #endif
641 
642 static Main *blo_find_main(FileData *fd, const char *filepath, const char *relabase)
643 {
644  ListBase *mainlist = fd->mainlist;
645  Main *m;
646  Library *lib;
647  char name1[FILE_MAX];
648 
649  BLI_strncpy(name1, filepath, sizeof(name1));
650  BLI_path_normalize(relabase, name1);
651 
652  // printf("blo_find_main: relabase %s\n", relabase);
653  // printf("blo_find_main: original in %s\n", filepath);
654  // printf("blo_find_main: converted to %s\n", name1);
655 
656  for (m = mainlist->first; m; m = m->next) {
657  const char *libname = (m->curlib) ? m->curlib->filepath_abs : m->filepath;
658 
659  if (BLI_path_cmp(name1, libname) == 0) {
660  if (G.debug & G_DEBUG) {
661  CLOG_INFO(&LOG, 3, "Found library %s", libname);
662  }
663  return m;
664  }
665  }
666 
667  m = BKE_main_new();
668  BLI_addtail(mainlist, m);
669 
670  /* Add library data-block itself to 'main' Main, since libraries are **never** linked data.
671  * Fixes bug where you could end with all ID_LI data-blocks having the same name... */
672  lib = BKE_libblock_alloc(mainlist->first, ID_LI, BLI_path_basename(filepath), 0);
673 
674  /* Important, consistency with main ID reading code from read_libblock(). */
675  lib->id.us = ID_FAKE_USERS(lib);
676 
677  /* Matches direct_link_library(). */
678  id_us_ensure_real(&lib->id);
679 
680  BLI_strncpy(lib->filepath, filepath, sizeof(lib->filepath));
681  BLI_strncpy(lib->filepath_abs, name1, sizeof(lib->filepath_abs));
682 
683  m->curlib = lib;
684 
685  read_file_version(fd, m);
686 
687  if (G.debug & G_DEBUG) {
688  CLOG_INFO(&LOG, 3, "Added new lib %s", filepath);
689  }
690  return m;
691 }
692 
693 void blo_readfile_invalidate(FileData *fd, Main *bmain, const char *message)
694 {
695  /* Tag given bmain, and 'root 'local' main one (in case given one is a library one) as invalid.
696  */
697  bmain->is_read_invalid = true;
698  for (; bmain->prev != NULL; bmain = bmain->prev)
699  ;
700  bmain->is_read_invalid = true;
701 
703  RPT_ERROR,
704  "A critical error happened (the blend file is likely corrupted): %s",
705  message);
706 }
707 
710 /* -------------------------------------------------------------------- */
714 typedef struct BlendDataReader {
717 
718 typedef struct BlendLibReader {
722 
723 typedef struct BlendExpander {
727 
728 static void switch_endian_bh4(BHead4 *bhead)
729 {
730  /* the ID_.. codes */
731  if ((bhead->code & 0xFFFF) == 0) {
732  bhead->code >>= 16;
733  }
734 
735  if (bhead->code != ENDB) {
736  BLI_endian_switch_int32(&bhead->len);
738  BLI_endian_switch_int32(&bhead->nr);
739  }
740 }
741 
742 static void switch_endian_bh8(BHead8 *bhead)
743 {
744  /* the ID_.. codes */
745  if ((bhead->code & 0xFFFF) == 0) {
746  bhead->code >>= 16;
747  }
748 
749  if (bhead->code != ENDB) {
750  BLI_endian_switch_int32(&bhead->len);
752  BLI_endian_switch_int32(&bhead->nr);
753  }
754 }
755 
756 static void bh4_from_bh8(BHead *bhead, BHead8 *bhead8, bool do_endian_swap)
757 {
758  BHead4 *bhead4 = (BHead4 *)bhead;
759  int64_t old;
760 
761  bhead4->code = bhead8->code;
762  bhead4->len = bhead8->len;
763 
764  if (bhead4->code != ENDB) {
765  /* perform a endian swap on 64bit pointers, otherwise the pointer might map to zero
766  * 0x0000000000000000000012345678 would become 0x12345678000000000000000000000000
767  */
768  if (do_endian_swap) {
769  BLI_endian_switch_uint64(&bhead8->old);
770  }
771 
772  /* this patch is to avoid `intptr_t` being read from not-eight aligned positions
773  * is necessary on any modern 64bit architecture) */
774  memcpy(&old, &bhead8->old, 8);
775  bhead4->old = (int)(old >> 3);
776 
777  bhead4->SDNAnr = bhead8->SDNAnr;
778  bhead4->nr = bhead8->nr;
779  }
780 }
781 
782 static void bh8_from_bh4(BHead *bhead, BHead4 *bhead4)
783 {
784  BHead8 *bhead8 = (BHead8 *)bhead;
785 
786  bhead8->code = bhead4->code;
787  bhead8->len = bhead4->len;
788 
789  if (bhead8->code != ENDB) {
790  bhead8->old = bhead4->old;
791  bhead8->SDNAnr = bhead4->SDNAnr;
792  bhead8->nr = bhead4->nr;
793  }
794 }
795 
797 {
798  BHeadN *new_bhead = NULL;
799  ssize_t readsize;
800 
801  if (fd) {
802  if (!fd->is_eof) {
803  /* initializing to zero isn't strictly needed but shuts valgrind up
804  * since uninitialized memory gets compared */
805  BHead8 bhead8 = {0};
806  BHead4 bhead4 = {0};
807  BHead bhead = {0};
808 
809  /* First read the bhead structure.
810  * Depending on the platform the file was written on this can
811  * be a big or little endian BHead4 or BHead8 structure.
812  *
813  * As usual 'ENDB' (the last *partial* bhead of the file)
814  * needs some special handling. We don't want to EOF just yet.
815  */
817  bhead4.code = DATA;
818  readsize = fd->file->read(fd->file, &bhead4, sizeof(bhead4));
819 
820  if (readsize == sizeof(bhead4) || bhead4.code == ENDB) {
821  if (fd->flags & FD_FLAGS_SWITCH_ENDIAN) {
822  switch_endian_bh4(&bhead4);
823  }
824 
825  if (fd->flags & FD_FLAGS_POINTSIZE_DIFFERS) {
826  bh8_from_bh4(&bhead, &bhead4);
827  }
828  else {
829  /* MIN2 is only to quiet '-Warray-bounds' compiler warning. */
830  BLI_assert(sizeof(bhead) == sizeof(bhead4));
831  memcpy(&bhead, &bhead4, MIN2(sizeof(bhead), sizeof(bhead4)));
832  }
833  }
834  else {
835  fd->is_eof = true;
836  bhead.len = 0;
837  }
838  }
839  else {
840  bhead8.code = DATA;
841  readsize = fd->file->read(fd->file, &bhead8, sizeof(bhead8));
842 
843  if (readsize == sizeof(bhead8) || bhead8.code == ENDB) {
844  if (fd->flags & FD_FLAGS_SWITCH_ENDIAN) {
845  switch_endian_bh8(&bhead8);
846  }
847 
848  if (fd->flags & FD_FLAGS_POINTSIZE_DIFFERS) {
849  bh4_from_bh8(&bhead, &bhead8, (fd->flags & FD_FLAGS_SWITCH_ENDIAN) != 0);
850  }
851  else {
852  /* MIN2 is only to quiet '-Warray-bounds' compiler warning. */
853  BLI_assert(sizeof(bhead) == sizeof(bhead8));
854  memcpy(&bhead, &bhead8, MIN2(sizeof(bhead), sizeof(bhead8)));
855  }
856  }
857  else {
858  fd->is_eof = true;
859  bhead.len = 0;
860  }
861  }
862 
863  /* make sure people are not trying to pass bad blend files */
864  if (bhead.len < 0) {
865  fd->is_eof = true;
866  }
867 
868  /* bhead now contains the (converted) bhead structure. Now read
869  * the associated data and put everything in a BHeadN (creative naming !)
870  */
871  if (fd->is_eof) {
872  /* pass */
873  }
874 #ifdef USE_BHEAD_READ_ON_DEMAND
875  else if (fd->file->seek != NULL && BHEAD_USE_READ_ON_DEMAND(&bhead)) {
876  /* Delay reading bhead content. */
877  new_bhead = MEM_mallocN(sizeof(BHeadN), "new_bhead");
878  if (new_bhead) {
879  new_bhead->next = new_bhead->prev = NULL;
880  new_bhead->file_offset = fd->file->offset;
881  new_bhead->has_data = false;
882  new_bhead->is_memchunk_identical = false;
883  new_bhead->bhead = bhead;
884  off64_t seek_new = fd->file->seek(fd->file, bhead.len, SEEK_CUR);
885  if (seek_new == -1) {
886  fd->is_eof = true;
887  MEM_freeN(new_bhead);
888  new_bhead = NULL;
889  }
890  BLI_assert(fd->file->offset == seek_new);
891  }
892  else {
893  fd->is_eof = true;
894  }
895  }
896 #endif
897  else {
898  new_bhead = MEM_mallocN(sizeof(BHeadN) + (size_t)bhead.len, "new_bhead");
899  if (new_bhead) {
900  new_bhead->next = new_bhead->prev = NULL;
901 #ifdef USE_BHEAD_READ_ON_DEMAND
902  new_bhead->file_offset = 0; /* don't seek. */
903  new_bhead->has_data = true;
904 #endif
905  new_bhead->is_memchunk_identical = false;
906  new_bhead->bhead = bhead;
907 
908  readsize = fd->file->read(fd->file, new_bhead + 1, (size_t)bhead.len);
909 
910  if (readsize != bhead.len) {
911  fd->is_eof = true;
912  MEM_freeN(new_bhead);
913  new_bhead = NULL;
914  }
915 
916  if (fd->flags & FD_FLAGS_IS_MEMFILE) {
917  new_bhead->is_memchunk_identical = ((UndoReader *)fd->file)->memchunk_identical;
918  }
919  }
920  else {
921  fd->is_eof = true;
922  }
923  }
924  }
925  }
926 
927  /* We've read a new block. Now add it to the list
928  * of blocks.
929  */
930  if (new_bhead) {
931  BLI_addtail(&fd->bhead_list, new_bhead);
932  }
933 
934  return new_bhead;
935 }
936 
938 {
939  BHeadN *new_bhead;
940  BHead *bhead = NULL;
941 
942  /* Rewind the file
943  * Read in a new block if necessary
944  */
945  new_bhead = fd->bhead_list.first;
946  if (new_bhead == NULL) {
947  new_bhead = get_bhead(fd);
948  }
949 
950  if (new_bhead) {
951  bhead = &new_bhead->bhead;
952  }
953 
954  return bhead;
955 }
956 
958 {
959  BHeadN *bheadn = BHEADN_FROM_BHEAD(thisblock);
960  BHeadN *prev = bheadn->prev;
961 
962  return (prev) ? &prev->bhead : NULL;
963 }
964 
966 {
967  BHeadN *new_bhead = NULL;
968  BHead *bhead = NULL;
969 
970  if (thisblock) {
971  /* bhead is actually a sub part of BHeadN
972  * We calculate the BHeadN pointer from the BHead pointer below */
973  new_bhead = BHEADN_FROM_BHEAD(thisblock);
974 
975  /* get the next BHeadN. If it doesn't exist we read in the next one */
976  new_bhead = new_bhead->next;
977  if (new_bhead == NULL) {
978  new_bhead = get_bhead(fd);
979  }
980  }
981 
982  if (new_bhead) {
983  /* here we do the reverse:
984  * go from the BHeadN pointer to the BHead pointer */
985  bhead = &new_bhead->bhead;
986  }
987 
988  return bhead;
989 }
990 
991 #ifdef USE_BHEAD_READ_ON_DEMAND
992 static bool blo_bhead_read_data(FileData *fd, BHead *thisblock, void *buf)
993 {
994  bool success = true;
995  BHeadN *new_bhead = BHEADN_FROM_BHEAD(thisblock);
996  BLI_assert(new_bhead->has_data == false && new_bhead->file_offset != 0);
997  off64_t offset_backup = fd->file->offset;
998  if (UNLIKELY(fd->file->seek(fd->file, new_bhead->file_offset, SEEK_SET) == -1)) {
999  success = false;
1000  }
1001  else {
1002  if (fd->file->read(fd->file, buf, (size_t)new_bhead->bhead.len) != new_bhead->bhead.len) {
1003  success = false;
1004  }
1005  if (fd->flags & FD_FLAGS_IS_MEMFILE) {
1006  new_bhead->is_memchunk_identical = ((UndoReader *)fd->file)->memchunk_identical;
1007  }
1008  }
1009  if (fd->file->seek(fd->file, offset_backup, SEEK_SET) == -1) {
1010  success = false;
1011  }
1012  return success;
1013 }
1014 
1015 static BHead *blo_bhead_read_full(FileData *fd, BHead *thisblock)
1016 {
1017  BHeadN *new_bhead = BHEADN_FROM_BHEAD(thisblock);
1018  BHeadN *new_bhead_data = MEM_mallocN(sizeof(BHeadN) + new_bhead->bhead.len, "new_bhead");
1019  new_bhead_data->bhead = new_bhead->bhead;
1020  new_bhead_data->file_offset = new_bhead->file_offset;
1021  new_bhead_data->has_data = true;
1022  new_bhead_data->is_memchunk_identical = false;
1023  if (!blo_bhead_read_data(fd, thisblock, new_bhead_data + 1)) {
1024  MEM_freeN(new_bhead_data);
1025  return NULL;
1026  }
1027  return &new_bhead_data->bhead;
1028 }
1029 #endif /* USE_BHEAD_READ_ON_DEMAND */
1030 
1031 const char *blo_bhead_id_name(const FileData *fd, const BHead *bhead)
1032 {
1033  return (const char *)POINTER_OFFSET(bhead, sizeof(*bhead) + fd->id_name_offset);
1034 }
1035 
1037 {
1039  return (fd->id_asset_data_offset >= 0) ?
1040  *(AssetMetaData **)POINTER_OFFSET(bhead, sizeof(*bhead) + fd->id_asset_data_offset) :
1041  NULL;
1042 }
1043 
1045 {
1046  char header[SIZEOFBLENDERHEADER], num[4];
1047  ssize_t readsize;
1048 
1049  /* read in the header data */
1050  readsize = fd->file->read(fd->file, header, sizeof(header));
1051 
1052  if (readsize == sizeof(header) && STREQLEN(header, "BLENDER", 7) && ELEM(header[7], '_', '-') &&
1053  ELEM(header[8], 'v', 'V') &&
1054  (isdigit(header[9]) && isdigit(header[10]) && isdigit(header[11]))) {
1055  fd->flags |= FD_FLAGS_FILE_OK;
1056 
1057  /* what size are pointers in the file ? */
1058  if (header[7] == '_') {
1060  if (sizeof(void *) != 4) {
1062  }
1063  }
1064  else {
1065  if (sizeof(void *) != 8) {
1067  }
1068  }
1069 
1070  /* is the file saved in a different endian
1071  * than we need ?
1072  */
1073  if (((header[8] == 'v') ? L_ENDIAN : B_ENDIAN) != ENDIAN_ORDER) {
1075  }
1076 
1077  /* get the version number */
1078  memcpy(num, header + 9, 3);
1079  num[3] = 0;
1080  fd->fileversion = atoi(num);
1081  }
1082 }
1083 
1087 static bool read_file_dna(FileData *fd, const char **r_error_message)
1088 {
1089  BHead *bhead;
1090  int subversion = 0;
1091 
1092  for (bhead = blo_bhead_first(fd); bhead; bhead = blo_bhead_next(fd, bhead)) {
1093  if (bhead->code == GLOB) {
1094  /* Before this, the subversion didn't exist in 'FileGlobal' so the subversion
1095  * value isn't accessible for the purpose of DNA versioning in this case. */
1096  if (fd->fileversion <= 242) {
1097  continue;
1098  }
1099  /* We can't use read_global because this needs 'DNA1' to be decoded,
1100  * however the first 4 chars are _always_ the subversion. */
1101  FileGlobal *fg = (void *)&bhead[1];
1102  BLI_STATIC_ASSERT(offsetof(FileGlobal, subvstr) == 0, "Must be first: subvstr")
1103  char num[5];
1104  memcpy(num, fg->subvstr, 4);
1105  num[4] = 0;
1106  subversion = atoi(num);
1107  }
1108  else if (bhead->code == DNA1) {
1109  const bool do_endian_swap = (fd->flags & FD_FLAGS_SWITCH_ENDIAN) != 0;
1110 
1112  &bhead[1], bhead->len, do_endian_swap, true, r_error_message);
1113  if (fd->filesdna) {
1114  blo_do_versions_dna(fd->filesdna, fd->fileversion, subversion);
1117  fd->filesdna, fd->memsdna, fd->compflags);
1118  /* used to retrieve ID names from (bhead+1) */
1119  fd->id_name_offset = DNA_elem_offset(fd->filesdna, "ID", "char", "name[]");
1120  BLI_assert(fd->id_name_offset != -1);
1122  fd->filesdna, "ID", "AssetMetaData", "*asset_data");
1123 
1124  return true;
1125  }
1126 
1127  return false;
1128  }
1129  else if (bhead->code == ENDB) {
1130  break;
1131  }
1132  }
1133 
1134  *r_error_message = "Missing DNA block";
1135  return false;
1136 }
1137 
1139 {
1140  BHead *bhead;
1141  int *blend_thumb = NULL;
1142 
1143  for (bhead = blo_bhead_first(fd); bhead; bhead = blo_bhead_next(fd, bhead)) {
1144  if (bhead->code == TEST) {
1145  const bool do_endian_swap = (fd->flags & FD_FLAGS_SWITCH_ENDIAN) != 0;
1146  int *data = (int *)(bhead + 1);
1147 
1148  if (bhead->len < (sizeof(int[2]))) {
1149  break;
1150  }
1151 
1152  if (do_endian_swap) {
1155  }
1156 
1157  const int width = data[0];
1158  const int height = data[1];
1160  break;
1161  }
1162  if (bhead->len < BLEN_THUMB_MEMSIZE_FILE(width, height)) {
1163  break;
1164  }
1165 
1166  blend_thumb = data;
1167  break;
1168  }
1169  if (bhead->code != REND) {
1170  /* Thumbnail is stored in TEST immediately after first REND... */
1171  break;
1172  }
1173  }
1174 
1175  return blend_thumb;
1176 }
1177 
1180 /* -------------------------------------------------------------------- */
1185 {
1186  BLI_assert(reports != NULL);
1187 
1188  FileData *fd = MEM_callocN(sizeof(FileData), "FileData");
1189 
1190  fd->memsdna = DNA_sdna_current_get();
1191 
1192  fd->datamap = oldnewmap_new();
1193  fd->globmap = oldnewmap_new();
1194  fd->libmap = oldnewmap_new();
1195 
1196  fd->reports = reports;
1197 
1198  return fd;
1199 }
1200 
1204 {
1205  BLI_assert(fd->filesdna != NULL);
1206  for (BHead *bhead = blo_bhead_first(fd); bhead; bhead = blo_bhead_next(fd, bhead)) {
1207  if (bhead->code != GLOB) {
1208  continue;
1209  }
1210 
1211  FileGlobal *fg = read_struct(fd, bhead, "Global");
1213 
1214  if ((fg->minversion > BLENDER_FILE_VERSION) ||
1216  char writer_ver_str[16];
1217  char min_reader_ver_str[16];
1218  if (fd->fileversion == fg->minversion) {
1220  writer_ver_str, sizeof(writer_ver_str), (short)(fd->fileversion), fg->subversion);
1222  min_reader_ver_str, sizeof(min_reader_ver_str), fg->minversion, fg->minsubversion);
1223  }
1224  else {
1226  writer_ver_str, sizeof(writer_ver_str), (short)(fd->fileversion), -1);
1228  min_reader_ver_str, sizeof(min_reader_ver_str), fg->minversion, -1);
1229  }
1230  BKE_reportf(reports,
1231  RPT_ERROR,
1232  TIP_("The file was saved by a newer version, open it with Blender %s or later"),
1233  min_reader_ver_str);
1234  CLOG_WARN(&LOG,
1235  "%s: File saved by a newer version of Blender (%s), Blender %s or later is "
1236  "needed to open it.",
1237  fd->relabase,
1238  writer_ver_str,
1239  min_reader_ver_str);
1240  MEM_freeN(fg);
1241  return true;
1242  }
1243  MEM_freeN(fg);
1244  return false;
1245  }
1246  return false;
1247 }
1248 
1250 {
1252 
1253  if (fd->flags & FD_FLAGS_FILE_OK) {
1254  const char *error_message = NULL;
1255  if (read_file_dna(fd, &error_message) == false) {
1256  BKE_reportf(
1257  reports, RPT_ERROR, "Failed to read blend file '%s': %s", fd->relabase, error_message);
1258  blo_filedata_free(fd);
1259  fd = NULL;
1260  }
1261  else if (is_minversion_older_than_blender(fd, reports)) {
1262  blo_filedata_free(fd);
1263  fd = NULL;
1264  }
1265  }
1266  else {
1267  BKE_reportf(
1268  reports, RPT_ERROR, "Failed to read blend file '%s', not a blend file", fd->relabase);
1269  blo_filedata_free(fd);
1270  fd = NULL;
1271  }
1272 
1273  return fd;
1274 }
1275 
1276 static FileData *blo_filedata_from_file_descriptor(const char *filepath,
1277  BlendFileReadReport *reports,
1278  int filedes)
1279 {
1280  char header[7];
1281  FileReader *rawfile = BLI_filereader_new_file(filedes);
1282  FileReader *file = NULL;
1283 
1284  errno = 0;
1285  /* If opening the file failed or we can't read the header, give up. */
1286  if (rawfile == NULL || rawfile->read(rawfile, header, sizeof(header)) != sizeof(header)) {
1287  BKE_reportf(reports->reports,
1288  RPT_WARNING,
1289  "Unable to read '%s': %s",
1290  filepath,
1291  errno ? strerror(errno) : TIP_("insufficient content"));
1292  if (rawfile) {
1293  rawfile->close(rawfile);
1294  }
1295  else {
1296  close(filedes);
1297  }
1298  return NULL;
1299  }
1300 
1301  /* Rewind the file after reading the header. */
1302  rawfile->seek(rawfile, 0, SEEK_SET);
1303 
1304  /* Check if we have a regular file. */
1305  if (memcmp(header, "BLENDER", sizeof(header)) == 0) {
1306  /* Try opening the file with memory-mapped IO. */
1307  file = BLI_filereader_new_mmap(filedes);
1308  if (file == NULL) {
1309  /* mmap failed, so just keep using rawfile. */
1310  file = rawfile;
1311  rawfile = NULL;
1312  }
1313  }
1314  else if (BLI_file_magic_is_gzip(header)) {
1315  file = BLI_filereader_new_gzip(rawfile);
1316  if (file != NULL) {
1317  rawfile = NULL; /* The `Gzip` #FileReader takes ownership of `rawfile`. */
1318  }
1319  }
1320  else if (BLI_file_magic_is_zstd(header)) {
1321  file = BLI_filereader_new_zstd(rawfile);
1322  if (file != NULL) {
1323  rawfile = NULL; /* The `Zstd` #FileReader takes ownership of `rawfile`. */
1324  }
1325  }
1326 
1327  /* Clean up `rawfile` if it wasn't taken over. */
1328  if (rawfile != NULL) {
1329  rawfile->close(rawfile);
1330  }
1331  if (file == NULL) {
1332  BKE_reportf(reports->reports, RPT_WARNING, "Unrecognized file format '%s'", filepath);
1333  return NULL;
1334  }
1335 
1336  FileData *fd = filedata_new(reports);
1337  fd->file = file;
1338 
1339  return fd;
1340 }
1341 
1342 static FileData *blo_filedata_from_file_open(const char *filepath, BlendFileReadReport *reports)
1343 {
1344  errno = 0;
1345  const int file = BLI_open(filepath, O_BINARY | O_RDONLY, 0);
1346  if (file == -1) {
1347  BKE_reportf(reports->reports,
1348  RPT_WARNING,
1349  "Unable to open '%s': %s",
1350  filepath,
1351  errno ? strerror(errno) : TIP_("unknown error reading file"));
1352  return NULL;
1353  }
1354  return blo_filedata_from_file_descriptor(filepath, reports, file);
1355 }
1356 
1357 FileData *blo_filedata_from_file(const char *filepath, BlendFileReadReport *reports)
1358 {
1359  FileData *fd = blo_filedata_from_file_open(filepath, reports);
1360  if (fd != NULL) {
1361  /* needed for library_append and read_libraries */
1362  BLI_strncpy(fd->relabase, filepath, sizeof(fd->relabase));
1363 
1364  return blo_decode_and_check(fd, reports->reports);
1365  }
1366  return NULL;
1367 }
1368 
1373 static FileData *blo_filedata_from_file_minimal(const char *filepath)
1374 {
1375  FileData *fd = blo_filedata_from_file_open(filepath, &(BlendFileReadReport){.reports = NULL});
1376  if (fd != NULL) {
1378  if (fd->flags & FD_FLAGS_FILE_OK) {
1379  return fd;
1380  }
1381  blo_filedata_free(fd);
1382  }
1383  return NULL;
1384 }
1385 
1386 FileData *blo_filedata_from_memory(const void *mem, int memsize, BlendFileReadReport *reports)
1387 {
1388  if (!mem || memsize < SIZEOFBLENDERHEADER) {
1389  BKE_report(
1390  reports->reports, RPT_WARNING, (mem) ? TIP_("Unable to read") : TIP_("Unable to open"));
1391  return NULL;
1392  }
1393 
1394  FileReader *mem_file = BLI_filereader_new_memory(mem, memsize);
1395  FileReader *file = mem_file;
1396 
1397  if (BLI_file_magic_is_gzip(mem)) {
1398  file = BLI_filereader_new_gzip(mem_file);
1399  }
1400  else if (BLI_file_magic_is_zstd(mem)) {
1401  file = BLI_filereader_new_zstd(mem_file);
1402  }
1403 
1404  if (file == NULL) {
1405  /* Compression initialization failed. */
1406  mem_file->close(mem_file);
1407  return NULL;
1408  }
1409 
1410  FileData *fd = filedata_new(reports);
1411  fd->file = file;
1412 
1413  return blo_decode_and_check(fd, reports->reports);
1414 }
1415 
1417  const struct BlendFileReadParams *params,
1418  BlendFileReadReport *reports)
1419 {
1420  if (!memfile) {
1421  BKE_report(reports->reports, RPT_WARNING, "Unable to open blend <memory>");
1422  return NULL;
1423  }
1424 
1425  FileData *fd = filedata_new(reports);
1426  fd->file = BLO_memfile_new_filereader(memfile, params->undo_direction);
1427  fd->undo_direction = params->undo_direction;
1428  fd->flags |= FD_FLAGS_IS_MEMFILE;
1429 
1430  return blo_decode_and_check(fd, reports->reports);
1431 }
1432 
1434 {
1435  if (fd) {
1436 
1437  /* Free all BHeadN data blocks */
1438 #ifndef NDEBUG
1439  BLI_freelistN(&fd->bhead_list);
1440 #else
1441  /* Sanity check we're not keeping memory we don't need. */
1442  LISTBASE_FOREACH_MUTABLE (BHeadN *, new_bhead, &fd->bhead_list) {
1443  if (fd->file->seek != NULL && BHEAD_USE_READ_ON_DEMAND(&new_bhead->bhead)) {
1444  BLI_assert(new_bhead->has_data == 0);
1445  }
1446  MEM_freeN(new_bhead);
1447  }
1448 #endif
1449  fd->file->close(fd->file);
1450 
1451  if (fd->filesdna) {
1452  DNA_sdna_free(fd->filesdna);
1453  }
1454  if (fd->compflags) {
1455  MEM_freeN((void *)fd->compflags);
1456  }
1457  if (fd->reconstruct_info) {
1459  }
1460 
1461  if (fd->datamap) {
1462  oldnewmap_free(fd->datamap);
1463  }
1464  if (fd->globmap) {
1465  oldnewmap_free(fd->globmap);
1466  }
1467  if (fd->packedmap) {
1469  }
1470  if (fd->libmap && !(fd->flags & FD_FLAGS_NOT_MY_LIBMAP)) {
1471  oldnewmap_free(fd->libmap);
1472  }
1473  if (fd->old_idmap != NULL) {
1475  }
1477  if (fd->bheadmap) {
1478  MEM_freeN(fd->bheadmap);
1479  }
1480 
1481 #ifdef USE_GHASH_BHEAD
1482  if (fd->bhead_idname_hash) {
1484  }
1485 #endif
1486 
1487  MEM_freeN(fd);
1488  }
1489 }
1490 
1493 /* -------------------------------------------------------------------- */
1497 bool BLO_has_bfile_extension(const char *str)
1498 {
1499  const char *ext_test[4] = {".blend", ".ble", ".blend.gz", NULL};
1500  return BLI_path_extension_check_array(str, ext_test);
1501 }
1502 
1503 bool BLO_library_path_explode(const char *path, char *r_dir, char **r_group, char **r_name)
1504 {
1505  /* We might get some data names with slashes,
1506  * so we have to go up in path until we find blend file itself,
1507  * then we know next path item is group, and everything else is data name. */
1508  char *slash = NULL, *prev_slash = NULL, c = '\0';
1509 
1510  r_dir[0] = '\0';
1511  if (r_group) {
1512  *r_group = NULL;
1513  }
1514  if (r_name) {
1515  *r_name = NULL;
1516  }
1517 
1518  /* if path leads to an existing directory, we can be sure we're not (in) a library */
1519  if (BLI_is_dir(path)) {
1520  return false;
1521  }
1522 
1523  strcpy(r_dir, path);
1524 
1525  while ((slash = (char *)BLI_path_slash_rfind(r_dir))) {
1526  char tc = *slash;
1527  *slash = '\0';
1528  if (BLO_has_bfile_extension(r_dir) && BLI_is_file(r_dir)) {
1529  break;
1530  }
1531  if (STREQ(r_dir, BLO_EMBEDDED_STARTUP_BLEND)) {
1532  break;
1533  }
1534 
1535  if (prev_slash) {
1536  *prev_slash = c;
1537  }
1538  prev_slash = slash;
1539  c = tc;
1540  }
1541 
1542  if (!slash) {
1543  return false;
1544  }
1545 
1546  if (slash[1] != '\0') {
1547  BLI_assert(strlen(slash + 1) < BLO_GROUP_MAX);
1548  if (r_group) {
1549  *r_group = slash + 1;
1550  }
1551  }
1552 
1553  if (prev_slash && (prev_slash[1] != '\0')) {
1554  BLI_assert(strlen(prev_slash + 1) < MAX_ID_NAME - 2);
1555  if (r_name) {
1556  *r_name = prev_slash + 1;
1557  }
1558  }
1559 
1560  return true;
1561 }
1562 
1564 {
1565  FileData *fd;
1567  int *fd_data;
1568 
1569  fd = blo_filedata_from_file_minimal(filepath);
1570  fd_data = fd ? read_file_thumbnail(fd) : NULL;
1571 
1572  if (fd_data) {
1573  const int width = fd_data[0];
1574  const int height = fd_data[1];
1576  const size_t data_size = BLEN_THUMB_MEMSIZE(width, height);
1577  data = MEM_mallocN(data_size, __func__);
1578  if (data) {
1579  BLI_assert((data_size - sizeof(*data)) ==
1580  (BLEN_THUMB_MEMSIZE_FILE(width, height) - (sizeof(*fd_data) * 2)));
1581  data->width = width;
1582  data->height = height;
1583  memcpy(data->rect, &fd_data[2], data_size - sizeof(*data));
1584  }
1585  }
1586  }
1587 
1588  blo_filedata_free(fd);
1589 
1590  return data;
1591 }
1592 
1595 /* -------------------------------------------------------------------- */
1599 /* Only direct data-blocks. */
1600 static void *newdataadr(FileData *fd, const void *adr)
1601 {
1602  return oldnewmap_lookup_and_inc(fd->datamap, adr, true);
1603 }
1604 
1605 /* Only direct data-blocks. */
1606 static void *newdataadr_no_us(FileData *fd, const void *adr)
1607 {
1608  return oldnewmap_lookup_and_inc(fd->datamap, adr, false);
1609 }
1610 
1612 {
1613  return oldnewmap_lookup_and_inc(fd->globmap, adr, true);
1614 }
1615 
1616 /* Used to restore packed data after undo. */
1617 static void *newpackedadr(FileData *fd, const void *adr)
1618 {
1619  if (fd->packedmap && adr) {
1620  return oldnewmap_lookup_and_inc(fd->packedmap, adr, true);
1621  }
1622 
1623  return oldnewmap_lookup_and_inc(fd->datamap, adr, true);
1624 }
1625 
1626 /* only lib data */
1627 static void *newlibadr(FileData *fd, const void *lib, const void *adr)
1628 {
1629  return oldnewmap_liblookup(fd->libmap, adr, lib);
1630 }
1631 
1632 void *blo_do_versions_newlibadr(FileData *fd, const void *lib, const void *adr)
1633 {
1634  return newlibadr(fd, lib, adr);
1635 }
1636 
1637 /* increases user number */
1638 static void change_link_placeholder_to_real_ID_pointer_fd(FileData *fd, const void *old, void *new)
1639 {
1640  for (int i = 0; i < fd->libmap->nentries; i++) {
1641  OldNew *entry = &fd->libmap->entries[i];
1642 
1643  if (old == entry->newp && entry->nr == ID_LINK_PLACEHOLDER) {
1644  entry->newp = new;
1645  if (new) {
1646  entry->nr = GS(((ID *)new)->name);
1647  }
1648  }
1649  }
1650 }
1651 
1653  FileData *basefd,
1654  void *old,
1655  void *new)
1656 {
1657  LISTBASE_FOREACH (Main *, mainptr, mainlist) {
1658  FileData *fd;
1659 
1660  if (mainptr->curlib) {
1661  fd = mainptr->curlib->filedata;
1662  }
1663  else {
1664  fd = basefd;
1665  }
1666 
1667  if (fd) {
1669  }
1670  }
1671 }
1672 
1673 /* XXX disabled this feature - packed files also belong in temp saves and quit.blend,
1674  * to make restore work. */
1675 
1677 {
1678  oldnewmap_insert(fd->packedmap, pf, pf, 0);
1679  oldnewmap_insert(fd->packedmap, pf->data, pf->data, 0);
1680 }
1681 
1683 {
1684  fd->packedmap = oldnewmap_new();
1685 
1686  LISTBASE_FOREACH (Image *, ima, &oldmain->images) {
1687  if (ima->packedfile) {
1688  insert_packedmap(fd, ima->packedfile);
1689  }
1690 
1691  LISTBASE_FOREACH (ImagePackedFile *, imapf, &ima->packedfiles) {
1692  if (imapf->packedfile) {
1693  insert_packedmap(fd, imapf->packedfile);
1694  }
1695  }
1696  }
1697 
1698  LISTBASE_FOREACH (VFont *, vfont, &oldmain->fonts) {
1699  if (vfont->packedfile) {
1700  insert_packedmap(fd, vfont->packedfile);
1701  }
1702  }
1703 
1704  LISTBASE_FOREACH (bSound *, sound, &oldmain->sounds) {
1705  if (sound->packedfile) {
1706  insert_packedmap(fd, sound->packedfile);
1707  }
1708  }
1709 
1710  LISTBASE_FOREACH (Volume *, volume, &oldmain->volumes) {
1711  if (volume->packedfile) {
1712  insert_packedmap(fd, volume->packedfile);
1713  }
1714  }
1715 
1716  LISTBASE_FOREACH (Library *, lib, &oldmain->libraries) {
1717  if (lib->packedfile) {
1718  insert_packedmap(fd, lib->packedfile);
1719  }
1720  }
1721 }
1722 
1724 {
1725  OldNew *entry = fd->packedmap->entries;
1726 
1727  /* used entries were restored, so we put them to zero */
1728  for (int i = 0; i < fd->packedmap->nentries; i++, entry++) {
1729  if (entry->nr > 0) {
1730  entry->newp = NULL;
1731  }
1732  }
1733 
1734  LISTBASE_FOREACH (Image *, ima, &oldmain->images) {
1735  ima->packedfile = newpackedadr(fd, ima->packedfile);
1736 
1737  LISTBASE_FOREACH (ImagePackedFile *, imapf, &ima->packedfiles) {
1738  imapf->packedfile = newpackedadr(fd, imapf->packedfile);
1739  }
1740  }
1741 
1742  LISTBASE_FOREACH (VFont *, vfont, &oldmain->fonts) {
1743  vfont->packedfile = newpackedadr(fd, vfont->packedfile);
1744  }
1745 
1746  LISTBASE_FOREACH (bSound *, sound, &oldmain->sounds) {
1747  sound->packedfile = newpackedadr(fd, sound->packedfile);
1748  }
1749 
1750  LISTBASE_FOREACH (Library *, lib, &oldmain->libraries) {
1751  lib->packedfile = newpackedadr(fd, lib->packedfile);
1752  }
1753 
1754  LISTBASE_FOREACH (Volume *, volume, &oldmain->volumes) {
1755  volume->packedfile = newpackedadr(fd, volume->packedfile);
1756  }
1757 }
1758 
1760 {
1761  ListBase *lbarray[INDEX_ID_MAX];
1762 
1763  LISTBASE_FOREACH (Main *, ptr, old_mainlist) {
1764  int i = set_listbasepointers(ptr, lbarray);
1765  while (i--) {
1766  LISTBASE_FOREACH (ID *, id, lbarray[i]) {
1767  oldnewmap_lib_insert(fd, id, id, GS(id->name));
1768  }
1769  }
1770  }
1771 
1772  fd->old_mainlist = old_mainlist;
1773 }
1774 
1776 {
1777  if (fd->old_idmap != NULL) {
1779  }
1781 }
1782 
1783 typedef struct BLOCacheStorage {
1787 
1788 typedef struct BLOCacheStorageValue {
1789  void *cache_v;
1792 
1795  ID *id, const IDCacheKey *key, void **cache_p, uint UNUSED(flags), void *cache_storage_v)
1796 {
1798  UNUSED_VARS_NDEBUG(id);
1799 
1800  BLOCacheStorage *cache_storage = cache_storage_v;
1801  BLI_assert(!BLI_ghash_haskey(cache_storage->cache_map, key));
1802 
1803  IDCacheKey *storage_key = BLI_memarena_alloc(cache_storage->memarena, sizeof(*storage_key));
1804  *storage_key = *key;
1805  BLOCacheStorageValue *storage_value = BLI_memarena_alloc(cache_storage->memarena,
1806  sizeof(*storage_value));
1807  storage_value->cache_v = *cache_p;
1808  storage_value->new_usage_count = 0;
1809  BLI_ghash_insert(cache_storage->cache_map, storage_key, storage_value);
1810 }
1811 
1814  ID *UNUSED(id), const IDCacheKey *key, void **cache_p, uint flags, void *cache_storage_v)
1815 {
1816  BLOCacheStorage *cache_storage = cache_storage_v;
1817 
1818  if (cache_storage == NULL) {
1819  /* In non-undo case, only clear the pointer if it is a purely runtime one.
1820  * If it may be stored in a persistent way in the .blend file, direct_link code is responsible
1821  * to properly deal with it. */
1822  if ((flags & IDTYPE_CACHE_CB_FLAGS_PERSISTENT) == 0) {
1823  *cache_p = NULL;
1824  }
1825  return;
1826  }
1827 
1828  BLOCacheStorageValue *storage_value = BLI_ghash_lookup(cache_storage->cache_map, key);
1829  if (storage_value == NULL) {
1830  *cache_p = NULL;
1831  return;
1832  }
1833  storage_value->new_usage_count++;
1834  *cache_p = storage_value->cache_v;
1835 }
1836 
1839  const IDCacheKey *key,
1840  void **cache_p,
1841  uint UNUSED(flags),
1842  void *cache_storage_v)
1843 {
1844  BLOCacheStorage *cache_storage = cache_storage_v;
1845 
1846  BLOCacheStorageValue *storage_value = BLI_ghash_lookup(cache_storage->cache_map, key);
1847  if (storage_value == NULL) {
1848  *cache_p = NULL;
1849  return;
1850  }
1851  /* If that cache has been restored into some new ID, we want to remove it from old one, otherwise
1852  * keep it there so that it gets properly freed together with its ID. */
1853  if (storage_value->new_usage_count != 0) {
1854  *cache_p = NULL;
1855  }
1856  else {
1857  BLI_assert(*cache_p == storage_value->cache_v);
1858  }
1859 }
1860 
1862 {
1863  if (fd->flags & FD_FLAGS_IS_MEMFILE) {
1864  BLI_assert(fd->cache_storage == NULL);
1865  fd->cache_storage = MEM_mallocN(sizeof(*fd->cache_storage), __func__);
1869 
1870  ListBase *lb;
1871  FOREACH_MAIN_LISTBASE_BEGIN (bmain, lb) {
1872  ID *id = lb->first;
1873  if (id == NULL) {
1874  continue;
1875  }
1876 
1877  const IDTypeInfo *type_info = BKE_idtype_get_info_from_id(id);
1878  if (type_info->foreach_cache == NULL) {
1879  continue;
1880  }
1881 
1883  if (ID_IS_LINKED(id)) {
1884  continue;
1885  }
1887  }
1889  }
1891  }
1892  else {
1893  fd->cache_storage = NULL;
1894  }
1895 }
1896 
1898 {
1899  if (fd->cache_storage != NULL) {
1900  ListBase *lb;
1901  FOREACH_MAIN_LISTBASE_BEGIN (bmain_old, lb) {
1902  ID *id = lb->first;
1903  if (id == NULL) {
1904  continue;
1905  }
1906 
1907  const IDTypeInfo *type_info = BKE_idtype_get_info_from_id(id);
1908  if (type_info->foreach_cache == NULL) {
1909  continue;
1910  }
1911 
1913  if (ID_IS_LINKED(id)) {
1914  continue;
1915  }
1917  }
1919  }
1921  }
1922 }
1923 
1925 {
1926  if (fd->cache_storage != NULL) {
1929  MEM_freeN(fd->cache_storage);
1930  fd->cache_storage = NULL;
1931  }
1932 }
1933 
1936 /* -------------------------------------------------------------------- */
1940 static void switch_endian_structs(const struct SDNA *filesdna, BHead *bhead)
1941 {
1942  int blocksize, nblocks;
1943  char *data;
1944 
1945  data = (char *)(bhead + 1);
1946  blocksize = filesdna->types_size[filesdna->structs[bhead->SDNAnr]->type];
1947 
1948  nblocks = bhead->nr;
1949  while (nblocks--) {
1950  DNA_struct_switch_endian(filesdna, bhead->SDNAnr, data);
1951 
1952  data += blocksize;
1953  }
1954 }
1955 
1956 static void *read_struct(FileData *fd, BHead *bh, const char *blockname)
1957 {
1958  void *temp = NULL;
1959 
1960  if (bh->len) {
1961 #ifdef USE_BHEAD_READ_ON_DEMAND
1962  BHead *bh_orig = bh;
1963 #endif
1964 
1965  /* switch is based on file dna */
1966  if (bh->SDNAnr && (fd->flags & FD_FLAGS_SWITCH_ENDIAN)) {
1967 #ifdef USE_BHEAD_READ_ON_DEMAND
1968  if (BHEADN_FROM_BHEAD(bh)->has_data == false) {
1969  bh = blo_bhead_read_full(fd, bh);
1970  if (UNLIKELY(bh == NULL)) {
1971  fd->flags &= ~FD_FLAGS_FILE_OK;
1972  return NULL;
1973  }
1974  }
1975 #endif
1977  }
1978 
1979  if (fd->compflags[bh->SDNAnr] != SDNA_CMP_REMOVED) {
1980  if (fd->compflags[bh->SDNAnr] == SDNA_CMP_NOT_EQUAL) {
1981 #ifdef USE_BHEAD_READ_ON_DEMAND
1982  if (BHEADN_FROM_BHEAD(bh)->has_data == false) {
1983  bh = blo_bhead_read_full(fd, bh);
1984  if (UNLIKELY(bh == NULL)) {
1985  fd->flags &= ~FD_FLAGS_FILE_OK;
1986  return NULL;
1987  }
1988  }
1989 #endif
1990  temp = DNA_struct_reconstruct(fd->reconstruct_info, bh->SDNAnr, bh->nr, (bh + 1));
1991  }
1992  else {
1993  /* SDNA_CMP_EQUAL */
1994  temp = MEM_mallocN(bh->len, blockname);
1995 #ifdef USE_BHEAD_READ_ON_DEMAND
1996  if (BHEADN_FROM_BHEAD(bh)->has_data) {
1997  memcpy(temp, (bh + 1), bh->len);
1998  }
1999  else {
2000  /* Instead of allocating the bhead, then copying it,
2001  * read the data from the file directly into the memory. */
2002  if (UNLIKELY(!blo_bhead_read_data(fd, bh, temp))) {
2003  fd->flags &= ~FD_FLAGS_FILE_OK;
2004  MEM_freeN(temp);
2005  temp = NULL;
2006  }
2007  }
2008 #else
2009  memcpy(temp, (bh + 1), bh->len);
2010 #endif
2011  }
2012  }
2013 
2014 #ifdef USE_BHEAD_READ_ON_DEMAND
2015  if (bh_orig != bh) {
2017  }
2018 #endif
2019  }
2020 
2021  return temp;
2022 }
2023 
2024 /* Like read_struct, but gets a pointer without allocating. Only works for
2025  * undo since DNA must match. */
2026 static const void *peek_struct_undo(FileData *fd, BHead *bhead)
2027 {
2029  UNUSED_VARS_NDEBUG(fd);
2030  return (bhead->len) ? (const void *)(bhead + 1) : NULL;
2031 }
2032 
2033 static void link_glob_list(FileData *fd, ListBase *lb) /* for glob data */
2034 {
2035  Link *ln, *prev;
2036  void *poin;
2037 
2038  if (BLI_listbase_is_empty(lb)) {
2039  return;
2040  }
2041  poin = newdataadr(fd, lb->first);
2042  if (lb->first) {
2043  oldnewmap_insert(fd->globmap, lb->first, poin, 0);
2044  }
2045  lb->first = poin;
2046 
2047  ln = lb->first;
2048  prev = NULL;
2049  while (ln) {
2050  poin = newdataadr(fd, ln->next);
2051  if (ln->next) {
2052  oldnewmap_insert(fd->globmap, ln->next, poin, 0);
2053  }
2054  ln->next = poin;
2055  ln->prev = prev;
2056  prev = ln;
2057  ln = ln->next;
2058  }
2059  lb->last = prev;
2060 }
2061 
2064 /* -------------------------------------------------------------------- */
2068 static void lib_link_id(BlendLibReader *reader, ID *id);
2069 
2070 static void lib_link_id_embedded_id(BlendLibReader *reader, ID *id)
2071 {
2072 
2073  /* Handle 'private IDs'. */
2074  bNodeTree *nodetree = ntreeFromID(id);
2075  if (nodetree != NULL) {
2076  lib_link_id(reader, &nodetree->id);
2077  ntreeBlendReadLib(reader, nodetree);
2078  }
2079 
2080  if (GS(id->name) == ID_SCE) {
2081  Scene *scene = (Scene *)id;
2082  if (scene->master_collection != NULL) {
2083  lib_link_id(reader, &scene->master_collection->id);
2085  }
2086  }
2087 }
2088 
2089 static void lib_link_id(BlendLibReader *reader, ID *id)
2090 {
2091  /* NOTE: WM IDProperties are never written to file, hence they should always be NULL here. */
2092  BLI_assert((GS(id->name) != ID_WM) || id->properties == NULL);
2093  IDP_BlendReadLib(reader, id->lib, id->properties);
2094 
2095  AnimData *adt = BKE_animdata_from_id(id);
2096  if (adt != NULL) {
2097  BKE_animdata_blend_read_lib(reader, id, adt);
2098  }
2099 
2100  if (id->override_library) {
2104  }
2105 
2106  lib_link_id_embedded_id(reader, id);
2107 }
2108 
2110 {
2112 
2114  BLO_read_data_address(reader, &opop->subitem_local_name);
2115 
2116  opop->tag = 0; /* Runtime only. */
2117 }
2118 
2120 {
2122 
2123  BLO_read_data_address(reader, &op->rna_path);
2124 
2125  op->tag = 0; /* Runtime only. */
2126 
2128 }
2129 
2130 static void direct_link_id_common(
2131  BlendDataReader *reader, Library *current_library, ID *id, ID *id_old, const int tag);
2132 
2134  Library *current_library,
2135  ID *id,
2136  ID *id_old)
2137 {
2138  /* Handle 'private IDs'. */
2139  bNodeTree **nodetree = BKE_ntree_ptr_from_id(id);
2140  if (nodetree != NULL && *nodetree != NULL) {
2141  BLO_read_data_address(reader, nodetree);
2142  direct_link_id_common(reader,
2143  current_library,
2144  (ID *)*nodetree,
2145  id_old != NULL ? (ID *)ntreeFromID(id_old) : NULL,
2146  0);
2147  ntreeBlendReadData(reader, *nodetree);
2148  }
2149 
2150  if (GS(id->name) == ID_SCE) {
2151  Scene *scene = (Scene *)id;
2152  if (scene->master_collection != NULL) {
2154  direct_link_id_common(reader,
2155  current_library,
2157  id_old != NULL ? &((Scene *)id_old)->master_collection->id : NULL,
2158  0);
2160  }
2161  }
2162 }
2163 
2164 static int direct_link_id_restore_recalc_exceptions(const ID *id_current)
2165 {
2166  /* Exception for armature objects, where the pose has direct points to the
2167  * armature data-block. */
2168  if (GS(id_current->name) == ID_OB && ((Object *)id_current)->pose) {
2169  return ID_RECALC_GEOMETRY;
2170  }
2171 
2172  return 0;
2173 }
2174 
2176  const ID *id_target,
2177  const ID *id_current,
2178  const bool is_identical)
2179 {
2180  /* These are the evaluations that had not been performed yet at the time the
2181  * target undo state was written. These need to be done again, since they may
2182  * flush back changes to the original datablock. */
2183  int recalc = id_target->recalc;
2184 
2185  if (id_current == NULL) {
2186  /* ID does not currently exist in the database, so also will not exist in
2187  * the dependency graphs. That means it will be newly created and as a
2188  * result also fully re-evaluated regardless of the recalc flag set here. */
2189  recalc |= ID_RECALC_ALL;
2190  }
2191  else {
2192  /* If the contents datablock changed, the depsgraph needs to copy the
2193  * datablock again to ensure it matches the original datablock. */
2194  if (!is_identical) {
2195  recalc |= ID_RECALC_COPY_ON_WRITE;
2196  }
2197 
2198  /* Special exceptions. */
2199  recalc |= direct_link_id_restore_recalc_exceptions(id_current);
2200 
2201  /* Evaluations for the current state that have not been performed yet
2202  * by the time we are performing this undo step. */
2203  recalc |= id_current->recalc;
2204 
2205  /* Tags that were set between the target state and the current state,
2206  * that we need to perform again. */
2207  if (fd->undo_direction == STEP_UNDO) {
2208  /* Undo: tags from target to the current state. */
2209  recalc |= id_current->recalc_up_to_undo_push;
2210  }
2211  else {
2213  /* Redo: tags from current to the target state. */
2214  recalc |= id_target->recalc_up_to_undo_push;
2215  }
2216  }
2217 
2218  return recalc;
2219 }
2220 
2222  BlendDataReader *reader, Library *current_library, ID *id, ID *id_old, const int tag)
2223 {
2224  if (!BLO_read_data_is_undo(reader)) {
2225  /* When actually reading a file, we do want to reset/re-generate session uuids.
2226  * In undo case, we want to re-use existing ones. */
2227  id->session_uuid = MAIN_ID_SESSION_UUID_UNSET;
2228  }
2229 
2230  if ((tag & LIB_TAG_TEMP_MAIN) == 0) {
2232  }
2233 
2234  id->lib = current_library;
2235  id->us = ID_FAKE_USERS(id);
2236  id->icon_id = 0;
2237  id->newid = NULL; /* Needed because .blend may have been saved with crap value here... */
2238  id->orig_id = NULL;
2239  id->py_instance = NULL;
2240 
2241  /* Initialize with provided tag. */
2242  id->tag = tag;
2243 
2244  if (ID_IS_LINKED(id)) {
2245  id->library_weak_reference = NULL;
2246  }
2247  else {
2249  }
2250 
2251  if (tag & LIB_TAG_ID_LINK_PLACEHOLDER) {
2252  /* For placeholder we only need to set the tag and properly initialize generic ID fields above,
2253  * no further data to read. */
2254  return;
2255  }
2256 
2257  if (id->asset_data) {
2258  BLO_read_data_address(reader, &id->asset_data);
2260  /* Restore runtime asset type info. */
2261  const IDTypeInfo *id_type = BKE_idtype_get_info_from_id(id);
2262  id->asset_data->local_type_info = id_type->asset_type_info;
2263  }
2264 
2265  /* Link direct data of ID properties. */
2266  if (id->properties) {
2267  BLO_read_data_address(reader, &id->properties);
2268  /* this case means the data was written incorrectly, it should not happen */
2269  IDP_BlendDataRead(reader, &id->properties);
2270  }
2271 
2272  id->flag &= ~LIB_INDIRECT_WEAK_LINK;
2273 
2274  /* NOTE: It is important to not clear the recalc flags for undo/redo.
2275  * Preserving recalc flags on redo/undo is the only way to make dependency graph detect
2276  * that animation is to be evaluated on undo/redo. If this is not enforced by the recalc
2277  * flags dependency graph does not do animation update to avoid loss of unkeyed changes.,
2278  * which conflicts with undo/redo of changes to animation data itself.
2279  *
2280  * But for regular file load we clear the flag, since the flags might have been changed since
2281  * the version the file has been saved with. */
2282  if (!BLO_read_data_is_undo(reader)) {
2283  id->recalc = 0;
2284  id->recalc_after_undo_push = 0;
2285  }
2286  else if ((reader->fd->skip_flags & BLO_READ_SKIP_UNDO_OLD_MAIN) == 0) {
2287  id->recalc = direct_link_id_restore_recalc(reader->fd, id, id_old, false);
2288  id->recalc_after_undo_push = 0;
2289  }
2290 
2291  /* Link direct data of overrides. */
2292  if (id->override_library) {
2294  /* Work around file corruption on writing, see T86853. */
2295  if (id->override_library != NULL) {
2298  id->override_library->runtime = NULL;
2299  }
2300  }
2301 
2302  DrawDataList *drawdata = DRW_drawdatalist_from_id(id);
2303  if (drawdata) {
2304  BLI_listbase_clear((ListBase *)drawdata);
2305  }
2306 
2307  /* Handle 'private IDs'. */
2308  direct_link_id_embedded_id(reader, current_library, id, id_old);
2309 }
2310 
2313 /* -------------------------------------------------------------------- */
2319 /* -------------------------------------------------------------------- */
2324 {
2325  key->uidgen = 1;
2326  LISTBASE_FOREACH (KeyBlock *, block, &key->block) {
2327  block->uid = key->uidgen++;
2328  }
2329 }
2330 
2333 /* -------------------------------------------------------------------- */
2337 #ifdef USE_SETSCENE_CHECK
2341 static bool scene_validate_setscene__liblink(Scene *sce, const int totscene)
2342 {
2343  Scene *sce_iter;
2344  int a;
2345 
2346  if (sce->set == NULL) {
2347  return true;
2348  }
2349 
2350  for (a = 0, sce_iter = sce; sce_iter->set; sce_iter = sce_iter->set, a++) {
2351  /* This runs per library (before each libraries #Main has been joined),
2352  * so we can't step into other libraries since `totscene` is only for this library.
2353  *
2354  * Also, other libraries may not have been linked yet,
2355  * while we could check #LIB_TAG_NEED_LINK the library pointer check is sufficient. */
2356  if (sce->id.lib != sce_iter->id.lib) {
2357  return true;
2358  }
2360  return true;
2361  }
2362 
2363  if (a > totscene) {
2364  sce->set = NULL;
2365  return false;
2366  }
2367  }
2368 
2369  return true;
2370 }
2371 #endif
2372 
2373 static void lib_link_scenes_check_set(Main *bmain)
2374 {
2375 #ifdef USE_SETSCENE_CHECK
2376  const int totscene = BLI_listbase_count(&bmain->scenes);
2377  LISTBASE_FOREACH (Scene *, sce, &bmain->scenes) {
2380  if (!scene_validate_setscene__liblink(sce, totscene)) {
2381  CLOG_WARN(&LOG, "Found cyclic background scene when linking %s", sce->id.name + 2);
2382  }
2383  }
2384  }
2385 #else
2386  UNUSED_VARS(bmain, totscene);
2387 #endif
2388 }
2389 
2390 #undef USE_SETSCENE_CHECK
2391 
2394 /* -------------------------------------------------------------------- */
2398 /* how to handle user count on pointer restore */
2399 typedef enum ePointerUserMode {
2400  USER_IGNORE = 0, /* ignore user count */
2401  USER_REAL = 1, /* ensure at least one real user (fake user ignored) */
2403 
2404 static void restore_pointer_user(ID *id, ID *newid, ePointerUserMode user)
2405 {
2406  BLI_assert(STREQ(newid->name + 2, id->name + 2));
2407  BLI_assert(newid->lib == id->lib);
2408  UNUSED_VARS_NDEBUG(id);
2409 
2410  if (user == USER_REAL) {
2411  id_us_ensure_real(newid);
2412  }
2413 }
2414 
2415 #ifndef USE_GHASH_RESTORE_POINTER
2421 static void *restore_pointer_by_name_main(Main *mainp, ID *id, ePointerUserMode user)
2422 {
2423  if (id) {
2424  ListBase *lb = which_libbase(mainp, GS(id->name));
2425  if (lb) { /* there's still risk of checking corrupt mem (freed Ids in oops) */
2426  ID *idn = lb->first;
2427  for (; idn; idn = idn->next) {
2428  if (STREQ(idn->name + 2, id->name + 2)) {
2429  if (idn->lib == id->lib) {
2430  restore_pointer_user(id, idn, user);
2431  break;
2432  }
2433  }
2434  }
2435  return idn;
2436  }
2437  }
2438  return NULL;
2439 }
2440 #endif
2441 
2453 {
2454 #ifdef USE_GHASH_RESTORE_POINTER
2455  if (id) {
2456  /* use fast lookup when available */
2457  ID *idn = BKE_main_idmap_lookup_id(id_map, id);
2458  if (idn) {
2459  restore_pointer_user(id, idn, user);
2460  }
2461  return idn;
2462  }
2463  return NULL;
2464 #else
2466  return restore_pointer_by_name_main(mainp, id, user);
2467 #endif
2468 }
2469 
2471 {
2472  if (id) {
2473  /* clipboard must ensure this */
2474  BLI_assert(id->newid != NULL);
2476  }
2477 }
2478 static bool lib_link_seq_clipboard_cb(Sequence *seq, void *arg_pt)
2479 {
2480  struct IDNameLib_Map *id_map = arg_pt;
2481 
2487  return true;
2488 }
2489 
2491 {
2492  /* update IDs stored in sequencer clipboard */
2494 }
2495 
2497 {
2498  const int cb_flag = cb_data->cb_flag;
2499  ID **id_pointer = cb_data->id_pointer;
2500  if (cb_flag & IDWALK_CB_EMBEDDED || *id_pointer == NULL) {
2501  return IDWALK_RET_NOP;
2502  }
2503 
2504  /* Special ugly case here, thanks again for those non-IDs IDs... */
2505  /* We probably need to add more cases here (hint: nodetrees),
2506  * but will wait for changes from D5559 to get in first. */
2507  if (GS((*id_pointer)->name) == ID_GR) {
2508  Collection *collection = (Collection *)*id_pointer;
2509  if (collection->flag & COLLECTION_IS_MASTER) {
2510  /* We should never reach that point anymore, since master collection private ID should be
2511  * properly tagged with IDWALK_CB_EMBEDDED. */
2513  return IDWALK_RET_NOP;
2514  }
2515  }
2516 
2517  struct IDNameLib_Map *id_map = cb_data->user_data;
2518 
2519  /* NOTE: Handling of usercount here is really bad, defining its own system...
2520  * Will have to be refactored at some point, but that is not top priority task for now.
2521  * And all user-counts are properly recomputed at the end of the undo management code anyway. */
2522  *id_pointer = restore_pointer_by_name(
2523  id_map, *id_pointer, (cb_flag & IDWALK_CB_USER_ONE) ? USER_REAL : USER_IGNORE);
2524 
2525  return IDWALK_RET_NOP;
2526 }
2527 
2528 static void lib_link_main_data_restore(struct IDNameLib_Map *id_map, Main *newmain)
2529 {
2530  ID *id;
2531  FOREACH_MAIN_ID_BEGIN (newmain, id) {
2533  }
2535 }
2536 
2538 {
2541 }
2542 
2544 {
2546 
2547  LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
2548  LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
2549  if (sl->spacetype == SPACE_VIEW3D) {
2550  View3D *v3d = (View3D *)sl;
2551 
2552  if (v3d->camera == NULL || v3d->scenelock) {
2553  v3d->camera = scene->camera;
2554  }
2555 
2556  if (v3d->localvd) {
2557  Base *base = NULL;
2558 
2559  v3d->localvd->camera = scene->camera;
2560 
2561  /* Local-view can become invalid during undo/redo steps,
2562  * so we exit it when no could be found. */
2563  for (base = view_layer->object_bases.first; base; base = base->next) {
2564  if (base->local_view_bits & v3d->local_view_uuid) {
2565  break;
2566  }
2567  }
2568  if (base == NULL) {
2569  MEM_freeN(v3d->localvd);
2570  v3d->localvd = NULL;
2571  v3d->local_view_uuid = 0;
2572 
2573  /* Region-base storage is different depending if the space is active. */
2574  ListBase *regionbase = (sl == area->spacedata.first) ? &area->regionbase :
2575  &sl->regionbase;
2576  LISTBASE_FOREACH (ARegion *, region, regionbase) {
2577  if (region->regiontype == RGN_TYPE_WINDOW) {
2578  RegionView3D *rv3d = region->regiondata;
2579  if (rv3d->localvd) {
2580  MEM_freeN(rv3d->localvd);
2581  rv3d->localvd = NULL;
2582  }
2583  }
2584  }
2585  }
2586  }
2587  }
2588  }
2589  }
2590 }
2591 
2593  Main *newmain,
2594  WorkSpaceLayout *layout)
2595 {
2596  bScreen *screen = BKE_workspace_layout_screen_get(layout);
2597 
2598  /* avoid conflicts with 2.8x branch */
2599  {
2600  LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
2601  LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
2602  if (sl->spacetype == SPACE_VIEW3D) {
2603  View3D *v3d = (View3D *)sl;
2604 
2607  }
2608  else if (sl->spacetype == SPACE_GRAPH) {
2609  SpaceGraph *sipo = (SpaceGraph *)sl;
2610  bDopeSheet *ads = sipo->ads;
2611 
2612  if (ads) {
2614 
2615  if (ads->filter_grp) {
2617  id_map, (ID *)ads->filter_grp, USER_IGNORE);
2618  }
2619  }
2620 
2621  /* force recalc of list of channels (i.e. includes calculating F-Curve colors)
2622  * thus preventing the "black curves" problem post-undo
2623  */
2625  }
2626  else if (sl->spacetype == SPACE_PROPERTIES) {
2627  SpaceProperties *sbuts = (SpaceProperties *)sl;
2629  if (sbuts->pinid == NULL) {
2630  sbuts->flag &= ~SB_PIN_CONTEXT;
2631  }
2632 
2633  /* TODO: restore path pointers: T40046
2634  * (complicated because this contains data pointers too, not just ID). */
2635  MEM_SAFE_FREE(sbuts->path);
2636  }
2637  else if (sl->spacetype == SPACE_FILE) {
2638  SpaceFile *sfile = (SpaceFile *)sl;
2639  sfile->op = NULL;
2641  }
2642  else if (sl->spacetype == SPACE_ACTION) {
2643  SpaceAction *saction = (SpaceAction *)sl;
2644 
2645  saction->action = restore_pointer_by_name(id_map, (ID *)saction->action, USER_REAL);
2646  saction->ads.source = restore_pointer_by_name(
2647  id_map, (ID *)saction->ads.source, USER_REAL);
2648 
2649  if (saction->ads.filter_grp) {
2651  id_map, (ID *)saction->ads.filter_grp, USER_IGNORE);
2652  }
2653 
2654  /* force recalc of list of channels, potentially updating the active action
2655  * while we're at it (as it can only be updated that way) T28962.
2656  */
2658  }
2659  else if (sl->spacetype == SPACE_IMAGE) {
2660  SpaceImage *sima = (SpaceImage *)sl;
2661 
2662  sima->image = restore_pointer_by_name(id_map, (ID *)sima->image, USER_REAL);
2663 
2664  /* this will be freed, not worth attempting to find same scene,
2665  * since it gets initialized later */
2666  sima->iuser.scene = NULL;
2667 
2668 #if 0
2669  /* Those are allocated and freed by space code, no need to handle them here. */
2673  MEM_SAFE_FREE(sima->scopes.vecscope);
2674 #endif
2675  sima->scopes.ok = 0;
2676 
2677  /* NOTE: pre-2.5, this was local data not lib data, but now we need this as lib data
2678  * so assume that here we're doing for undo only...
2679  */
2680  sima->gpd = restore_pointer_by_name(id_map, (ID *)sima->gpd, USER_REAL);
2682  id_map, (ID *)sima->mask_info.mask, USER_REAL);
2683  }
2684  else if (sl->spacetype == SPACE_SEQ) {
2685  SpaceSeq *sseq = (SpaceSeq *)sl;
2686 
2687  /* NOTE: pre-2.5, this was local data not lib data, but now we need this as lib data
2688  * so assume that here we're doing for undo only...
2689  */
2690  sseq->gpd = restore_pointer_by_name(id_map, (ID *)sseq->gpd, USER_REAL);
2691  }
2692  else if (sl->spacetype == SPACE_NLA) {
2693  SpaceNla *snla = (SpaceNla *)sl;
2694  bDopeSheet *ads = snla->ads;
2695 
2696  if (ads) {
2698 
2699  if (ads->filter_grp) {
2701  id_map, (ID *)ads->filter_grp, USER_IGNORE);
2702  }
2703  }
2704  }
2705  else if (sl->spacetype == SPACE_TEXT) {
2706  SpaceText *st = (SpaceText *)sl;
2707 
2708  st->text = restore_pointer_by_name(id_map, (ID *)st->text, USER_IGNORE);
2709  if (st->text == NULL) {
2710  st->text = newmain->texts.first;
2711  }
2712  }
2713  else if (sl->spacetype == SPACE_SCRIPT) {
2714  SpaceScript *scpt = (SpaceScript *)sl;
2715 
2717 
2718  // screen->script = NULL; /* 2.45 set to null, better re-run the script. */
2719  if (scpt->script) {
2720  SCRIPT_SET_NULL(scpt->script);
2721  }
2722  }
2723  else if (sl->spacetype == SPACE_OUTLINER) {
2724  SpaceOutliner *space_outliner = (SpaceOutliner *)sl;
2725 
2726  space_outliner->search_tse.id = restore_pointer_by_name(
2727  id_map, space_outliner->search_tse.id, USER_IGNORE);
2728 
2729  if (space_outliner->treestore) {
2730  TreeStoreElem *tselem;
2731  BLI_mempool_iter iter;
2732 
2733  BLI_mempool_iternew(space_outliner->treestore, &iter);
2734  while ((tselem = BLI_mempool_iterstep(&iter))) {
2735  /* Do not try to restore pointers to drivers/sequence/etc.,
2736  * can crash in undo case! */
2737  if (TSE_IS_REAL_ID(tselem)) {
2738  tselem->id = restore_pointer_by_name(id_map, tselem->id, USER_IGNORE);
2739  }
2740  else {
2741  tselem->id = NULL;
2742  }
2743  }
2744  /* rebuild hash table, because it depends on ids too */
2745  space_outliner->storeflag |= SO_TREESTORE_REBUILD;
2746  }
2747  }
2748  else if (sl->spacetype == SPACE_NODE) {
2749  SpaceNode *snode = (SpaceNode *)sl;
2750  bNodeTreePath *path, *path_next;
2751  bNodeTree *ntree;
2752 
2753  /* node tree can be stored locally in id too, link this first */
2754  snode->id = restore_pointer_by_name(id_map, snode->id, USER_REAL);
2755  snode->from = restore_pointer_by_name(id_map, snode->from, USER_IGNORE);
2756 
2757  ntree = snode->id ? ntreeFromID(snode->id) : NULL;
2758  snode->nodetree = ntree ?
2759  ntree :
2761 
2762  for (path = snode->treepath.first; path; path = path->next) {
2763  if (path == snode->treepath.first) {
2764  /* first nodetree in path is same as snode->nodetree */
2765  path->nodetree = snode->nodetree;
2766  }
2767  else {
2769  }
2770 
2771  if (!path->nodetree) {
2772  break;
2773  }
2774  }
2775 
2776  /* remaining path entries are invalid, remove */
2777  for (; path; path = path_next) {
2778  path_next = path->next;
2779 
2780  BLI_remlink(&snode->treepath, path);
2781  MEM_freeN(path);
2782  }
2783 
2784  /* edittree is just the last in the path,
2785  * set this directly since the path may have been shortened above */
2786  if (snode->treepath.last) {
2787  path = snode->treepath.last;
2788  snode->edittree = path->nodetree;
2789  }
2790  else {
2791  snode->edittree = NULL;
2792  }
2793  }
2794  else if (sl->spacetype == SPACE_CLIP) {
2795  SpaceClip *sclip = (SpaceClip *)sl;
2796 
2797  sclip->clip = restore_pointer_by_name(id_map, (ID *)sclip->clip, USER_REAL);
2799  id_map, (ID *)sclip->mask_info.mask, USER_REAL);
2800 
2801  sclip->scopes.ok = 0;
2802  }
2803  else if (sl->spacetype == SPACE_SPREADSHEET) {
2804  SpaceSpreadsheet *sspreadsheet = (SpaceSpreadsheet *)sl;
2805 
2807  if (context->type == SPREADSHEET_CONTEXT_OBJECT) {
2809  object_context->object = restore_pointer_by_name(
2810  id_map, (ID *)object_context->object, USER_IGNORE);
2811  }
2812  }
2813  }
2814  }
2815  }
2816  }
2817 }
2818 
2820  Main *newmain,
2821  wmWindowManager *curwm,
2822  Scene *curscene,
2823  ViewLayer *cur_view_layer)
2824 {
2826  newmain, true, oldmain, MAIN_IDMAP_TYPE_NAME);
2827 
2828  LISTBASE_FOREACH (WorkSpace *, workspace, &newmain->workspaces) {
2829  LISTBASE_FOREACH (WorkSpaceLayout *, layout, &workspace->layouts) {
2830  lib_link_workspace_layout_restore(id_map, newmain, layout);
2831  }
2832  workspace->pin_scene = restore_pointer_by_name(
2833  id_map, (ID *)workspace->pin_scene, USER_IGNORE);
2834  }
2835 
2836  LISTBASE_FOREACH (wmWindow *, win, &curwm->windows) {
2837  WorkSpace *workspace = BKE_workspace_active_get(win->workspace_hook);
2838  ID *workspace_id = (ID *)workspace;
2839  Scene *oldscene = win->scene;
2840 
2841  workspace = restore_pointer_by_name(id_map, workspace_id, USER_REAL);
2842  BKE_workspace_active_set(win->workspace_hook, workspace);
2843  win->scene = restore_pointer_by_name(id_map, (ID *)win->scene, USER_REAL);
2844  if (win->scene == NULL) {
2845  win->scene = curscene;
2846  }
2847  win->unpinned_scene = restore_pointer_by_name(id_map, (ID *)win->unpinned_scene, USER_IGNORE);
2848  if (BKE_view_layer_find(win->scene, win->view_layer_name) == NULL) {
2849  STRNCPY(win->view_layer_name, cur_view_layer->name);
2850  }
2851  BKE_workspace_active_set(win->workspace_hook, workspace);
2852 
2853  /* keep cursor location through undo */
2854  memcpy(&win->scene->cursor, &oldscene->cursor, sizeof(win->scene->cursor));
2855 
2856  /* NOTE: even though that function seems to redo part of what is done by
2857  * `lib_link_workspace_layout_restore()` above, it seems to have a slightly different scope:
2858  * while the former updates the whole UI pointers from Main db (going over all layouts of
2859  * all workspaces), that one only focuses one current active screen, takes care of
2860  * potential local view, and needs window's scene pointer to be final... */
2861  lib_link_window_scene_data_restore(win, win->scene, cur_view_layer);
2862 
2863  BLI_assert(win->screen == NULL);
2864  }
2865 
2867 
2868  /* Restore all ID pointers in Main database itself
2869  * (especially IDProperties might point to some word-space of other 'weirdly unchanged' ID
2870  * pointers, see T69146).
2871  * Note that this will re-apply again a few pointers in workspaces or so,
2872  * but since we are remapping final ones already set above,
2873  * that is just some minor harmless double-processing. */
2875 
2876  /* update IDs stored in all possible clipboards */
2878 
2880 }
2881 
2884 /* -------------------------------------------------------------------- */
2889 {
2890  Main *newmain;
2891 
2892  /* check if the library was already read */
2893  for (newmain = fd->mainlist->first; newmain; newmain = newmain->next) {
2894  if (newmain->curlib) {
2895  if (BLI_path_cmp(newmain->curlib->filepath_abs, lib->filepath_abs) == 0) {
2897  RPT_WARNING,
2898  TIP_("Library '%s', '%s' had multiple instances, save and reload!"),
2899  lib->filepath,
2900  lib->filepath_abs);
2901 
2903  /* change_link_placeholder_to_real_ID_pointer_fd(fd, lib, newmain->curlib); */
2904 
2905  BLI_remlink(&main->libraries, lib);
2906  MEM_freeN(lib);
2907 
2908  /* Now, since Blender always expect **latest** Main pointer from fd->mainlist
2909  * to be the active library Main pointer,
2910  * where to add all non-library data-blocks found in file next, we have to switch that
2911  * 'dupli' found Main to latest position in the list!
2912  * Otherwise, you get weird disappearing linked data on a rather inconsistent basis.
2913  * See also T53977 for reproducible case. */
2914  BLI_remlink(fd->mainlist, newmain);
2915  BLI_addtail(fd->mainlist, newmain);
2916 
2917  return;
2918  }
2919  }
2920  }
2921 
2922  /* Make sure we have full path in lib->filepath_abs */
2923  BLI_strncpy(lib->filepath_abs, lib->filepath, sizeof(lib->filepath));
2924  BLI_path_normalize(fd->relabase, lib->filepath_abs);
2925 
2926  // printf("direct_link_library: filepath %s\n", lib->filepath);
2927  // printf("direct_link_library: filepath_abs %s\n", lib->filepath_abs);
2928 
2929  BlendDataReader reader = {fd};
2930  BKE_packedfile_blend_read(&reader, &lib->packedfile);
2931 
2932  /* new main */
2933  newmain = BKE_main_new();
2934  BLI_addtail(fd->mainlist, newmain);
2935  newmain->curlib = lib;
2936 
2937  lib->parent = NULL;
2938 
2939  id_us_ensure_real(&lib->id);
2940 }
2941 
2943 {
2944 }
2945 
2946 /* Always call this once you have loaded new library data to set the relative paths correctly
2947  * in relation to the blend file. */
2948 static void fix_relpaths_library(const char *basepath, Main *main)
2949 {
2950  /* #BLO_read_from_memory uses a blank file-path. */
2951  if (basepath == NULL || basepath[0] == '\0') {
2952  LISTBASE_FOREACH (Library *, lib, &main->libraries) {
2953  /* when loading a linked lib into a file which has not been saved,
2954  * there is nothing we can be relative to, so instead we need to make
2955  * it absolute. This can happen when appending an object with a relative
2956  * link into an unsaved blend file. See T27405.
2957  * The remap relative option will make it relative again on save - campbell */
2958  if (BLI_path_is_rel(lib->filepath)) {
2959  BLI_strncpy(lib->filepath, lib->filepath_abs, sizeof(lib->filepath));
2960  }
2961  }
2962  }
2963  else {
2964  LISTBASE_FOREACH (Library *, lib, &main->libraries) {
2965  /* Libraries store both relative and abs paths, recreate relative paths,
2966  * relative to the blend file since indirectly linked libs will be
2967  * relative to their direct linked library. */
2968  if (BLI_path_is_rel(lib->filepath)) { /* if this is relative to begin with? */
2969  BLI_strncpy(lib->filepath, lib->filepath_abs, sizeof(lib->filepath));
2970  BLI_path_rel(lib->filepath, basepath);
2971  }
2972  }
2973  }
2974 }
2975 
2978 /* -------------------------------------------------------------------- */
2982 static ID *create_placeholder(Main *mainvar, const short idcode, const char *idname, const int tag)
2983 {
2984  ListBase *lb = which_libbase(mainvar, idcode);
2985  ID *ph_id = BKE_libblock_alloc_notest(idcode);
2986 
2987  *((short *)ph_id->name) = idcode;
2988  BLI_strncpy(ph_id->name + 2, idname, sizeof(ph_id->name) - 2);
2989  BKE_libblock_init_empty(ph_id);
2990  ph_id->lib = mainvar->curlib;
2991  ph_id->tag = tag | LIB_TAG_MISSING;
2992  ph_id->us = ID_FAKE_USERS(ph_id);
2993  ph_id->icon_id = 0;
2994 
2995  BLI_addtail(lb, ph_id);
2996  id_sort_by_name(lb, ph_id, NULL);
2997 
2998  if (mainvar->id_map != NULL) {
2999  BKE_main_idmap_insert_id(mainvar->id_map, ph_id);
3000  }
3001 
3002  if ((tag & LIB_TAG_TEMP_MAIN) == 0) {
3004  }
3005 
3006  return ph_id;
3007 }
3008 
3010 {
3011  /* Placeholder ObData IDs won't have any material, we have to update their objects for that,
3012  * otherwise the inconsistency between both will lead to crashes (especially in Eevee?). */
3013  LISTBASE_FOREACH (Object *, ob, &bmain->objects) {
3014  ID *obdata = ob->data;
3015  if (obdata != NULL && obdata->tag & LIB_TAG_MISSING) {
3016  BKE_object_materials_test(bmain, ob, obdata);
3017  }
3018  }
3019 }
3020 
3021 static const char *dataname(short id_code)
3022 {
3023  switch ((ID_Type)id_code) {
3024  case ID_OB:
3025  return "Data from OB";
3026  case ID_ME:
3027  return "Data from ME";
3028  case ID_IP:
3029  return "Data from IP";
3030  case ID_SCE:
3031  return "Data from SCE";
3032  case ID_MA:
3033  return "Data from MA";
3034  case ID_TE:
3035  return "Data from TE";
3036  case ID_CU_LEGACY:
3037  return "Data from CU";
3038  case ID_GR:
3039  return "Data from GR";
3040  case ID_AR:
3041  return "Data from AR";
3042  case ID_AC:
3043  return "Data from AC";
3044  case ID_LI:
3045  return "Data from LI";
3046  case ID_MB:
3047  return "Data from MB";
3048  case ID_IM:
3049  return "Data from IM";
3050  case ID_LT:
3051  return "Data from LT";
3052  case ID_LA:
3053  return "Data from LA";
3054  case ID_CA:
3055  return "Data from CA";
3056  case ID_KE:
3057  return "Data from KE";
3058  case ID_WO:
3059  return "Data from WO";
3060  case ID_SCR:
3061  return "Data from SCR";
3062  case ID_VF:
3063  return "Data from VF";
3064  case ID_TXT:
3065  return "Data from TXT";
3066  case ID_SPK:
3067  return "Data from SPK";
3068  case ID_LP:
3069  return "Data from LP";
3070  case ID_SO:
3071  return "Data from SO";
3072  case ID_NT:
3073  return "Data from NT";
3074  case ID_BR:
3075  return "Data from BR";
3076  case ID_PA:
3077  return "Data from PA";
3078  case ID_PAL:
3079  return "Data from PAL";
3080  case ID_PC:
3081  return "Data from PCRV";
3082  case ID_GD:
3083  return "Data from GD";
3084  case ID_WM:
3085  return "Data from WM";
3086  case ID_MC:
3087  return "Data from MC";
3088  case ID_MSK:
3089  return "Data from MSK";
3090  case ID_LS:
3091  return "Data from LS";
3092  case ID_CF:
3093  return "Data from CF";
3094  case ID_WS:
3095  return "Data from WS";
3096  case ID_CV:
3097  return "Data from HA";
3098  case ID_PT:
3099  return "Data from PT";
3100  case ID_VO:
3101  return "Data from VO";
3102  case ID_SIM:
3103  return "Data from SIM";
3104  }
3105  return "Data from Lib Block";
3106 }
3107 
3108 static bool direct_link_id(FileData *fd, Main *main, const int tag, ID *id, ID *id_old)
3109 {
3110  BlendDataReader reader = {fd};
3111 
3112  /* Read part of datablock that is common between real and embedded datablocks. */
3113  direct_link_id_common(&reader, main->curlib, id, id_old, tag);
3114 
3115  if (tag & LIB_TAG_ID_LINK_PLACEHOLDER) {
3116  /* For placeholder we only need to set the tag, no further data to read. */
3117  id->tag = tag;
3118  return true;
3119  }
3120 
3121  const IDTypeInfo *id_type = BKE_idtype_get_info_from_id(id);
3122  if (id_type->blend_read_data != NULL) {
3123  id_type->blend_read_data(&reader, id);
3124  }
3125 
3126  /* XXX Very weakly handled currently, see comment in read_libblock() before trying to
3127  * use it for anything new. */
3128  bool success = true;
3129 
3130  switch (GS(id->name)) {
3131  case ID_SCR:
3132  success = BKE_screen_blend_read_data(&reader, (bScreen *)id);
3133  break;
3134  case ID_LI:
3135  direct_link_library(fd, (Library *)id, main);
3136  break;
3137  default:
3138  /* Do nothing. Handled by IDTypeInfo callback. */
3139  break;
3140  }
3141 
3142  /* try to restore (when undoing) or clear ID's cache pointers. */
3143  if (id_type->foreach_cache != NULL) {
3146  }
3147 
3148  return success;
3149 }
3150 
3151 /* Read all data associated with a datablock into datamap. */
3152 static BHead *read_data_into_datamap(FileData *fd, BHead *bhead, const char *allocname)
3153 {
3154  bhead = blo_bhead_next(fd, bhead);
3155 
3156  while (bhead && bhead->code == DATA) {
3157  /* The code below is useful for debugging leaks in data read from the blend file.
3158  * Without this the messages only tell us what ID-type the memory came from,
3159  * eg: `Data from OB len 64`, see #dataname.
3160  * With the code below we get the struct-name to help tracking down the leak.
3161  * This is kept disabled as the #malloc for the text always leaks memory. */
3162 #if 0
3163  {
3164  const short *sp = fd->filesdna->structs[bhead->SDNAnr];
3165  allocname = fd->filesdna->types[sp[0]];
3166  size_t allocname_size = strlen(allocname) + 1;
3167  char *allocname_buf = malloc(allocname_size);
3168  memcpy(allocname_buf, allocname, allocname_size);
3169  allocname = allocname_buf;
3170  }
3171 #endif
3172 
3173  void *data = read_struct(fd, bhead, allocname);
3174  if (data) {
3175  oldnewmap_insert(fd->datamap, bhead->old, data, 0);
3176  }
3177 
3178  bhead = blo_bhead_next(fd, bhead);
3179  }
3180 
3181  return bhead;
3182 }
3183 
3184 /* Verify if the datablock and all associated data is identical. */
3186 {
3187  /* Test ID itself. */
3188  if (bhead->len && !BHEADN_FROM_BHEAD(bhead)->is_memchunk_identical) {
3189  return false;
3190  }
3191 
3192  /* Test any other data that is part of ID (logic must match read_data_into_datamap). */
3193  bhead = blo_bhead_next(fd, bhead);
3194 
3195  while (bhead && bhead->code == DATA) {
3196  if (bhead->len && !BHEADN_FROM_BHEAD(bhead)->is_memchunk_identical) {
3197  return false;
3198  }
3199 
3200  bhead = blo_bhead_next(fd, bhead);
3201  }
3202 
3203  return true;
3204 }
3205 
3206 /* For undo, restore matching library datablock from the old main. */
3208 {
3209  /* In undo case, most libs and linked data should be kept as is from previous state
3210  * (see BLO_read_from_memfile).
3211  * However, some needed by the snapshot being read may have been removed in previous one,
3212  * and would go missing.
3213  * This leads e.g. to disappearing objects in some undo/redo case, see T34446.
3214  * That means we have to carefully check whether current lib or
3215  * libdata already exits in old main, if it does we merely copy it over into new main area,
3216  * otherwise we have to do a full read of that bhead... */
3217  CLOG_INFO(&LOG_UNDO, 2, "UNDO: restore library %s", id->name);
3218 
3219  Main *libmain = fd->old_mainlist->first;
3220  /* Skip oldmain itself... */
3221  for (libmain = libmain->next; libmain; libmain = libmain->next) {
3222  if (libmain->curlib && STREQ(id->name, libmain->curlib->id.name)) {
3223  Main *oldmain = fd->old_mainlist->first;
3225  2,
3226  " compare with %s -> match",
3227  libmain->curlib ? libmain->curlib->id.name : "<NULL>");
3228  /* In case of a library, we need to re-add its main to fd->mainlist,
3229  * because if we have later a missing ID_LINK_PLACEHOLDER,
3230  * we need to get the correct lib it is linked to!
3231  * Order is crucial, we cannot bulk-add it in BLO_read_from_memfile()
3232  * like it used to be. */
3233  BLI_remlink(fd->old_mainlist, libmain);
3234  BLI_remlink_safe(&oldmain->libraries, libmain->curlib);
3235  BLI_addtail(fd->mainlist, libmain);
3236  BLI_addtail(&main->libraries, libmain->curlib);
3237  return true;
3238  }
3240  2,
3241  " compare with %s -> NO match",
3242  libmain->curlib ? libmain->curlib->id.name : "<NULL>");
3243  }
3244 
3245  return false;
3246 }
3247 
3248 /* For undo, restore existing linked datablock from the old main. */
3249 static bool read_libblock_undo_restore_linked(FileData *fd, Main *main, const ID *id, BHead *bhead)
3250 {
3251  CLOG_INFO(&LOG_UNDO, 2, "UNDO: restore linked datablock %s", id->name);
3252 
3253  ID *id_old = BKE_libblock_find_name(main, GS(id->name), id->name + 2);
3254  if (id_old != NULL) {
3256  2,
3257  " from %s (%s): found",
3258  main->curlib ? main->curlib->id.name : "<NULL>",
3259  main->curlib ? main->curlib->filepath : "<NULL>");
3260  /* Even though we found our linked ID, there is no guarantee its address
3261  * is still the same. */
3262  if (id_old != bhead->old) {
3263  oldnewmap_lib_insert(fd, bhead->old, id_old, GS(id_old->name));
3264  }
3265 
3266  /* No need to do anything else for ID_LINK_PLACEHOLDER, it's assumed
3267  * already present in its lib's main. */
3268  return true;
3269  }
3270 
3272  2,
3273  " from %s (%s): NOT found",
3274  main->curlib ? main->curlib->id.name : "<NULL>",
3275  main->curlib ? main->curlib->filepath : "<NULL>");
3276  return false;
3277 }
3278 
3279 /* For undo, restore unchanged datablock from old main. */
3281  FileData *fd, Main *main, const ID *UNUSED(id), ID *id_old, const int tag)
3282 {
3284  BLI_assert(id_old != NULL);
3285 
3286  /* Some tags need to be preserved here. */
3287  id_old->tag = tag | (id_old->tag & LIB_TAG_EXTRAUSER);
3288  id_old->lib = main->curlib;
3289  id_old->us = ID_FAKE_USERS(id_old);
3290  /* Do not reset id->icon_id here, memory allocated for it remains valid. */
3291  /* Needed because .blend may have been saved with crap value here... */
3292  id_old->newid = NULL;
3293  id_old->orig_id = NULL;
3294 
3295  const short idcode = GS(id_old->name);
3296  Main *old_bmain = fd->old_mainlist->first;
3297  ListBase *old_lb = which_libbase(old_bmain, idcode);
3298  ListBase *new_lb = which_libbase(main, idcode);
3299  BLI_remlink(old_lb, id_old);
3300  BLI_addtail(new_lb, id_old);
3301 
3302  /* Recalc flags, mostly these just remain as they are. */
3304  id_old->recalc_after_undo_push = 0;
3305 
3306  if (GS(id_old->name) == ID_OB) {
3307  Object *ob = (Object *)id_old;
3308  /* For undo we stay in object mode during undo presses, so keep editmode disabled for re-used
3309  * data-blocks too. */
3310  ob->mode &= ~OB_MODE_EDIT;
3311  }
3312 }
3313 
3314 /* For undo, store changed datablock at old address. */
3316 {
3317  /* During memfile undo, if an ID changed and we cannot directly re-use existing one from old
3318  * bmain, we do a full read of the new id from the memfile, and then fully swap its content
3319  * with the old id. This allows us to keep the same pointer even for modified data, which
3320  * helps reducing further detected changes by the depsgraph (since unchanged IDs remain fully
3321  * unchanged, even if they are using/pointing to a changed one). */
3323  BLI_assert(id_old != NULL);
3324 
3325  const short idcode = GS(id->name);
3326 
3327  Main *old_bmain = fd->old_mainlist->first;
3328  ListBase *old_lb = which_libbase(old_bmain, idcode);
3329  ListBase *new_lb = which_libbase(main, idcode);
3330  BLI_remlink(old_lb, id_old);
3331  BLI_remlink(new_lb, id);
3332 
3333  /* We do not need any remapping from this call here, since no ID pointer is valid in the data
3334  * currently (they are all pointing to old addresses, and need to go through `lib_link`
3335  * process). So we can pass NULL for the Main pointer parameter. */
3336  BKE_lib_id_swap_full(NULL, id, id_old);
3337 
3338  /* Special temporary usage of this pointer, necessary for the `undo_preserve` call after
3339  * lib-linking to restore some data that should never be affected by undo, e.g. the 3D cursor of
3340  * #Scene. */
3341  id_old->orig_id = id;
3342 
3343  BLI_addtail(new_lb, id_old);
3344  BLI_addtail(old_lb, id);
3345 }
3346 
3348  FileData *fd, Main *main, BHead *bhead, const int tag, ID **r_id_old)
3349 {
3350  /* Get pointer to memory of new ID that we will be reading. */
3351  const ID *id = peek_struct_undo(fd, bhead);
3352  const short idcode = GS(id->name);
3353 
3354  if (bhead->code == ID_LI) {
3355  /* Restore library datablock. */
3357  return true;
3358  }
3359  }
3360  else if (bhead->code == ID_LINK_PLACEHOLDER) {
3361  /* Restore linked datablock. */
3362  if (read_libblock_undo_restore_linked(fd, main, id, bhead)) {
3363  return true;
3364  }
3365  }
3366  else if (ELEM(idcode, ID_WM, ID_SCR, ID_WS)) {
3367  /* Skip reading any UI datablocks, existing ones are kept. We don't
3368  * support pointers from other datablocks to UI datablocks so those
3369  * we also don't put UI datablocks in fd->libmap. */
3370  return true;
3371  }
3372 
3373  /* Restore local datablocks. */
3374  ID *id_old = NULL;
3375  const bool do_partial_undo = (fd->skip_flags & BLO_READ_SKIP_UNDO_OLD_MAIN) == 0;
3376  if (do_partial_undo && (bhead->code != ID_LINK_PLACEHOLDER)) {
3377  /* This code should only ever be reached for local data-blocks. */
3378  BLI_assert(main->curlib == NULL);
3379 
3380  /* Find the 'current' existing ID we want to reuse instead of the one we
3381  * would read from the undo memfile. */
3382  BLI_assert(fd->old_idmap != NULL);
3384  }
3385 
3386  if (id_old != NULL && read_libblock_is_identical(fd, bhead)) {
3387  /* Local datablock was unchanged, restore from the old main. */
3389  2,
3390  "UNDO: read %s (uuid %u) -> keep identical datablock",
3391  id->name,
3392  id->session_uuid);
3393 
3394  /* Do not add LIB_TAG_NEW here, this should not be needed/used in undo case anyway (as
3395  * this is only for do_version-like code), but for sake of consistency, and also because
3396  * it will tell us which ID is re-used from old Main, and which one is actually new. */
3397  /* Also do not add LIB_TAG_NEED_LINK, those IDs will never be re-liblinked, hence that tag will
3398  * never be cleared, leading to critical issue in link/append code. */
3399  const int id_tag = tag | LIB_TAG_UNDO_OLD_ID_REUSED;
3400  read_libblock_undo_restore_identical(fd, main, id, id_old, id_tag);
3401 
3402  /* Insert into library map for lookup by newly read datablocks (with pointer value bhead->old).
3403  * Note that existing datablocks in memory (which pointer value would be id_old) are not
3404  * remapped anymore, so no need to store this info here. */
3405  oldnewmap_lib_insert(fd, bhead->old, id_old, bhead->code);
3406 
3407  *r_id_old = id_old;
3408  return true;
3409  }
3410  if (id_old != NULL) {
3411  /* Local datablock was changed. Restore at the address of the old datablock. */
3413  2,
3414  "UNDO: read %s (uuid %u) -> read to old existing address",
3415  id->name,
3416  id->session_uuid);
3417  *r_id_old = id_old;
3418  return false;
3419  }
3420 
3421  /* Local datablock does not exist in the undo step, so read from scratch. */
3422  CLOG_INFO(
3423  &LOG_UNDO, 2, "UNDO: read %s (uuid %u) -> read at new address", id->name, id->session_uuid);
3424  return false;
3425 }
3426 
3427 /* This routine reads a datablock and its direct data, and advances bhead to
3428  * the next datablock. For library linked datablocks, only a placeholder will
3429  * be generated, to be replaced in read_library_linked_ids.
3430  *
3431  * When reading for undo, libraries, linked datablocks and unchanged datablocks
3432  * will be restored from the old database. Only new or changed datablocks will
3433  * actually be read. */
3435  Main *main,
3436  BHead *bhead,
3437  const int tag,
3438  const bool placeholder_set_indirect_extern,
3439  ID **r_id)
3440 {
3441  /* First attempt to restore existing datablocks for undo.
3442  * When datablocks are changed but still exist, we restore them at the old
3443  * address and inherit recalc flags for the dependency graph. */
3444  ID *id_old = NULL;
3445  if (fd->flags & FD_FLAGS_IS_MEMFILE) {
3446  if (read_libblock_undo_restore(fd, main, bhead, tag, &id_old)) {
3447  if (r_id) {
3448  *r_id = id_old;
3449  }
3450  if (main->id_map != NULL) {
3451  BKE_main_idmap_insert_id(main->id_map, id_old);
3452  }
3453 
3454  return blo_bhead_next(fd, bhead);
3455  }
3456  }
3457 
3458  /* Read libblock struct. */
3459  ID *id = read_struct(fd, bhead, "lib block");
3460  if (id == NULL) {
3461  if (r_id) {
3462  *r_id = NULL;
3463  }
3464  return blo_bhead_next(fd, bhead);
3465  }
3466 
3467  /* Determine ID type and add to main database list. */
3468  const short idcode = GS(id->name);
3469  ListBase *lb = which_libbase(main, idcode);
3470  if (lb == NULL) {
3471  /* Unknown ID type. */
3472  CLOG_WARN(&LOG, "Unknown id code '%c%c'", (idcode & 0xff), (idcode >> 8));
3473  MEM_freeN(id);
3474  if (r_id) {
3475  *r_id = NULL;
3476  }
3477  return blo_bhead_next(fd, bhead);
3478  }
3479 
3480  /* NOTE: id must be added to the list before direct_link_id(), since
3481  * direct_link_library() may remove it from there in case of duplicates. */
3482  BLI_addtail(lb, id);
3483 
3484  /* Insert into library map for lookup by newly read datablocks (with pointer value bhead->old).
3485  * Note that existing datablocks in memory (which pointer value would be id_old) are not remapped
3486  * remapped anymore, so no need to store this info here. */
3487  ID *id_target = id_old ? id_old : id;
3488  oldnewmap_lib_insert(fd, bhead->old, id_target, bhead->code);
3489 
3490  if (r_id) {
3491  *r_id = id_target;
3492  }
3493 
3494  /* Set tag for new datablock to indicate lib linking and versioning needs
3495  * to be done still. */
3496  int id_tag = tag | LIB_TAG_NEED_LINK | LIB_TAG_NEW;
3497 
3498  if (bhead->code == ID_LINK_PLACEHOLDER) {
3499  /* Read placeholder for linked datablock. */
3500  id_tag |= LIB_TAG_ID_LINK_PLACEHOLDER;
3501 
3502  if (placeholder_set_indirect_extern) {
3503  if (id->flag & LIB_INDIRECT_WEAK_LINK) {
3504  id_tag |= LIB_TAG_INDIRECT;
3505  }
3506  else {
3507  id_tag |= LIB_TAG_EXTERN;
3508  }
3509  }
3510 
3511  direct_link_id(fd, main, id_tag, id, id_old);
3512 
3513  if (main->id_map != NULL) {
3514  BKE_main_idmap_insert_id(main->id_map, id);
3515  }
3516 
3517  return blo_bhead_next(fd, bhead);
3518  }
3519 
3520  /* Read datablock contents.
3521  * Use convenient malloc name for debugging and better memory link prints. */
3522  const char *allocname = dataname(idcode);
3523  bhead = read_data_into_datamap(fd, bhead, allocname);
3524  const bool success = direct_link_id(fd, main, id_tag, id, id_old);
3525  oldnewmap_clear(fd->datamap);
3526 
3527  if (!success) {
3528  /* XXX This is probably working OK currently given the very limited scope of that flag.
3529  * However, it is absolutely **not** handled correctly: it is freeing an ID pointer that has
3530  * been added to the fd->libmap mapping, which in theory could lead to nice crashes...
3531  * This should be properly solved at some point. */
3532  BKE_id_free(main, id);
3533  if (r_id != NULL) {
3534  *r_id = NULL;
3535  }
3536  }
3537  else if (id_old) {
3538  /* For undo, store contents read into id at id_old. */
3540 
3541  if (main->id_map != NULL) {
3542  BKE_main_idmap_insert_id(main->id_map, id_old);
3543  }
3544  }
3545  else if (main->id_map != NULL) {
3546  BKE_main_idmap_insert_id(main->id_map, id);
3547  }
3548 
3549  return bhead;
3550 }
3551 
3554 /* -------------------------------------------------------------------- */
3559 {
3561 
3562  bhead = read_data_into_datamap(fd, bhead, "asset-data read");
3563 
3564  BlendDataReader reader = {fd};
3565  BLO_read_data_address(&reader, r_asset_data);
3566  BKE_asset_metadata_read(&reader, *r_asset_data);
3567 
3568  oldnewmap_clear(fd->datamap);
3569 
3570  return bhead;
3571 }
3572 
3575 /* -------------------------------------------------------------------- */
3579 /* NOTE: this has to be kept for reading older files... */
3580 /* also version info is written here */
3581 static BHead *read_global(BlendFileData *bfd, FileData *fd, BHead *bhead)
3582 {
3583  FileGlobal *fg = read_struct(fd, bhead, "Global");
3584 
3585  /* NOTE: `bfd->main->versionfile` is supposed to have already been set from `fd->fileversion`
3586  * beforehand by calling code. */
3587  bfd->main->subversionfile = fg->subversion;
3590 
3591  bfd->main->minversionfile = fg->minversion;
3592  bfd->main->minsubversionfile = fg->minsubversion;
3593 
3595  BLI_strncpy(bfd->main->build_hash, fg->build_hash, sizeof(bfd->main->build_hash));
3596 
3597  bfd->fileflags = fg->fileflags;
3598  bfd->globalf = fg->globalf;
3599  STRNCPY(bfd->filepath, fg->filepath);
3600 
3601  /* Error in 2.65 and older: `main->filepath` was not set if you save from startup
3602  * (not after loading file). */
3603  if (bfd->filepath[0] == 0) {
3604  if (fd->fileversion < 265 || (fd->fileversion == 265 && fg->subversion < 1)) {
3605  if ((G.fileflags & G_FILE_RECOVER_READ) == 0) {
3607  }
3608  }
3609 
3610  /* early 2.50 version patch - filepath not in FileGlobal struct at all */
3611  if (fd->fileversion <= 250) {
3613  }
3614  }
3615 
3616  if (G.fileflags & G_FILE_RECOVER_READ) {
3617  BLI_strncpy(fd->relabase, fg->filepath, sizeof(fd->relabase));
3618  }
3619 
3620  bfd->curscreen = fg->curscreen;
3621  bfd->curscene = fg->curscene;
3622  bfd->cur_view_layer = fg->cur_view_layer;
3623 
3624  MEM_freeN(fg);
3625 
3626  fd->globalf = bfd->globalf;
3627  fd->fileflags = bfd->fileflags;
3628 
3629  return blo_bhead_next(fd, bhead);
3630 }
3631 
3632 /* NOTE: this has to be kept for reading older files... */
3633 static void link_global(FileData *fd, BlendFileData *bfd)
3634 {
3636  bfd->curscreen = newlibadr(fd, NULL, bfd->curscreen);
3637  bfd->curscene = newlibadr(fd, NULL, bfd->curscene);
3638  /* this happens in files older than 2.35 */
3639  if (bfd->curscene == NULL) {
3640  if (bfd->curscreen) {
3641  bfd->curscene = bfd->curscreen->scene;
3642  }
3643  }
3644 }
3645 
3648 /* -------------------------------------------------------------------- */
3653 {
3654  UserDef *user = bfd->user;
3655 
3656  if (user == NULL) {
3657  return;
3658  }
3659 
3661 }
3662 
3663 static void do_versions(FileData *fd, Library *lib, Main *main)
3664 {
3665  /* WATCH IT!!!: pointers from libdata have not been converted */
3666 
3667  /* Don't allow versioning to create new data-blocks. */
3668  main->is_locked_for_linking = true;
3669 
3670  if (G.debug & G_DEBUG) {
3671  char build_commit_datetime[32];
3672  time_t temp_time = main->build_commit_timestamp;
3673  struct tm *tm = (temp_time) ? gmtime(&temp_time) : NULL;
3674  if (LIKELY(tm)) {
3675  strftime(build_commit_datetime, sizeof(build_commit_datetime), "%Y-%m-%d %H:%M", tm);
3676  }
3677  else {
3678  BLI_strncpy(build_commit_datetime, "unknown", sizeof(build_commit_datetime));
3679  }
3680 
3681  CLOG_INFO(&LOG, 0, "Read file %s", fd->relabase);
3682  CLOG_INFO(&LOG,
3683  0,
3684  " Version %d sub %d date %s hash %s",
3685  main->versionfile,
3686  main->subversionfile,
3687  build_commit_datetime,
3688  main->build_hash);
3689  }
3690 
3691  if (!main->is_read_invalid) {
3693  }
3694  if (!main->is_read_invalid) {
3696  }
3697  if (!main->is_read_invalid) {
3699  }
3700  if (!main->is_read_invalid) {
3702  }
3703  if (!main->is_read_invalid) {
3705  }
3706  if (!main->is_read_invalid) {
3708  }
3709  if (!main->is_read_invalid) {
3711  }
3712  if (!main->is_read_invalid) {
3714  }
3715 
3716  /* WATCH IT!!!: pointers from libdata have not been converted yet here! */
3717  /* WATCH IT 2!: Userdef struct init see do_versions_userdef() above! */
3718 
3719  /* don't forget to set version number in BKE_blender_version.h! */
3720 
3721  main->is_locked_for_linking = false;
3722 }
3723 
3725 {
3726  CLOG_INFO(&LOG,
3727  2,
3728  "Processing %s (%s), %d.%d",
3729  main->curlib ? main->curlib->filepath : main->filepath,
3730  main->curlib ? "LIB" : "MAIN",
3731  main->versionfile,
3732  main->subversionfile);
3733 
3734  /* Don't allow versioning to create new data-blocks. */
3735  main->is_locked_for_linking = true;
3736 
3737  if (!main->is_read_invalid) {
3739  }
3740  if (!main->is_read_invalid) {
3742  }
3743  if (!main->is_read_invalid) {
3745  }
3746  if (!main->is_read_invalid) {
3748  }
3749  if (!main->is_read_invalid) {
3751  }
3752  if (!main->is_read_invalid) {
3754  }
3755  if (!main->is_read_invalid) {
3757  }
3758 
3759  main->is_locked_for_linking = false;
3760 }
3761 
3764 /* -------------------------------------------------------------------- */
3768 static void lib_link_all(FileData *fd, Main *bmain)
3769 {
3770  const bool do_partial_undo = (fd->skip_flags & BLO_READ_SKIP_UNDO_OLD_MAIN) == 0;
3771 
3772  BlendLibReader reader = {fd, bmain};
3773 
3774  ID *id;
3775  FOREACH_MAIN_ID_BEGIN (bmain, id) {
3776  if ((id->tag & LIB_TAG_NEED_LINK) == 0) {
3777  /* This ID does not need liblink, just skip to next one. */
3778  continue;
3779  }
3780 
3781  if ((fd->flags & FD_FLAGS_IS_MEMFILE) && GS(id->name) == ID_WM) {
3782  /* No load UI for undo memfiles.
3783  * Only WM currently, SCR needs it still (see below), and so does WS? */
3784  continue;
3785  }
3786 
3787  if ((fd->flags & FD_FLAGS_IS_MEMFILE) && do_partial_undo &&
3788  (id->tag & LIB_TAG_UNDO_OLD_ID_REUSED) != 0) {
3789  /* This ID has been re-used from 'old' bmain. Since it was therefore unchanged across
3790  * current undo step, and old IDs re-use their old memory address, we do not need to liblink
3791  * it at all. */
3792  continue;
3793  }
3794 
3795  lib_link_id(&reader, id);
3796 
3797  const IDTypeInfo *id_type = BKE_idtype_get_info_from_id(id);
3798  if (id_type->blend_read_lib != NULL) {
3799  id_type->blend_read_lib(&reader, id);
3800  }
3801 
3802  if (GS(id->name) == ID_LI) {
3803  lib_link_library(&reader, (Library *)id); /* Only init users. */
3804  }
3805 
3806  id->tag &= ~LIB_TAG_NEED_LINK;
3807 
3808  /* Some data that should be persistent, like the 3DCursor or the tool settings, are
3809  * stored in IDs affected by undo, like Scene. So this requires some specific handling. */
3810  if (id_type->blend_read_undo_preserve != NULL && id->orig_id != NULL) {
3811  id_type->blend_read_undo_preserve(&reader, id, id->orig_id);
3812  }
3813  }
3815 
3816  /* Cleanup `ID.orig_id`, this is now reserved for depsgraph/COW usage only. */
3817  FOREACH_MAIN_ID_BEGIN (bmain, id) {
3818  id->orig_id = NULL;
3819  }
3821 
3822 #ifndef NDEBUG
3823  /* Double check we do not have any 'need link' tag remaining, this should never be the case once
3824  * this function has run. */
3825  FOREACH_MAIN_ID_BEGIN (bmain, id) {
3826  BLI_assert((id->tag & LIB_TAG_NEED_LINK) == 0);
3827  }
3829 #endif
3830 }
3831 
3838 {
3839  /* We only expect a merged Main here, not a split one. */
3840  BLI_assert((bmain->prev == NULL) && (bmain->next == NULL));
3841 
3842  /* Check for possible cycles in scenes' 'set' background property. */
3844 
3845  /* We could integrate that to mesh/curve/lattice lib_link, but this is really cheap process,
3846  * so simpler to just use it directly in this single call. */
3848 
3850 
3851  /* We have to rebuild that runtime information *after* all data-blocks have been properly linked.
3852  */
3854 }
3855 
3858 /* -------------------------------------------------------------------- */
3863 {
3864  BLO_read_data_address(reader, &kmi->properties);
3865  IDP_BlendDataRead(reader, &kmi->properties);
3866  kmi->ptr = NULL;
3867  kmi->flag &= ~KMI_UPDATE;
3868 }
3869 
3870 static BHead *read_userdef(BlendFileData *bfd, FileData *fd, BHead *bhead)
3871 {
3872  UserDef *user;
3873  bfd->user = user = read_struct(fd, bhead, "user def");
3874 
3875  /* User struct has separate do-version handling */
3876  user->versionfile = bfd->main->versionfile;
3877  user->subversionfile = bfd->main->subversionfile;
3878 
3879  /* read all data into fd->datamap */
3880  bhead = read_data_into_datamap(fd, bhead, "user def");
3881 
3882  BlendDataReader reader_ = {fd};
3883  BlendDataReader *reader = &reader_;
3884 
3885  BLO_read_list(reader, &user->themes);
3886  BLO_read_list(reader, &user->user_keymaps);
3887  BLO_read_list(reader, &user->user_keyconfig_prefs);
3888  BLO_read_list(reader, &user->user_menus);
3889  BLO_read_list(reader, &user->addons);
3890  BLO_read_list(reader, &user->autoexec_paths);
3891  BLO_read_list(reader, &user->asset_libraries);
3892 
3893  LISTBASE_FOREACH (wmKeyMap *, keymap, &user->user_keymaps) {
3894  keymap->modal_items = NULL;
3895  keymap->poll = NULL;
3896  keymap->flag &= ~KEYMAP_UPDATE;
3897 
3898  BLO_read_list(reader, &keymap->diff_items);
3899  BLO_read_list(reader, &keymap->items);
3900 
3901  LISTBASE_FOREACH (wmKeyMapDiffItem *, kmdi, &keymap->diff_items) {
3902  BLO_read_data_address(reader, &kmdi->remove_item);
3903  BLO_read_data_address(reader, &kmdi->add_item);
3904 
3905  if (kmdi->remove_item) {
3906  direct_link_keymapitem(reader, kmdi->remove_item);
3907  }
3908  if (kmdi->add_item) {
3909  direct_link_keymapitem(reader, kmdi->add_item);
3910  }
3911  }
3912 
3913  LISTBASE_FOREACH (wmKeyMapItem *, kmi, &keymap->items) {
3914  direct_link_keymapitem(reader, kmi);
3915  }
3916  }
3917 
3919  BLO_read_data_address(reader, &kpt->prop);
3920  IDP_BlendDataRead(reader, &kpt->prop);
3921  }
3922 
3923  LISTBASE_FOREACH (bUserMenu *, um, &user->user_menus) {
3924  BLO_read_list(reader, &um->items);
3925  LISTBASE_FOREACH (bUserMenuItem *, umi, &um->items) {
3926  if (umi->type == USER_MENU_TYPE_OPERATOR) {
3927  bUserMenuItem_Op *umi_op = (bUserMenuItem_Op *)umi;
3928  BLO_read_data_address(reader, &umi_op->prop);
3929  IDP_BlendDataRead(reader, &umi_op->prop);
3930  }
3931  }
3932  }
3933 
3934  LISTBASE_FOREACH (bAddon *, addon, &user->addons) {
3935  BLO_read_data_address(reader, &addon->prop);
3936  IDP_BlendDataRead(reader, &addon->prop);
3937  }
3938 
3939  /* XXX */
3940  user->uifonts.first = user->uifonts.last = NULL;
3941 
3942  BLO_read_list(reader, &user->uistyles);
3943 
3944  /* Don't read the active app template, use the default one. */
3945  user->app_template[0] = '\0';
3946 
3947  /* Clear runtime data. */
3948  user->runtime.is_dirty = false;
3949  user->edit_studio_light = 0;
3950 
3951  /* free fd->datamap again */
3952  oldnewmap_clear(fd->datamap);
3953 
3954  return bhead;
3955 }
3956 
3959 /* -------------------------------------------------------------------- */
3963 BlendFileData *blo_read_file_internal(FileData *fd, const char *filepath)
3964 {
3965  BHead *bhead = blo_bhead_first(fd);
3966  BlendFileData *bfd;
3967  ListBase mainlist = {NULL, NULL};
3968 
3969  if (fd->flags & FD_FLAGS_IS_MEMFILE) {
3970  CLOG_INFO(&LOG_UNDO, 2, "UNDO: read step");
3971  }
3972 
3973  bfd = MEM_callocN(sizeof(BlendFileData), "blendfiledata");
3974 
3975  bfd->main = BKE_main_new();
3976  bfd->main->versionfile = fd->fileversion;
3977 
3978  bfd->type = BLENFILETYPE_BLEND;
3979 
3980  if ((fd->skip_flags & BLO_READ_SKIP_DATA) == 0) {
3981  BLI_addtail(&mainlist, bfd->main);
3982  fd->mainlist = &mainlist;
3983  STRNCPY(bfd->main->filepath, filepath);
3984  }
3985 
3986  if (G.background) {
3987  /* We only read & store .blend thumbnail in background mode
3988  * (because we cannot re-generate it, no OpenGL available).
3989  */
3990  const int *data = read_file_thumbnail(fd);
3991 
3992  if (data) {
3993  const int width = data[0];
3994  const int height = data[1];
3996  const size_t data_size = BLEN_THUMB_MEMSIZE(width, height);
3997  bfd->main->blen_thumb = MEM_mallocN(data_size, __func__);
3998 
3999  BLI_assert((data_size - sizeof(*bfd->main->blen_thumb)) ==
4000  (BLEN_THUMB_MEMSIZE_FILE(width, height) - (sizeof(*data) * 2)));
4001  bfd->main->blen_thumb->width = width;
4002  bfd->main->blen_thumb->height = height;
4003  memcpy(bfd->main->blen_thumb->rect, &data[2], data_size - sizeof(*bfd->main->blen_thumb));
4004  }
4005  }
4006  }
4007 
4008  while (bhead) {
4009  switch (bhead->code) {
4010  case DATA:
4011  case DNA1:
4012  case TEST: /* used as preview since 2.5x */
4013  case REND:
4014  bhead = blo_bhead_next(fd, bhead);
4015  break;
4016  case GLOB:
4017  bhead = read_global(bfd, fd, bhead);
4018  break;
4019  case USER:
4020  if (fd->skip_flags & BLO_READ_SKIP_USERDEF) {
4021  bhead = blo_bhead_next(fd, bhead);
4022  }
4023  else {
4024  bhead = read_userdef(bfd, fd, bhead);
4025  }
4026  break;
4027  case ENDB:
4028  bhead = NULL;
4029  break;
4030 
4031  case ID_LINK_PLACEHOLDER:
4032  if (fd->skip_flags & BLO_READ_SKIP_DATA) {
4033  bhead = blo_bhead_next(fd, bhead);
4034  }
4035  else {
4036  /* Add link placeholder to the main of the library it belongs to.
4037  * The library is the most recently loaded ID_LI block, according
4038  * to the file format definition. So we can use the entry at the
4039  * end of mainlist, added in direct_link_library. */
4040  Main *libmain = mainlist.last;
4041  bhead = read_libblock(fd, libmain, bhead, 0, true, NULL);
4042  }
4043  break;
4044  /* in 2.50+ files, the file identifier for screens is patched, forward compatibility */
4045  case ID_SCRN:
4046  bhead->code = ID_SCR;
4047  /* pass on to default */
4049  default:
4050  if (fd->skip_flags & BLO_READ_SKIP_DATA) {
4051  bhead = blo_bhead_next(fd, bhead);
4052  }
4053  else {
4054  bhead = read_libblock(fd, bfd->main, bhead, LIB_TAG_LOCAL, false, NULL);
4055  }
4056  }
4057 
4058  if (bfd->main->is_read_invalid) {
4059  return bfd;
4060  }
4061  }
4062 
4063  /* do before read_libraries, but skip undo case */
4064  if ((fd->flags & FD_FLAGS_IS_MEMFILE) == 0) {
4065  if ((fd->skip_flags & BLO_READ_SKIP_DATA) == 0) {
4066  do_versions(fd, NULL, bfd->main);
4067  }
4068 
4069  if ((fd->skip_flags & BLO_READ_SKIP_USERDEF) == 0) {
4070  do_versions_userdef(fd, bfd);
4071  }
4072  }
4073 
4074  if (bfd->main->is_read_invalid) {
4075  return bfd;
4076  }
4077 
4078  if ((fd->skip_flags & BLO_READ_SKIP_DATA) == 0) {
4080  read_libraries(fd, &mainlist);
4081 
4082  blo_join_main(&mainlist);
4083 
4084  lib_link_all(fd, bfd->main);
4086 
4088 
4089  /* Skip in undo case. */
4090  if ((fd->flags & FD_FLAGS_IS_MEMFILE) == 0) {
4091  /* Note that we can't recompute user-counts at this point in undo case, we play too much with
4092  * IDs from different memory realms, and Main database is not in a fully valid state yet.
4093  */
4094  /* Some versioning code does expect some proper user-reference-counting, e.g. in conversion
4095  * from groups to collections... We could optimize out that first call when we are reading a
4096  * current version file, but again this is really not a bottle neck currently.
4097  * So not worth it. */
4098  BKE_main_id_refcount_recompute(bfd->main, false);
4099 
4100  /* Yep, second splitting... but this is a very cheap operation, so no big deal. */
4101  blo_split_main(&mainlist, bfd->main);
4102  LISTBASE_FOREACH (Main *, mainvar, &mainlist) {
4103  BLI_assert(mainvar->versionfile != 0);
4104  do_versions_after_linking(fd, mainvar);
4105  }
4106  blo_join_main(&mainlist);
4107 
4108  /* And we have to compute those user-reference-counts again, as `do_versions_after_linking()`
4109  * does not always properly handle user counts, and/or that function does not take into
4110  * account old, deprecated data. */
4111  BKE_main_id_refcount_recompute(bfd->main, false);
4112  }
4113 
4114  if (bfd->main->is_read_invalid) {
4115  return bfd;
4116  }
4117 
4118  /* After all data has been read and versioned, uses LIB_TAG_NEW. Theoretically this should
4119  * not be calculated in the undo case, but it is currently needed even on undo to recalculate
4120  * a cache. */
4121  ntreeUpdateAllNew(bfd->main);
4122 
4124 
4125  BKE_main_id_tag_all(bfd->main, LIB_TAG_NEW, false);
4126 
4127  /* Now that all our data-blocks are loaded,
4128  * we can re-generate overrides from their references. */
4129  if ((fd->flags & FD_FLAGS_IS_MEMFILE) == 0) {
4130  /* Do not apply in undo case! */
4132 
4135 
4138  }
4139 
4141 
4142  /* Make all relative paths, relative to the open blend file. */
4143  fix_relpaths_library(fd->relabase, bfd->main);
4144 
4145  link_global(fd, bfd); /* as last */
4146  }
4147 
4148  fd->mainlist = NULL; /* Safety, this is local variable, shall not be used afterward. */
4149 
4150  BLI_assert(bfd->main->id_map == NULL);
4151 
4152  return bfd;
4153 }
4154 
4157 /* -------------------------------------------------------------------- */
4163 struct BHeadSort {
4165  const void *old;
4166 };
4167 
4168 static int verg_bheadsort(const void *v1, const void *v2)
4169 {
4170  const struct BHeadSort *x1 = v1, *x2 = v2;
4171 
4172  if (x1->old > x2->old) {
4173  return 1;
4174  }
4175  if (x1->old < x2->old) {
4176  return -1;
4177  }
4178  return 0;
4179 }
4180 
4182 {
4183  BHead *bhead;
4184  struct BHeadSort *bhs;
4185  int tot = 0;
4186 
4187  for (bhead = blo_bhead_first(fd); bhead; bhead = blo_bhead_next(fd, bhead)) {
4188  tot++;
4189  }
4190 
4191  fd->tot_bheadmap = tot;
4192  if (tot == 0) {
4193  return;
4194  }
4195 
4196  bhs = fd->bheadmap = MEM_malloc_arrayN(tot, sizeof(struct BHeadSort), "BHeadSort");
4197 
4198  for (bhead = blo_bhead_first(fd); bhead; bhead = blo_bhead_next(fd, bhead), bhs++) {
4199  bhs->bhead = bhead;
4200  bhs->old = bhead->old;
4201  }
4202 
4203  qsort(fd->bheadmap, tot, sizeof(struct BHeadSort), verg_bheadsort);
4204 }
4205 
4207 {
4208  /* Skip library data-blocks in undo, see comment in read_libblock. */
4209  if (fd->flags & FD_FLAGS_IS_MEMFILE) {
4210  return NULL;
4211  }
4212 
4213  for (; bhead; bhead = blo_bhead_prev(fd, bhead)) {
4214  if (bhead->code == ID_LI) {
4215  break;
4216  }
4217  }
4218 
4219  return bhead;
4220 }
4221 
4222 static BHead *find_bhead(FileData *fd, void *old)
4223 {
4224 #if 0
4225  BHead* bhead;
4226 #endif
4227  struct BHeadSort *bhs, bhs_s;
4228 
4229  if (!old) {
4230  return NULL;
4231  }
4232 
4233  if (fd->bheadmap == NULL) {
4234  sort_bhead_old_map(fd);
4235  }
4236 
4237  bhs_s.old = old;
4238  bhs = bsearch(&bhs_s, fd->bheadmap, fd->tot_bheadmap, sizeof(struct BHeadSort), verg_bheadsort);
4239 
4240  if (bhs) {
4241  return bhs->bhead;
4242  }
4243 
4244 #if 0
4245  for (bhead = blo_bhead_first(fd); bhead; bhead = blo_bhead_next(fd, bhead)) {
4246  if (bhead->old == old) {
4247  return bhead;
4248  }
4249  }
4250 #endif
4251 
4252  return NULL;
4253 }
4254 
4255 static BHead *find_bhead_from_code_name(FileData *fd, const short idcode, const char *name)
4256 {
4257 #ifdef USE_GHASH_BHEAD
4258 
4259  char idname_full[MAX_ID_NAME];
4260 
4261  *((short *)idname_full) = idcode;
4262  BLI_strncpy(idname_full + 2, name, sizeof(idname_full) - 2);
4263 
4264  return BLI_ghash_lookup(fd->bhead_idname_hash, idname_full);
4265 
4266 #else
4267  BHead *bhead;
4268 
4269  for (bhead = blo_bhead_first(fd); bhead; bhead = blo_bhead_next(fd, bhead)) {
4270  if (bhead->code == idcode) {
4271  const char *idname_test = blo_bhead_id_name(fd, bhead);
4272  if (STREQ(idname_test + 2, name)) {
4273  return bhead;
4274  }
4275  }
4276  else if (bhead->code == ENDB) {
4277  break;
4278  }
4279  }
4280 
4281  return NULL;
4282 #endif
4283 }
4284 
4285 static BHead *find_bhead_from_idname(FileData *fd, const char *idname)
4286 {
4287 #ifdef USE_GHASH_BHEAD
4288  return BLI_ghash_lookup(fd->bhead_idname_hash, idname);
4289 #else
4290  return find_bhead_from_code_name(fd, GS(idname), idname + 2);
4291 #endif
4292 }
4293 
4294 static ID *is_yet_read(FileData *fd, Main *mainvar, BHead *bhead)
4295 {
4296  if (mainvar->id_map == NULL) {
4297  mainvar->id_map = BKE_main_idmap_create(mainvar, false, NULL, MAIN_IDMAP_TYPE_NAME);
4298  }
4299  BLI_assert(BKE_main_idmap_main_get(mainvar->id_map) == mainvar);
4300 
4301  const char *idname = blo_bhead_id_name(fd, bhead);
4302 
4303  ID *id = BKE_main_idmap_lookup_name(mainvar->id_map, GS(idname), idname + 2, mainvar->curlib);
4304  BLI_assert(id == BLI_findstring(which_libbase(mainvar, GS(idname)), idname, offsetof(ID, name)));
4305  return id;
4306 }
4307 
4310 /* -------------------------------------------------------------------- */
4314 static void expand_doit_library(void *fdhandle, Main *mainvar, void *old)
4315 {
4316  FileData *fd = fdhandle;
4317 
4318  BHead *bhead = find_bhead(fd, old);
4319  if (bhead == NULL) {
4320  return;
4321  }
4322 
4323  if (bhead->code == ID_LINK_PLACEHOLDER) {
4324  /* Placeholder link to data-block in another library. */
4325  BHead *bheadlib = find_previous_lib(fd, bhead);
4326  if (bheadlib == NULL) {
4327  return;
4328  }
4329 
4330  Library *lib = read_struct(fd, bheadlib, "Library");
4331  Main *libmain = blo_find_main(fd, lib->filepath, fd->relabase);
4332 
4333  if (libmain->curlib == NULL) {
4334  const char *idname = blo_bhead_id_name(fd, bhead);
4335 
4337  RPT_WARNING,
4338  TIP_("LIB: Data refers to main .blend file: '%s' from %s"),
4339  idname,
4340  mainvar->curlib->filepath_abs);
4341  return;
4342  }
4343 
4344  ID *id = is_yet_read(fd, libmain, bhead);
4345 
4346  if (id == NULL) {
4347  /* ID has not been read yet, add placeholder to the main of the
4348  * library it belongs to, so that it will be read later. */
4349  read_libblock(fd, libmain, bhead, fd->id_tag_extra | LIB_TAG_INDIRECT, false, &id);
4350  BLI_assert(id != NULL);
4351  id_sort_by_name(which_libbase(libmain, GS(id->name)), id, id->prev);
4352 
4353  /* commented because this can print way too much */
4354  // if (G.debug & G_DEBUG) printf("expand_doit: other lib %s\n", lib->filepath);
4355 
4356  /* for outliner dependency only */
4357  libmain->curlib->parent = mainvar->curlib;
4358  }
4359  else {
4360  /* Convert any previously read weak link to regular link
4361  * to signal that we want to read this data-block. */
4363  id->flag &= ~LIB_INDIRECT_WEAK_LINK;
4364  }
4365 
4366  /* "id" is either a placeholder or real ID that is already in the
4367  * main of the library (A) it belongs to. However it might have been
4368  * put there by another library (C) which only updated its own
4369  * fd->libmap. In that case we also need to update the fd->libmap
4370  * of the current library (B) so we can find it for lookups.
4371  *
4372  * An example of such a setup is:
4373  * (A) tree.blend: contains Tree object.
4374  * (B) forest.blend: contains Forest collection linking in Tree from tree.blend.
4375  * (C) shot.blend: links in both Tree from tree.blend and Forest from forest.blend.
4376  */
4377  oldnewmap_lib_insert(fd, bhead->old, id, bhead->code);
4378 
4379  /* If "id" is a real data-block and not a placeholder, we need to
4380  * update fd->libmap to replace ID_LINK_PLACEHOLDER with the real
4381  * ID_* code.
4382  *
4383  * When the real ID is read this replacement happens for all
4384  * libraries read so far, but not for libraries that have not been
4385  * read yet at that point. */
4387 
4388  /* Commented because this can print way too much. */
4389 #if 0
4390  if (G.debug & G_DEBUG) {
4391  printf("expand_doit: already linked: %s lib: %s\n", id->name, lib->filepath);
4392  }
4393 #endif
4394  }
4395 
4396  MEM_freeN(lib);
4397  }
4398  else {
4399  /* Data-block in same library. */
4400  /* In 2.50+ file identifier for screens is patched, forward compatibility. */
4401  if (bhead->code == ID_SCRN) {
4402  bhead->code = ID_SCR;
4403  }
4404 
4405  ID *id = is_yet_read(fd, mainvar, bhead);
4406  if (id == NULL) {
4407  read_libblock(fd,
4408  mainvar,
4409  bhead,
4411  false,
4412  &id);
4413  BLI_assert(id != NULL);
4414  id_sort_by_name(which_libbase(mainvar, GS(id->name)), id, id->prev);
4415  }
4416  else {
4417  /* Convert any previously read weak link to regular link
4418  * to signal that we want to read this data-block. */
4420  id->flag &= ~LIB_INDIRECT_WEAK_LINK;
4421  }
4422 
4423  /* this is actually only needed on UI call? when ID was already read before,
4424  * and another append happens which invokes same ID...
4425  * in that case the lookup table needs this entry */
4426  oldnewmap_lib_insert(fd, bhead->old, id, bhead->code);
4427  /* commented because this can print way too much */
4428  // if (G.debug & G_DEBUG) printf("expand: already read %s\n", id->name);
4429  }
4430  }
4431 }
4432 
4434 
4435 static void expand_id(BlendExpander *expander, ID *id);
4436 
4437 static void expand_id_embedded_id(BlendExpander *expander, ID *id)
4438 {
4439  /* Handle 'private IDs'. */
4440  bNodeTree *nodetree = ntreeFromID(id);
4441  if (nodetree != NULL) {
4442  expand_id(expander, &nodetree->id);
4443  ntreeBlendReadExpand(expander, nodetree);
4444  }
4445 
4446  if (GS(id->name) == ID_SCE) {
4447  Scene *scene = (Scene *)id;
4448  if (scene->master_collection != NULL) {
4449  expand_id(expander, &scene->master_collection->id);
4451  }
4452  }
4453 }
4454 
4455 static void expand_id(BlendExpander *expander, ID *id)
4456 {
4457  IDP_BlendReadExpand(expander, id->properties);
4458 
4459  if (id->override_library) {
4460  BLO_expand(expander, id->override_library->reference);
4461  BLO_expand(expander, id->override_library->storage);
4462  }
4463 
4464  AnimData *adt = BKE_animdata_from_id(id);
4465  if (adt != NULL) {
4466  BKE_animdata_blend_read_expand(expander, adt);
4467  }
4468 
4469  expand_id_embedded_id(expander, id);
4470 }
4471 
4473 {
4474  expand_doit = expand_doit_func;
4475 }
4476 
4477 void BLO_expand_main(void *fdhandle, Main *mainvar)
4478 {
4479  ListBase *lbarray[INDEX_ID_MAX];
4480  FileData *fd = fdhandle;
4481  ID *id;
4482  int a;
4483  bool do_it = true;
4484 
4485  BlendExpander expander = {fd, mainvar};
4486 
4487  while (do_it) {
4488  do_it = false;
4489 
4490  a = set_listbasepointers(mainvar, lbarray);
4491  while (a--) {
4492  id = lbarray[a]->first;
4493  while (id) {
4494  if (id->tag & LIB_TAG_NEED_EXPAND) {
4495  expand_id(&expander, id);
4496 
4497  const IDTypeInfo *id_type = BKE_idtype_get_info_from_id(id);
4498  if (id_type->blend_read_expand != NULL) {
4499  id_type->blend_read_expand(&expander, id);
4500  }
4501 
4502  do_it = true;
4503  id->tag &= ~LIB_TAG_NEED_EXPAND;
4504  }
4505  id = id->next;
4506  }
4507  }
4508  }
4509 }
4510 
4513 /* -------------------------------------------------------------------- */
4517 /* returns true if the item was found
4518  * but it may already have already been appended/linked */
4520  Main *mainl, FileData *fd, const short idcode, const char *name, const int flag)
4521 {
4522  BHead *bhead = find_bhead_from_code_name(fd, idcode, name);
4523  ID *id;
4524 
4525  const bool use_placeholders = (flag & BLO_LIBLINK_USE_PLACEHOLDERS) != 0;
4526  const bool force_indirect = (flag & BLO_LIBLINK_FORCE_INDIRECT) != 0;
4527 
4529 
4530  if (bhead) {
4531  id = is_yet_read(fd, mainl, bhead);
4532  if (id == NULL) {
4533  /* not read yet */
4534  const int tag = ((force_indirect ? LIB_TAG_INDIRECT : LIB_TAG_EXTERN) | fd->id_tag_extra);
4535  read_libblock(fd, mainl, bhead, tag | LIB_TAG_NEED_EXPAND, false, &id);
4536 
4537  if (id) {
4538  /* sort by name in list */
4539  ListBase *lb = which_libbase(mainl, idcode);
4540  id_sort_by_name(lb, id, NULL);
4541  }
4542  }
4543  else {
4544  /* already linked */
4545  CLOG_WARN(&LOG, "Append: ID '%s' is already linked", id->name);
4546  oldnewmap_lib_insert(fd, bhead->old, id, bhead->code);
4547  if (!force_indirect && (id->tag & LIB_TAG_INDIRECT)) {
4548  id->tag &= ~LIB_TAG_INDIRECT;
4549  id->flag &= ~LIB_INDIRECT_WEAK_LINK;
4550  id->tag |= LIB_TAG_EXTERN;
4551  }
4552  }
4553  }
4554  else if (use_placeholders) {
4555  /* XXX flag part is weak! */
4556  id = create_placeholder(
4557  mainl, idcode, name, force_indirect ? LIB_TAG_INDIRECT : LIB_TAG_EXTERN);
4558  }
4559  else {
4560  id = NULL;
4561  }
4562 
4563  /* if we found the id but the id is NULL, this is really bad */
4564  BLI_assert(!((bhead != NULL) && (id == NULL)));
4565 
4566  return id;
4567 }
4568 
4570  BlendHandle **bh,
4571  const short idcode,
4572  const char *name,
4573  const struct LibraryLink_Params *params)
4574 {
4575  FileData *fd = (FileData *)(*bh);
4576 
4577  ID *ret_id = NULL;
4578  if (!mainl->is_read_invalid) {
4579  ret_id = link_named_part(mainl, fd, idcode, name, params->flag);
4580  }
4581 
4582  if (mainl->is_read_invalid) {
4583  return NULL;
4584  }
4585  return ret_id;
4586 }
4587 
4588 /* common routine to append/link something from a library */
4589 
4590 static Main *library_link_begin(Main *mainvar,
4591  FileData **fd,
4592  const char *filepath,
4593  const int id_tag_extra)
4594 {
4595  Main *mainl;
4596 
4597  /* Only allow specific tags to be set as extra,
4598  * otherwise this could conflict with library loading logic.
4599  * Other flags can be added here, as long as they are safe. */
4600  BLI_assert((id_tag_extra & ~LIB_TAG_TEMP_MAIN) == 0);
4601 
4602  (*fd)->id_tag_extra = id_tag_extra;
4603 
4604  (*fd)->mainlist = MEM_callocN(sizeof(ListBase), "FileData.mainlist");
4605 
4606  /* make mains */
4607  blo_split_main((*fd)->mainlist, mainvar);
4608 
4609  /* which one do we need? */
4610  mainl = blo_find_main(*fd, filepath, BKE_main_blendfile_path(mainvar));
4611 
4612  /* needed for do_version */
4613  mainl->versionfile = (*fd)->fileversion;
4614  read_file_version(*fd, mainl);
4615 #ifdef USE_GHASH_BHEAD
4617 #endif
4618 
4619  return mainl;
4620 }
4621 
4623  struct Main *bmain,
4624  const int flag,
4625  const int id_tag_extra)
4626 {
4627  memset(params, 0, sizeof(*params));
4628  params->bmain = bmain;
4629  params->flag = flag;
4630  params->id_tag_extra = id_tag_extra;
4631 }
4632 
4634  struct Main *bmain,
4635  const int flag,
4636  const int id_tag_extra,
4637  /* Context arguments. */
4638  struct Scene *scene,
4639  struct ViewLayer *view_layer,
4640  const struct View3D *v3d)
4641 {
4642  BLO_library_link_params_init(params, bmain, flag, id_tag_extra);
4643  if (scene != NULL) {
4644  params->context.scene = scene;
4645  params->context.view_layer = view_layer;
4646  params->context.v3d = v3d;
4647  }
4648 }
4649 
4651  const char *filepath,
4652  const struct LibraryLink_Params *params)
4653 {
4654  FileData *fd = (FileData *)(*bh);
4655  return library_link_begin(params->bmain, &fd, filepath, params->id_tag_extra);
4656 }
4657 
4658 static void split_main_newid(Main *mainptr, Main *main_newid)
4659 {
4660  /* We only copy the necessary subset of data in this temp main. */
4661  main_newid->versionfile = mainptr->versionfile;
4662  main_newid->subversionfile = mainptr->subversionfile;
4663  STRNCPY(main_newid->filepath, mainptr->filepath);
4664  main_newid->curlib = mainptr->curlib;
4665 
4666  ListBase *lbarray[INDEX_ID_MAX];
4667  ListBase *lbarray_newid[INDEX_ID_MAX];
4668  int i = set_listbasepointers(mainptr, lbarray);
4669  set_listbasepointers(main_newid, lbarray_newid);
4670  while (i--) {
4671  BLI_listbase_clear(lbarray_newid[i]);
4672 
4673  LISTBASE_FOREACH_MUTABLE (ID *, id, lbarray[i]) {
4674  if (id->tag & LIB_TAG_NEW) {
4675  BLI_remlink(lbarray[i], id);
4676  BLI_addtail(lbarray_newid[i], id);
4677  }
4678  }
4679  }
4680 }
4681 
4682 static void library_link_end(Main *mainl, FileData **fd, const int flag)
4683 {
4684  Main *mainvar;
4685  Library *curlib;
4686 
4687  if (mainl->id_map == NULL) {
4688  mainl->id_map = BKE_main_idmap_create(mainl, false, NULL, MAIN_IDMAP_TYPE_NAME);
4689  }
4690 
4691  /* expander now is callback function */
4693 
4694  /* make main consistent */
4695  BLO_expand_main(*fd, mainl);
4696 
4697  /* do this when expand found other libs */
4698  read_libraries(*fd, (*fd)->mainlist);
4699 
4700  curlib = mainl->curlib;
4701 
4702  /* make the lib path relative if required */
4703  if (flag & FILE_RELPATH) {
4704  /* use the full path, this could have been read by other library even */
4705  BLI_strncpy(curlib->filepath, curlib->filepath_abs, sizeof(curlib->filepath));
4706 
4707  /* uses current .blend file as reference */
4709  }
4710 
4711  blo_join_main((*fd)->mainlist);
4712  mainvar = (*fd)->mainlist->first;
4713  mainl = NULL; /* blo_join_main free's mainl, can't use anymore */
4714 
4715  if (mainvar->is_read_invalid) {
4716  return;
4717  }
4718 
4719  lib_link_all(*fd, mainvar);
4721 
4722  /* Some versioning code does expect some proper userrefcounting, e.g. in conversion from
4723  * groups to collections... We could optimize out that first call when we are reading a
4724  * current version file, but again this is really not a bottle neck currently. so not worth
4725  * it. */
4726  BKE_main_id_refcount_recompute(mainvar, false);
4727 
4729 
4730  /* Yep, second splitting... but this is a very cheap operation, so no big deal. */
4731  blo_split_main((*fd)->mainlist, mainvar);
4732  Main *main_newid = BKE_main_new();
4733  for (mainvar = ((Main *)(*fd)->mainlist->first)->next; mainvar; mainvar = mainvar->next) {
4734  BLI_assert(mainvar->versionfile != 0);
4735  /* We need to split out IDs already existing,
4736  * or they will go again through do_versions - bad, very bad! */
4737  split_main_newid(mainvar, main_newid);
4738 
4739  do_versions_after_linking(*fd, main_newid);
4740 
4741  add_main_to_main(mainvar, main_newid);
4742 
4743  if (mainvar->is_read_invalid) {
4744  break;
4745  }
4746  }
4747 
4748  blo_join_main((*fd)->mainlist);
4749  mainvar = (*fd)->mainlist->first;
4750  MEM_freeN((*fd)->mainlist);
4751 
4752  if (mainvar->is_read_invalid) {
4753  BKE_main_free(main_newid);
4754  return;
4755  }
4756 
4757  /* This does not take into account old, deprecated data, so we also have to do it after
4758  * `do_versions_after_linking()`. */
4759  BKE_main_id_refcount_recompute(mainvar, false);
4760 
4761  /* After all data has been read and versioned, uses LIB_TAG_NEW. */
4762  ntreeUpdateAllNew(mainvar);
4763 
4764  placeholders_ensure_valid(mainvar);
4765 
4766  /* Apply overrides of newly linked data if needed. Already existing IDs need to split out, to
4767  * avoid re-applying their own overrides. */
4768  BLI_assert(BKE_main_is_empty(main_newid));
4769  split_main_newid(mainvar, main_newid);
4770  BKE_lib_override_library_main_validate(main_newid, (*fd)->reports->reports);
4772  add_main_to_main(mainvar, main_newid);
4773  BKE_main_free(main_newid);
4774 
4775  BKE_main_id_tag_all(mainvar, LIB_TAG_NEW, false);
4776 
4777  /* Make all relative paths, relative to the open blend file. */
4778  fix_relpaths_library(BKE_main_blendfile_path(mainvar), mainvar);
4779 
4780  /* patch to prevent switch_endian happens twice */
4781  if ((*fd)->flags & FD_FLAGS_SWITCH_ENDIAN) {
4782  blo_filedata_free(*fd);
4783  *fd = NULL;
4784  }
4785 }
4786 
4788 {
4789  FileData *fd = (FileData *)(*bh);
4790  if (!mainl->is_read_invalid) {
4791  library_link_end(mainl, &fd, params->flag);
4792  *bh = (BlendHandle *)fd;
4793  }
4794 }
4795 
4796 void *BLO_library_read_struct(FileData *fd, BHead *bh, const char *blockname)
4797 {
4798  return read_struct(fd, bh, blockname);
4799 }
4800 
4803 /* -------------------------------------------------------------------- */
4807 static int has_linked_ids_to_read(Main *mainvar)
4808 {
4809  ListBase *lbarray[INDEX_ID_MAX];
4810  int a = set_listbasepointers(mainvar, lbarray);
4811 
4812  while (a--) {
4813  LISTBASE_FOREACH (ID *, id, lbarray[a]) {
4815  return true;
4816  }
4817  }
4818  }
4819 
4820  return false;
4821 }
4822 
4824  FileData *basefd, FileData *fd, Main *mainvar, ID *id, ID **r_id)
4825 {
4826  BHead *bhead = NULL;
4827  const bool is_valid = BKE_idtype_idcode_is_linkable(GS(id->name)) ||
4828  ((id->tag & LIB_TAG_EXTERN) == 0);
4829 
4830  if (fd) {
4832  }
4833 
4834  if (!is_valid) {
4835  BLO_reportf_wrap(basefd->reports,
4836  RPT_ERROR,
4837  TIP_("LIB: %s: '%s' is directly linked from '%s' (parent '%s'), but is a "
4838  "non-linkable data type"),
4840  id->name + 2,
4841  mainvar->curlib->filepath_abs,
4842  library_parent_filepath(mainvar->curlib));
4843  }
4844 
4845  id->tag &= ~LIB_TAG_ID_LINK_PLACEHOLDER;
4846  id->flag &= ~LIB_INDIRECT_WEAK_LINK;
4847 
4848  if (bhead) {
4849  id->tag |= LIB_TAG_NEED_EXPAND;
4850  // printf("read lib block %s\n", id->name);
4851  read_libblock(fd, mainvar, bhead, id->tag, false, r_id);
4852  }
4853  else {
4854  BLO_reportf_wrap(basefd->reports,
4855  RPT_INFO,
4856  TIP_("LIB: %s: '%s' missing from '%s', parent '%s'"),
4858  id->name + 2,
4859  mainvar->curlib->filepath_abs,
4860  library_parent_filepath(mainvar->curlib));
4861  basefd->reports->count.missing_linked_id++;
4862 
4863  /* Generate a placeholder for this ID (simplified version of read_libblock actually...). */
4864  if (r_id) {
4865  *r_id = is_valid ? create_placeholder(mainvar, GS(id->name), id->name + 2, id->tag) : NULL;
4866  }
4867  }
4868 }
4869 
4870 static void read_library_linked_ids(FileData *basefd,
4871  FileData *fd,
4872  ListBase *mainlist,
4873  Main *mainvar)
4874 {
4875  GHash *loaded_ids = BLI_ghash_str_new(__func__);
4876 
4877  ListBase *lbarray[INDEX_ID_MAX];
4878  int a = set_listbasepointers(mainvar, lbarray);
4879 
4880  while (a--) {
4881  ID *id = lbarray[a]->first;
4882  ListBase pending_free_ids = {NULL};
4883 
4884  while (id) {
4885  ID *id_next = id->next;
4887  BLI_remlink(lbarray[a], id);
4888  if (mainvar->id_map != NULL) {
4889  BKE_main_idmap_remove_id(mainvar->id_map, id);
4890  }
4891 
4892  /* When playing with lib renaming and such, you may end with cases where
4893  * you have more than one linked ID of the same data-block from same
4894  * library. This is absolutely horrible, hence we use a ghash to ensure
4895  * we go back to a single linked data when loading the file. */
4896  ID **realid = NULL;
4897  if (!BLI_ghash_ensure_p(loaded_ids, id->name, (void ***)&realid)) {
4898  read_library_linked_id(basefd, fd, mainvar, id, realid);
4899  }
4900 
4901  /* `realid` shall never be NULL - unless some source file/lib is broken
4902  * (known case: some directly linked shapekey from a missing lib...). */
4903  // BLI_assert(*realid != NULL);
4904 
4905  /* Now that we have a real ID, replace all pointers to placeholders in
4906  * fd->libmap with pointers to the real data-blocks. We do this for all
4907  * libraries since multiple might be referencing this ID. */
4908  change_link_placeholder_to_real_ID_pointer(mainlist, basefd, id, *realid);
4909 
4910  /* We cannot free old lib-ref placeholder ID here anymore, since we use
4911  * its name as key in loaded_ids hash. */
4912  BLI_addtail(&pending_free_ids, id);
4913  }
4914  id = id_next;
4915  }
4916 
4917  /* Clear GHash and free link placeholder IDs of the current type. */
4918  BLI_ghash_clear(loaded_ids, NULL, NULL);
4919  BLI_freelistN(&pending_free_ids);
4920  }
4921 
4922  BLI_ghash_free(loaded_ids, NULL, NULL);
4923 }
4924 
4925 static void read_library_clear_weak_links(FileData *basefd, ListBase *mainlist, Main *mainvar)
4926 {
4927  /* Any remaining weak links at this point have been lost, silently drop
4928  * those by setting them to NULL pointers. */
4929  ListBase *lbarray[INDEX_ID_MAX];
4930  int a = set_listbasepointers(mainvar, lbarray);
4931 
4932  while (a--) {
4933  ID *id = lbarray[a]->first;
4934 
4935  while (id) {
4936  ID *id_next = id->next;
4938  CLOG_INFO(&LOG, 3, "Dropping weak link to '%s'", id->name);
4939  change_link_placeholder_to_real_ID_pointer(mainlist, basefd, id, NULL);
4940  BLI_freelinkN(lbarray[a], id);
4941  }
4942  id = id_next;
4943  }
4944  }
4945 }
4946 
4948  ListBase *mainlist,
4949  Main *mainl,
4950  Main *mainptr)
4951 {
4952  FileData *fd = mainptr->curlib->filedata;
4953 
4954  if (fd != NULL) {
4955  /* File already open. */
4956  return fd;
4957  }
4958 
4959  if (mainptr->curlib->packedfile) {
4960  /* Read packed file. */
4961  PackedFile *pf = mainptr->curlib->packedfile;
4962 
4963  BLO_reportf_wrap(basefd->reports,
4964  RPT_INFO,
4965  TIP_("Read packed library: '%s', parent '%s'"),
4966  mainptr->curlib->filepath,
4967  library_parent_filepath(mainptr->curlib));
4968  fd = blo_filedata_from_memory(pf->data, pf->size, basefd->reports);
4969 
4970  /* Needed for library_append and read_libraries. */
4971  BLI_strncpy(fd->relabase, mainptr->curlib->filepath_abs, sizeof(fd->relabase));
4972  }
4973  else {
4974  /* Read file on disk. */
4975  BLO_reportf_wrap(basefd->reports,
4976  RPT_INFO,
4977  TIP_("Read library: '%s', '%s', parent '%s'"),
4978  mainptr->curlib->filepath_abs,
4979  mainptr->curlib->filepath,
4980  library_parent_filepath(mainptr->curlib));
4981  fd = blo_filedata_from_file(mainptr->curlib->filepath_abs, basefd->reports);
4982  }
4983 
4984  if (fd) {
4985  /* Share the mainlist, so all libraries are added immediately in a
4986  * single list. It used to be that all FileData's had their own list,
4987  * but with indirectly linking this meant we didn't catch duplicate
4988  * libraries properly. */
4989  fd->mainlist = mainlist;
4990 
4991  fd->reports = basefd->reports;
4992 
4993  if (fd->libmap) {
4994  oldnewmap_free(fd->libmap);
4995  }
4996 
4997  fd->libmap = oldnewmap_new();
4998 
4999  mainptr->curlib->filedata = fd;
5000  mainptr->versionfile = fd->fileversion;
5001 
5002  /* subversion */
5003  read_file_version(fd, mainptr);
5004 #ifdef USE_GHASH_BHEAD
5006 #endif
5007  }
5008  else {
5009  mainptr->curlib->filedata = NULL;
5010  mainptr->curlib->id.tag |= LIB_TAG_MISSING;
5011  /* Set lib version to current main one... Makes assert later happy. */
5012  mainptr->versionfile = mainptr->curlib->versionfile = mainl->versionfile;
5013  mainptr->subversionfile = mainptr->curlib->subversionfile = mainl->subversionfile;
5014  }
5015 
5016  if (fd == NULL) {
5018  basefd->reports, RPT_INFO, TIP_("Cannot find lib '%s'"), mainptr->curlib->filepath_abs);
5019  basefd->reports->count.missing_libraries++;
5020  }
5021 
5022  return fd;
5023 }
5024 
5025 static void read_libraries(FileData *basefd, ListBase *mainlist)
5026 {
5027  Main *mainl = mainlist->first;
5028  bool do_it = true;
5029 
5030  /* Expander is now callback function. */
5032 
5033  /* At this point the base blend file has been read, and each library blend
5034  * encountered so far has a main with placeholders for linked data-blocks.
5035  *
5036  * Now we will read the library blend files and replace the placeholders
5037  * with actual data-blocks. We loop over library mains multiple times in
5038  * case a library needs to link additional data-blocks from another library
5039  * that had been read previously. */
5040  while (do_it) {
5041  do_it = false;
5042 
5043  /* Loop over mains of all library blend files encountered so far. Note
5044  * this list gets longer as more indirectly library blends are found. */
5045  for (Main *mainptr = mainl->next; mainptr; mainptr = mainptr->next) {
5046  /* Does this library have any more linked data-blocks we need to read? */
5047  if (has_linked_ids_to_read(mainptr)) {
5048  CLOG_INFO(&LOG,
5049  3,
5050  "Reading linked data-blocks from %s (%s)",
5051  mainptr->curlib->id.name,
5052  mainptr->curlib->filepath);
5053 
5054  /* Open file if it has not been done yet. */
5055  FileData *fd = read_library_file_data(basefd, mainlist, mainl, mainptr);
5056 
5057  if (fd) {
5058  do_it = true;
5059 
5060  if (mainptr->id_map == NULL) {
5061  mainptr->id_map = BKE_main_idmap_create(mainptr, false, NULL, MAIN_IDMAP_TYPE_NAME);
5062  }
5063  }
5064 
5065  /* Read linked data-blocks for each link placeholder, and replace
5066  * the placeholder with the real data-block. */
5067  read_library_linked_ids(basefd, fd, mainlist, mainptr);
5068 
5069  /* Test if linked data-blocks need to read further linked data-blocks
5070  * and create link placeholders for them. */
5071  BLO_expand_main(fd, mainptr);
5072  }
5073  }
5074  }
5075 
5076  for (Main *mainptr = mainl->next; mainptr; mainptr = mainptr->next) {
5077  /* Drop weak links for which no data-block was found.
5078  * Since this can remap pointers in `libmap` of all libraries, it needs to be performed in its
5079  * own loop, before any call to `lib_link_all` (and the freeing of the libraries' filedata). */
5080  read_library_clear_weak_links(basefd, mainlist, mainptr);
5081  }
5082 
5083  Main *main_newid = BKE_main_new();
5084  for (Main *mainptr = mainl->next; mainptr; mainptr = mainptr->next) {
5085  /* Do versioning for newly added linked data-blocks. If no data-blocks
5086  * were read from a library versionfile will still be zero and we can
5087  * skip it. */
5088  if (mainptr->versionfile) {
5089  /* Split out already existing IDs to avoid them going through
5090  * do_versions multiple times, which would have bad consequences. */
5091  split_main_newid(mainptr, main_newid);
5092 
5093  /* File data can be zero with link/append. */
5094  if (mainptr->curlib->filedata) {
5095  do_versions(mainptr->curlib->filedata, mainptr->curlib, main_newid);
5096  }
5097  else {
5098  do_versions(basefd, NULL, main_newid);
5099  }
5100 
5101  add_main_to_main(mainptr, main_newid);
5102  }
5103 
5104  /* Lib linking. */
5105  if (mainptr->curlib->filedata) {
5106  lib_link_all(mainptr->curlib->filedata, mainptr);
5107  }
5108 
5109  /* NOTE: No need to call #do_versions_after_linking() or #BKE_main_id_refcount_recompute()
5110  * here, as this function is only called for library 'subset' data handling, as part of
5111  * either full blendfile reading (#blo_read_file_internal()), or library-data linking
5112  * (#library_link_end()). */
5113 
5114  /* Free file data we no longer need. */
5115  if (mainptr->curlib->filedata) {
5116  blo_filedata_free(mainptr->curlib->filedata);
5117  }
5118  mainptr->curlib->filedata = NULL;
5119  }
5120  BKE_main_free(main_newid);
5121 }
5122 
5123 void *BLO_read_get_new_data_address(BlendDataReader *reader, const void *old_address)
5124 {
5125  return newdataadr(reader->fd, old_address);
5126 }
5127 
5128 void *BLO_read_get_new_data_address_no_us(BlendDataReader *reader, const void *old_address)
5129 {
5130  return newdataadr_no_us(reader->fd, old_address);
5131 }
5132 
5133 void *BLO_read_get_new_packed_address(BlendDataReader *reader, const void *old_address)
5134 {
5135  return newpackedadr(reader->fd, old_address);
5136 }
5137 
5139 {
5140  return newlibadr(reader->fd, lib, id);
5141 }
5142 
5144 {
5145  return (reader->fd->flags & FD_FLAGS_SWITCH_ENDIAN) != 0;
5146 }
5147 
5149 {
5150  if (BLI_listbase_is_empty(list)) {
5151  return;
5152  }
5153 
5154  BLO_read_data_address(reader, &list->first);
5155  if (callback != NULL) {
5156  callback(reader, list->first);
5157  }
5158  Link *ln = list->first;
5159  Link *prev = NULL;
5160  while (ln) {
5161  BLO_read_data_address(reader, &ln->next);
5162  if (ln->next != NULL && callback != NULL) {
5163  callback(reader, ln->next);
5164  }
5165  ln->prev = prev;
5166  prev = ln;
5167  ln = ln->next;
5168  }
5169  list->last = prev;
5170 }
5171 
5172 void BLO_read_list(BlendDataReader *reader, struct ListBase *list)
5173 {
5174  BLO_read_list_cb(reader, list, NULL);
5175 }
5176 
5177 void BLO_read_int32_array(BlendDataReader *reader, int array_size, int32_t **ptr_p)
5178 {
5179  BLO_read_data_address(reader, ptr_p);
5180  if (BLO_read_requires_endian_switch(reader)) {
5181  BLI_endian_switch_int32_array(*ptr_p, array_size);
5182  }
5183 }
5184 
5185 void BLO_read_uint32_array(BlendDataReader *reader, int array_size, uint32_t **ptr_p)
5186 {
5187  BLO_read_data_address(reader, ptr_p);
5188  if (BLO_read_requires_endian_switch(reader)) {
5189  BLI_endian_switch_uint32_array(*ptr_p, array_size);
5190  }
5191 }
5192 
5193 void BLO_read_float_array(BlendDataReader *reader, int array_size, float **ptr_p)
5194 {
5195  BLO_read_data_address(reader, ptr_p);
5196  if (BLO_read_requires_endian_switch(reader)) {
5197  BLI_endian_switch_float_array(*ptr_p, array_size);
5198  }
5199 }
5200 
5201 void BLO_read_float3_array(BlendDataReader *reader, int array_size, float **ptr_p)
5202 {
5203  BLO_read_float_array(reader, array_size * 3, ptr_p);
5204 }
5205 
5206 void BLO_read_double_array(BlendDataReader *reader, int array_size, double **ptr_p)
5207 {
5208  BLO_read_data_address(reader, ptr_p);
5209  if (BLO_read_requires_endian_switch(reader)) {
5210  BLI_endian_switch_double_array(*ptr_p, array_size);
5211  }
5212 }
5213 
5215  uint array_size,
5216  const uint64_t *src,
5217  uint32_t *dst)
5218 {
5219  /* Match pointer conversion rules from bh4_from_bh8 and cast_pointer. */
5220  if (BLO_read_requires_endian_switch(reader)) {
5221  for (int i = 0; i < array_size; i++) {
5222  uint64_t ptr = src[i];
5224  dst[i] = (uint32_t)(ptr >> 3);
5225  }
5226  }
5227  else {
5228  for (int i = 0; i < array_size; i++) {
5229  dst[i] = (uint32_t)(src[i] >> 3);
5230  }
5231  }
5232 }
5233 
5235  uint array_size,
5236  const uint32_t *src,
5237  uint64_t *dst)
5238 {
5239  /* Match pointer conversion rules from bh8_from_bh4 and cast_pointer_32_to_64. */
5240  for (int i = 0; i < array_size; i++) {
5241  dst[i] = src[i];
5242  }
5243 }
5244 
5245 void BLO_read_pointer_array(BlendDataReader *reader, void **ptr_p)
5246 {
5247  FileData *fd = reader->fd;
5248 
5249  void *orig_array = newdataadr(fd, *ptr_p);
5250  if (orig_array == NULL) {
5251  *ptr_p = NULL;
5252  return;
5253  }
5254 
5255  int file_pointer_size = fd->filesdna->pointer_size;
5256  int current_pointer_size = fd->memsdna->pointer_size;
5257 
5258  /* Over-allocation is fine, but might be better to pass the length as parameter. */
5259  int array_size = MEM_allocN_len(orig_array) / file_pointer_size;
5260 
5261  void *final_array = NULL;
5262 
5263  if (file_pointer_size == current_pointer_size) {
5264  /* No pointer conversion necessary. */
5265  final_array = orig_array;
5266  }
5267  else if (file_pointer_size == 8 && current_pointer_size == 4) {
5268  /* Convert pointers from 64 to 32 bit. */
5269  final_array = MEM_malloc_arrayN(array_size, 4, "new pointer array");
5271  reader, array_size, (uint64_t *)orig_array, (uint32_t *)final_array);
5272  MEM_freeN(orig_array);
5273  }
5274  else if (file_pointer_size == 4 && current_pointer_size == 8) {
5275  /* Convert pointers from 32 to 64 bit. */
5276  final_array = MEM_malloc_arrayN(array_size, 8, "new pointer array");
5278  reader, array_size, (uint32_t *)orig_array, (uint64_t *)final_array);
5279  MEM_freeN(orig_array);
5280  }
5281  else {
5282  BLI_assert(false);
5283  }
5284 
5285  *ptr_p = final_array;
5286 }
5287 
5289 {
5290  return (reader->fd->flags & FD_FLAGS_IS_MEMFILE);
5291 }
5292 
5293 void BLO_read_data_globmap_add(BlendDataReader *reader, void *oldaddr, void *newaddr)
5294 {
5295  oldnewmap_insert(reader->fd->globmap, oldaddr, newaddr, 0);
5296 }
5297 
5299 {
5300  link_glob_list(reader->fd, list);
5301 }
5302 
5304 {
5305  return reader->fd->reports;
5306 }
5307 
5309 {
5310  return (reader->fd->flags & FD_FLAGS_IS_MEMFILE);
5311 }
5312 
5314 {
5315  return reader->main;
5316 }
5317 
5319 {
5320  return reader->fd->reports;
5321 }
5322 
5323 void BLO_expand_id(BlendExpander *expander, ID *id)
5324 {
5325  expand_doit(expander->fd, expander->main, id);
5326 }
5327 
void BKE_animdata_blend_read_lib(struct BlendLibReader *reader, struct ID *id, struct AnimData *adt)
Definition: anim_data.c:1472
void BKE_animdata_blend_read_expand(struct BlendExpander *expander, struct AnimData *adt)
Definition: anim_data.c:1491
struct AnimData * BKE_animdata_from_id(const struct ID *id)
void BKE_asset_metadata_read(struct BlendDataReader *reader, struct AssetMetaData *asset_data)
Definition: asset.cc:173
void BKE_blender_version_blendfile_string_from_values(char *str_buff, const size_t str_buff_len, const short file_version, const short file_subversion)
Definition: blender.c:129
#define BLENDER_FILE_SUBVERSION
#define BLENDER_FILE_VERSION
void BKE_collection_blend_read_data(struct BlendDataReader *reader, struct Collection *collection)
Definition: collection.c:236
void BKE_collection_blend_read_lib(struct BlendLibReader *reader, struct Collection *collection)
Definition: collection.c:302
void BKE_collection_blend_read_expand(struct BlendExpander *expander, struct Collection *collection)
Definition: collection.c:337
void BKE_collections_after_lib_link(struct Main *bmain)
Definition: collection.c:1400
void BKE_main_collections_parent_relations_rebuild(struct Main *bmain)
Definition: collection.c:1658
@ G_FILE_RECOVER_READ
Definition: BKE_global.h:225
@ G_DEBUG
Definition: BKE_global.h:174
void IDP_BlendReadExpand(struct BlendExpander *expander, struct IDProperty *prop)
Definition: idprop.c:1471
#define IDP_BlendDataRead(reader, prop)
Definition: BKE_idprop.h:321
void IDP_BlendReadLib(struct BlendLibReader *reader, struct Library *lib, struct IDProperty *prop)
Definition: idprop.c:1435
const char * BKE_idtype_idcode_to_name(short idcode)
Definition: idtype.c:142
bool BKE_idtype_cache_key_cmp(const void *key_a_v, const void *key_b_v)
Definition: idtype.c:39
void BKE_idtype_id_foreach_cache(struct ID *id, IDTypeForeachCacheFunctionCallback function_callback, void *user_data)
Definition: idtype.c:447
bool BKE_idtype_idcode_is_linkable(short idcode)
Definition: idtype.c:175
const struct IDTypeInfo * BKE_idtype_get_info_from_id(const struct ID *id)
uint BKE_idtype_cache_key_hash(const void *key_v)
Definition: idtype.c:31
bool BKE_idtype_idcode_is_valid(short idcode)
Definition: idtype.c:170
@ IDTYPE_CACHE_CB_FLAGS_PERSISTENT
Definition: BKE_idtype.h:75
struct ViewLayer * BKE_view_layer_find(const struct Scene *scene, const char *layer_name)
void BKE_lib_libblock_session_uuid_ensure(struct ID *id)
Definition: lib_id.c:1140
void BKE_main_id_tag_all(struct Main *mainvar, int tag, bool value)
Definition: lib_id.c:930
void * BKE_libblock_alloc(struct Main *bmain, short type, const char *name, int flag) ATTR_WARN_UNUSED_RESULT
Definition: lib_id.c:1050
void BKE_main_id_refcount_recompute(struct Main *bmain, bool do_linked_only)
Definition: lib_id.c:1499
void * BKE_libblock_alloc_notest(short type) ATTR_WARN_UNUSED_RESULT
Definition: lib_id.c:1039
void BKE_lib_id_swap_full(struct Main *bmain, struct ID *id_a, struct ID *id_b)
Definition: lib_id.c:757
void BKE_id_free(struct Main *bmain, void *idv)
void BKE_libblock_init_empty(struct ID *id) ATTR_NONNULL(1)
Definition: lib_id.c:1115
void id_us_ensure_real(struct ID *id)
Definition: lib_id.c:260
#define MAIN_ID_SESSION_UUID_UNSET
Definition: BKE_lib_id.h:82
void id_sort_by_name(struct ListBase *lb, struct ID *id, struct ID *id_sorting_hint)
Definition: lib_id.c:1318
struct ID * BKE_libblock_find_name(struct Main *bmain, short type, const char *name) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: lib_id.c:1297
void BKE_lib_override_library_main_update(struct Main *bmain)
void BKE_lib_override_library_main_validate(struct Main *bmain, struct ReportList *reports)
void BKE_library_foreach_ID_link(struct Main *bmain, struct ID *id, LibraryIDLinkCallback callback, void *user_data, int flag)
Definition: lib_query.c:350
@ IDWALK_NOP
@ IDWALK_CB_USER_ONE
Definition: BKE_lib_query.h:79
@ IDWALK_CB_EMBEDDED
Definition: BKE_lib_query.h:48
@ IDWALK_RET_NOP
Definition: BKE_lib_query.h:83
#define FOREACH_MAIN_ID_END
Definition: BKE_main.h:367
struct Main * BKE_main_new(void)
Definition: main.c:32
#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 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
#define FOREACH_MAIN_ID_BEGIN(_bmain, _id)
Definition: BKE_main.h:361
#define MAIN_VERSION_FILE_OLDER_OR_EQUAL(main, ver, subver)
Definition: BKE_main.h:435
#define BLEN_THUMB_MEMSIZE(_x, _y)
Definition: BKE_main.h:448
struct ListBase * which_libbase(struct Main *bmain, short type)
Definition: main.c:567
#define BLEN_THUMB_MEMSIZE_IS_VALID(_x, _y)
Definition: BKE_main.h:451
bool BKE_main_is_empty(struct Main *bmain)
Definition: main.c:204
void BKE_main_free(struct Main *mainvar)
Definition: main.c:40
const char * BKE_main_blendfile_path_from_global(void)
Definition: main.c:562
struct IDNameLib_Map * BKE_main_idmap_create(struct Main *bmain, bool create_valid_ids_set, struct Main *old_bmain, int idmap_types) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition: main_idmap.c:77
struct ID struct ID struct ID * BKE_main_idmap_lookup_uuid(struct IDNameLib_Map *id_map, uint session_uuid) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition: main_idmap.c:250
@ MAIN_IDMAP_TYPE_UUID
@ MAIN_IDMAP_TYPE_NAME
void BKE_main_idmap_destroy(struct IDNameLib_Map *id_map) ATTR_NONNULL()
Definition: main_idmap.c:258
struct Main * BKE_main_idmap_main_get(struct IDNameLib_Map *id_map) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: main_idmap.c:182
void BKE_main_idmap_remove_id(struct IDNameLib_Map *id_map, struct ID *id) ATTR_NONNULL()
Definition: main_idmap.c:158
struct ID * BKE_main_idmap_lookup_name(struct IDNameLib_Map *id_map, short id_type, const char *name, const struct Library *lib) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1
void BKE_main_idmap_insert_id(struct IDNameLib_Map *id_map, struct ID *id) ATTR_NONNULL()
Definition: main_idmap.c:128
struct ID struct ID * BKE_main_idmap_lookup_id(struct IDNameLib_Map *id_map, const struct ID *id) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1
General operations, lookup, etc. for materials.
void BKE_object_materials_test(struct Main *bmain, struct Object *ob, struct ID *id)
Definition: material.c:864
struct bNodeTree * ntreeFromID(struct ID *id)
Definition: node.cc:3231
void ntreeBlendReadData(struct BlendDataReader *reader, struct bNodeTree *ntree)
Definition: node.cc:675
void ntreeBlendReadLib(struct BlendLibReader *reader, struct bNodeTree *ntree)
Definition: node.cc:900
struct bNodeTree ** BKE_ntree_ptr_from_id(struct ID *id)
Definition: node.cc:3209
void ntreeBlendReadExpand(struct BlendExpander *expander, struct bNodeTree *ntree)
Definition: node.cc:996
void ntreeUpdateAllNew(struct Main *main)
Definition: node.cc:4173
General operations, lookup, etc. for blender objects.
void BKE_packedfile_blend_read(struct BlendDataReader *reader, struct PackedFile **pf_p)
Definition: packedFile.c:864
void BKE_reportf(ReportList *reports, eReportType type, const char *format,...) ATTR_PRINTF_FORMAT(3
const char * BKE_report_type_str(eReportType type)
Definition: report.c:24
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition: report.c:83
bool BKE_screen_blend_read_data(struct BlendDataReader *reader, struct bScreen *screen)
Definition: screen.c:242
@ STEP_UNDO
@ STEP_REDO
struct WorkSpace * BKE_workspace_active_get(struct WorkSpaceInstanceHook *hook) GETTER_ATTRS
Definition: workspace.c:516
struct bScreen * BKE_workspace_active_screen_get(const struct WorkSpaceInstanceHook *hook) GETTER_ATTRS
void BKE_workspace_active_set(struct WorkSpaceInstanceHook *hook, struct WorkSpace *workspace) SETTER_ATTRS
Definition: workspace.c:520
struct bScreen * BKE_workspace_layout_screen_get(const struct WorkSpaceLayout *layout) GETTER_ATTRS
#define BLI_assert_unreachable()
Definition: BLI_assert.h:93
#define BLI_STATIC_ASSERT(a, msg)
Definition: BLI_assert.h:83
#define BLI_assert(a)
Definition: BLI_assert.h:46
#define ATTR_FALLTHROUGH
#define B_ENDIAN
#define L_ENDIAN
#define ENDIAN_ORDER
BLI_INLINE void BLI_endian_switch_uint64(uint64_t *val) ATTR_NONNULL(1)
void BLI_endian_switch_float_array(float *val, int size) ATTR_NONNULL(1)
Definition: endian_switch.c:51
BLI_INLINE void BLI_endian_switch_int32(int *val) ATTR_NONNULL(1)
void BLI_endian_switch_int32_array(int *val, int size) ATTR_NONNULL(1)
Definition: endian_switch.c:31
void BLI_endian_switch_uint32_array(unsigned int *val, int size) ATTR_NONNULL(1)
Definition: endian_switch.c:41
void BLI_endian_switch_double_array(double *val, int size) ATTR_NONNULL(1)
Definition: endian_switch.c:81
#define O_BINARY
Definition: BLI_fileops.h:319
bool BLI_file_magic_is_gzip(const char header[4])
Definition: fileops.c:133
bool BLI_is_file(const char *path) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: storage.c:402
bool BLI_file_magic_is_zstd(const char header[4])
Definition: fileops.c:140
bool BLI_is_dir(const char *path) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: storage.c:397
int BLI_open(const char *filepath, int oflag, int pmode) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: fileops.c:920
FileReader * BLI_filereader_new_file(int filedes) ATTR_WARN_UNUSED_RESULT
FileReader * BLI_filereader_new_zstd(FileReader *base) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
FileReader * BLI_filereader_new_gzip(FileReader *base) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
FileReader * BLI_filereader_new_memory(const void *data, size_t len) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
FileReader * BLI_filereader_new_mmap(int filedes) ATTR_WARN_UNUSED_RESULT
GHash * BLI_ghash_str_new_ex(const char *info, unsigned int nentries_reserve) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
bool BLI_ghash_haskey(const GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT
Definition: BLI_ghash.c:822
void BLI_ghash_clear(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
Definition: BLI_ghash.c:858
GHash * BLI_ghash_str_new(const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
GHash * BLI_ghash_new(GHashHashFP hashfp, GHashCmpFP cmpfp, const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
Definition: BLI_ghash.c:689
void * BLI_ghash_lookup(const GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT
Definition: BLI_ghash.c:734
void BLI_ghash_insert(GHash *gh, void *key, void *val)
Definition: BLI_ghash.c:710
void BLI_ghash_free(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
Definition: BLI_ghash.c:863
bool BLI_ghash_ensure_p(GHash *gh, void *key, void ***r_val) ATTR_WARN_UNUSED_RESULT
Definition: BLI_ghash.c:755
BLI_INLINE bool BLI_listbase_is_empty(const struct ListBase *lb)
Definition: BLI_listbase.h:269
#define LISTBASE_FOREACH(type, var, list)
Definition: BLI_listbase.h:336
void BLI_freelinkN(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:239
#define LISTBASE_FOREACH_MUTABLE(type, var, list)
Definition: BLI_listbase.h:354
BLI_INLINE void BLI_listbase_clear(struct ListBase *lb)
Definition: BLI_listbase.h:273
void void void BLI_movelisttolist(struct ListBase *dst, struct ListBase *src) ATTR_NONNULL(1
bool BLI_remlink_safe(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:123
void void BLI_freelistN(struct ListBase *listbase) ATTR_NONNULL(1)
Definition: listbase.c:466
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
void * BLI_findstring(const struct ListBase *listbase, const char *id, int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
int BLI_listbase_count(const struct ListBase *listbase) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
void BLI_memarena_free(struct MemArena *ma) ATTR_NONNULL(1)
Definition: BLI_memarena.c:94
struct MemArena * BLI_memarena_new(size_t bufsize, const char *name) ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL ATTR_NONNULL(2) ATTR_MALLOC
Definition: BLI_memarena.c:64
#define BLI_MEMARENA_STD_BUFSIZE
Definition: BLI_memarena.h:20
void * BLI_memarena_alloc(struct MemArena *ma, size_t size) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1) ATTR_MALLOC ATTR_ALLOC_SIZE(2)
Definition: BLI_memarena.c:116
void BLI_mempool_iternew(BLI_mempool *pool, BLI_mempool_iter *iter) ATTR_NONNULL()
Definition: BLI_mempool.c:498
void * BLI_mempool_iterstep(BLI_mempool_iter *iter) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: BLI_mempool.c:577
bool BLI_path_extension_check_array(const char *str, const char **ext_array) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT
Definition: path_util.c:1326
const char * BLI_path_basename(const char *path) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT
Definition: path_util.c:1653
bool BLI_path_is_rel(const char *path) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT
Definition: path_util.c:347
#define FILE_MAX
void BLI_path_normalize(const char *relabase, char *path) ATTR_NONNULL(2)
Definition: path_util.c:131
void BLI_path_rel(char *file, const char *relfile) ATTR_NONNULL()
Definition: path_util.c:450
const char * BLI_path_slash_rfind(const char *string) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT
Definition: path_util.c:1765
#define BLI_path_cmp
#define STRNCPY(dst, src)
Definition: BLI_string.h:483
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, size_t maxncpy) ATTR_NONNULL()
Definition: string.c:64
unsigned int uint
Definition: BLI_sys_types.h:67
#define UNUSED_VARS(...)
#define STREQLEN(a, b, n)
#define UNUSED_VARS_NDEBUG(...)
#define UNUSED(x)
#define UNLIKELY(x)
#define ELEM(...)
#define MIN2(a, b)
#define POINTER_OFFSET(v, ofs)
#define STREQ(a, b)
#define LIKELY(x)
Compatibility-like things for windows.
SSIZE_T ssize_t
Definition: BLI_winstuff.h:71
defines for blend-file codes.
@ GLOB
@ DNA1
@ ENDB
@ DATA
@ TEST
@ USER
@ REND
#define BLEN_THUMB_MEMSIZE_FILE(_x, _y)
Utilities ensuring .blend file (i.e. Main) is in valid state during write and/or read process.
bool BLO_main_validate_shapekeys(struct Main *bmain, struct ReportList *reports)
void BLO_main_validate_embedded_liboverrides(struct Main *bmain, struct ReportList *reports)
#define BLO_read_data_address(reader, ptr_p)
void(* BlendReadListFn)(BlendDataReader *reader, void *data)
#define BLO_read_id_address(reader, lib, id_ptr_p)
#define BLO_expand(expander, id)
external readfile function prototypes.
void(* BLOExpandDoitCallback)(void *fdhandle, struct Main *mainvar, void *idv)
Definition: BLO_readfile.h:463
@ BLO_LIBLINK_USE_PLACEHOLDERS
Definition: BLO_readfile.h:331
@ BLO_LIBLINK_FORCE_INDIRECT
Definition: BLO_readfile.h:333
#define BLO_GROUP_MAX
Definition: BLO_readfile.h:296
@ BLO_READ_SKIP_DATA
Definition: BLO_readfile.h:123
@ BLO_READ_SKIP_USERDEF
Definition: BLO_readfile.h:122
@ BLO_READ_SKIP_UNDO_OLD_MAIN
Definition: BLO_readfile.h:125
struct BlendHandle BlendHandle
Definition: BLO_readfile.h:35
#define BLO_EMBEDDED_STARTUP_BLEND
Definition: BLO_readfile.h:297
@ BLENFILETYPE_BLEND
Definition: BLO_readfile.h:50
FileReader * BLO_memfile_new_filereader(MemFile *memfile, int undo_direction)
Definition: undofile.c:332
#define TIP_(msgid)
#define CLOG_ERROR(clg_ref,...)
Definition: CLG_log.h:190
#define CLOG_WARN(clg_ref,...)
Definition: CLG_log.h:189
#define CLOG_INFO(clg_ref, level,...)
Definition: CLG_log.h:187
#define ID_FAKE_USERS(id)
Definition: DNA_ID.h:552
@ ID_RECALC_COPY_ON_WRITE
Definition: DNA_ID.h:834
@ ID_RECALC_GEOMETRY
Definition: DNA_ID.h:791
@ ID_RECALC_ALL
Definition: DNA_ID.h:891
@ INDEX_ID_MAX
Definition: DNA_ID.h:1058
#define ID_IS_LINKED(_id)
Definition: DNA_ID.h:566
#define MAX_ID_NAME
Definition: DNA_ID.h:337
@ LIB_TAG_INDIRECT
Definition: DNA_ID.h:677
@ LIB_TAG_EXTRAUSER
Definition: DNA_ID.h:698
@ LIB_TAG_TEMP_MAIN
Definition: DNA_ID.h:757
@ LIB_TAG_NEW
Definition: DNA_ID.h:704
@ LIB_TAG_UNDO_OLD_ID_REUSED
Definition: DNA_ID.h:752
@ LIB_TAG_LOCAL
Definition: DNA_ID.h:671
@ LIB_TAG_NEED_EXPAND
Definition: DNA_ID.h:681
@ LIB_TAG_EXTERN
Definition: DNA_ID.h:674
@ LIB_TAG_MISSING
Definition: DNA_ID.h:690
@ LIB_TAG_NEED_LINK
Definition: DNA_ID.h:686
@ LIB_TAG_ID_LINK_PLACEHOLDER
Definition: DNA_ID.h:684
@ LIB_INDIRECT_WEAK_LINK
Definition: DNA_ID.h:641
ID_Type
Definition: DNA_ID_enums.h:44
@ ID_WM
Definition: DNA_ID_enums.h:72
@ ID_CA
Definition: DNA_ID_enums.h:56
@ ID_AR
Definition: DNA_ID_enums.h:66
@ ID_MC
Definition: DNA_ID_enums.h:73
@ ID_CF
Definition: DNA_ID_enums.h:78
@ ID_LI
Definition: DNA_ID_enums.h:46
@ ID_TE
Definition: DNA_ID_enums.h:52
@ ID_IM
Definition: DNA_ID_enums.h:53
@ ID_VO
Definition: DNA_ID_enums.h:83
@ ID_WS
Definition: DNA_ID_enums.h:79
@ ID_NT
Definition: DNA_ID_enums.h:68
@ ID_LA
Definition: DNA_ID_enums.h:55
@ ID_KE
Definition: DNA_ID_enums.h:58
@ ID_TXT
Definition: DNA_ID_enums.h:62
@ ID_SO
Definition: DNA_ID_enums.h:64
@ ID_SCE
Definition: DNA_ID_enums.h:45
@ ID_LS
Definition: DNA_ID_enums.h:75
@ ID_MSK
Definition: DNA_ID_enums.h:74
@ ID_GD
Definition: DNA_ID_enums.h:71
@ ID_CV
Definition: DNA_ID_enums.h:81
@ ID_PAL
Definition: DNA_ID_enums.h:76
@ ID_BR
Definition: DNA_ID_enums.h:69
@ ID_LP
Definition: DNA_ID_enums.h:80
@ ID_WO
Definition: DNA_ID_enums.h:59
@ ID_SIM
Definition: DNA_ID_enums.h:84
@ ID_MA
Definition: DNA_ID_enums.h:51
@ ID_AC
Definition: DNA_ID_enums.h:67
@ ID_SCR
Definition: DNA_ID_enums.h:60
@ ID_CU_LEGACY
Definition: DNA_ID_enums.h:49
@ ID_VF
Definition: DNA_ID_enums.h:61
@ ID_ME
Definition: DNA_ID_enums.h:48
@ ID_IP
Definition: DNA_ID_enums.h:57
@ ID_GR
Definition: DNA_ID_enums.h:65
@ ID_SPK
Definition: DNA_ID_enums.h:63
@ ID_MB
Definition: DNA_ID_enums.h:50
@ ID_LT
Definition: DNA_ID_enums.h:54
@ ID_OB
Definition: DNA_ID_enums.h:47
@ ID_PA
Definition: DNA_ID_enums.h:70
@ ID_PT
Definition: DNA_ID_enums.h:82
@ ID_PC
Definition: DNA_ID_enums.h:77
#define ID_SCRN
Definition: DNA_ID_enums.h:91
#define ID_LINK_PLACEHOLDER
Definition: DNA_ID_enums.h:88
@ SACTION_RUNTIME_FLAG_NEED_CHAN_SYNC
Object groups, one object can be in many groups at once.
@ COLLECTION_IS_MASTER
blenloader genfile private function prototypes
void DNA_sdna_free(struct SDNA *sdna)
Definition: dna_genfile.c:123
struct SDNA * DNA_sdna_from_data(const void *data, int data_len, bool do_endian_swap, bool data_alloc, const char **r_error_message)
Definition: dna_genfile.c:519
struct DNA_ReconstructInfo * DNA_reconstruct_info_create(const struct SDNA *oldsdna, const struct SDNA *newsdna, const char *compare_flags)
void DNA_struct_switch_endian(const struct SDNA *sdna, int struct_nr, char *data)
void * DNA_struct_reconstruct(const struct DNA_ReconstructInfo *reconstruct_info, int old_struct_nr, int blocks, const void *old_blocks)
const char * DNA_struct_get_compareflags(const struct SDNA *sdna, const struct SDNA *newsdna)
void DNA_reconstruct_info_free(struct DNA_ReconstructInfo *reconstruct_info)
Definition: dna_genfile.c:1559
const struct SDNA * DNA_sdna_current_get(void)
Definition: dna_genfile.c:566
int DNA_elem_offset(struct SDNA *sdna, const char *stype, const char *vartype, const char *name)
Definition: dna_genfile.c:1571
@ SDNA_CMP_REMOVED
Definition: DNA_genfile.h:59
@ SDNA_CMP_NOT_EQUAL
Definition: DNA_genfile.h:65
@ OB_MODE_EDIT
#define TSE_IS_REAL_ID(_tse)
#define SCE_READFILE_LIBLINK_NEED_SETSCENE_CHECK
@ RGN_TYPE_WINDOW
@ SPREADSHEET_CONTEXT_OBJECT
@ SPACE_TEXT
@ SPACE_CLIP
@ SPACE_ACTION
@ SPACE_OUTLINER
@ SPACE_NODE
@ SPACE_SPREADSHEET
@ SPACE_FILE
@ SPACE_PROPERTIES
@ SPACE_NLA
@ SPACE_SEQ
@ SPACE_SCRIPT
@ SPACE_IMAGE
@ SPACE_GRAPH
@ SPACE_VIEW3D
#define SCRIPT_SET_NULL(_script)
@ FILE_TAG_REBUILD_MAIN_FILES
@ SB_PIN_CONTEXT
@ SIPO_RUNTIME_FLAG_NEED_CHAN_SYNC_COLOR
@ SO_TREESTORE_REBUILD
@ FILE_RELPATH
@ USER_MENU_TYPE_OPERATOR
struct DrawDataList * DRW_drawdatalist_from_id(struct ID *id)
Definition: draw_manager.c:836
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei height
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_BOOL GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLushort pattern _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble u2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLdouble GLdouble v2 _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLdouble GLdouble nz _GL_VOID_RET _GL_VOID GLfloat GLfloat nz _GL_VOID_RET _GL_VOID GLint GLint nz _GL_VOID_RET _GL_VOID GLshort GLshort nz _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const GLfloat *values _GL_VOID_RET _GL_VOID GLsizei const GLushort *values _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID const GLuint const GLclampf *priorities _GL_VOID_RET _GL_VOID GLdouble y _GL_VOID_RET _GL_VOID GLfloat y _GL_VOID_RET _GL_VOID GLint y _GL_VOID_RET _GL_VOID GLshort y _GL_VOID_RET _GL_VOID GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLfloat GLfloat z _GL_VOID_RET _GL_VOID GLint GLint z _GL_VOID_RET _GL_VOID GLshort GLshort z _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble w _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat w _GL_VOID_RET _GL_VOID GLint GLint GLint w _GL_VOID_RET _GL_VOID GLshort GLshort GLshort w _GL_VOID_RET _GL_VOID GLdouble GLdouble x2
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum type
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei width
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_BOOL GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLushort pattern _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint GLdouble v1
Read Guarded memory(de)allocation.
#define MEM_SAFE_FREE(v)
#define MEM_reallocN(vmemh, len)
Platform independent time functions.
int main(int argc, char *argv[])
ATTR_WARN_UNUSED_RESULT const BMVert * v2
Definition: id_map.h:23
Scene * scene
Definition: id_map.h:178
ListBase seqbase_clipboard
Definition: clipboard.c:45
StackEntry * from
FILE * file
Scene scene
bool is_valid
DEGForeachIDComponentCallback callback
SyclQueue void void * src
bNodeTree * ntree
DRWShaderLibrary * lib
#define str(s)
#define pf(_x, _i)
Prefetch 64.
Definition: gim_memory.h:48
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
#define GS(x)
Definition: iris.c:225
void SEQ_for_each_callback(ListBase *seqbase, SeqForEachFunc callback, void *user_data)
Definition: iterator.c:76
format
Definition: logImageCore.h:38
void *(* MEM_malloc_arrayN)(size_t len, size_t size, const char *str)
Definition: mallocn.c:34
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:27
size_t(* MEM_allocN_len)(const void *vmemh)
Definition: mallocn.c:26
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 c
Definition: RandGen.cpp:83
static unsigned a[3]
Definition: RandGen.cpp:78
static void area(int d1, int d2, int e1, int e2, float weights[2])
SymEdge< T > * prev(const SymEdge< T > *se)
Definition: delaunay_2d.cc:105
static const pxr::TfToken st("st", pxr::TfToken::Immortal)
void blo_do_versions_oldnewmap_insert(OldNewMap *onm, const void *oldaddr, void *newaddr, int nr)
Definition: readfile.c:368
void BLO_read_float3_array(BlendDataReader *reader, int array_size, float **ptr_p)
Definition: readfile.c:5201
void BLO_expand_main(void *fdhandle, Main *mainvar)
Definition: readfile.c:4477
static void read_libraries(FileData *basefd, ListBase *mainlist)
Definition: readfile.c:5025
static BHead * read_libblock(FileData *fd, Main *main, BHead *bhead, const int tag, const bool placeholder_set_indirect_extern, ID **r_id)
Definition: readfile.c:3434
void blo_make_packed_pointer_map(FileData *fd, Main *oldmain)
Definition: readfile.c:1682
static void lib_link_scenes_check_set(Main *bmain)
Definition: readfile.c:2373
struct BlendLibReader BlendLibReader
static void link_glob_list(FileData *fd, ListBase *lb)
Definition: readfile.c:2033
static void bh8_from_bh4(BHead *bhead, BHead4 *bhead4)
Definition: readfile.c:782
static BHead * blo_bhead_read_full(FileData *fd, BHead *thisblock)
Definition: readfile.c:1015
static FileData * blo_filedata_from_file_open(const char *filepath, BlendFileReadReport *reports)
Definition: readfile.c:1342
static void lib_link_all(FileData *fd, Main *bmain)
Definition: readfile.c:3768
void blo_cache_storage_end(FileData *fd)
Definition: readfile.c:1924
static void convert_pointer_array_32_to_64(BlendDataReader *UNUSED(reader), uint array_size, const uint32_t *src, uint64_t *dst)
Definition: readfile.c:5234
static void restore_pointer_user(ID *id, ID *newid, ePointerUserMode user)
Definition: readfile.c:2404
static void oldnewmap_clear_map(OldNewMap *onm)
Definition: readfile.c:308
BlendFileReadReport * BLO_read_data_reports(BlendDataReader *reader)
Definition: readfile.c:5303
void BLO_expand_id(BlendExpander *expander, ID *id)
Definition: readfile.c:5323
static void after_liblink_merged_bmain_process(Main *bmain)
Definition: readfile.c:3837
FileData * blo_filedata_from_memfile(MemFile *memfile, const struct BlendFileReadParams *params, BlendFileReadReport *reports)
Definition: readfile.c:1416
static FileData * filedata_new(BlendFileReadReport *reports)
Definition: readfile.c:1184
static void direct_link_library(FileData *fd, Library *lib, Main *main)
Definition: readfile.c:2888
static void direct_link_id_override_property_cb(BlendDataReader *reader, void *data)
Definition: readfile.c:2119
void BLO_library_link_end(Main *mainl, BlendHandle **bh, const struct LibraryLink_Params *params)
Definition: readfile.c:4787
BlendFileData * blo_read_file_internal(FileData *fd, const char *filepath)
Definition: readfile.c:3963
static void oldnewmap_init_data(OldNewMap *onm, const int capacity_exp)
Definition: readfile.c:326
static ID * link_named_part(Main *mainl, FileData *fd, const short idcode, const char *name, const int flag)
Definition: readfile.c:4519
static void convert_pointer_array_64_to_32(BlendDataReader *reader, uint array_size, const uint64_t *src, uint32_t *dst)
Definition: readfile.c:5214
static void lib_link_window_scene_data_restore(wmWindow *win, Scene *scene, ViewLayer *view_layer)
Definition: readfile.c:2543
static void blo_cache_storage_entry_clear_in_old(ID *UNUSED(id), const IDCacheKey *key, void **cache_p, uint UNUSED(flags), void *cache_storage_v)
Definition: readfile.c:1838
static void read_file_bhead_idname_map_create(FileData *fd)
Definition: readfile.c:601
static int direct_link_id_restore_recalc_exceptions(const ID *id_current)
Definition: readfile.c:2164
struct BLOCacheStorage BLOCacheStorage
static int lib_link_main_data_restore_cb(LibraryIDLinkCallbackData *cb_data)
Definition: readfile.c:2496
struct BlendExpander BlendExpander
BlendFileReadReport * BLO_read_lib_reports(BlendLibReader *reader)
Definition: readfile.c:5318
static void split_main_newid(Main *mainptr, Main *main_newid)
Definition: readfile.c:4658
static void link_global(FileData *fd, BlendFileData *bfd)
Definition: readfile.c:3633
void * BLO_read_get_new_packed_address(BlendDataReader *reader, const void *old_address)
Definition: readfile.c:5133
void BLO_library_link_params_init(struct LibraryLink_Params *params, struct Main *bmain, const int flag, const int id_tag_extra)
Definition: readfile.c:4622
static bool read_libblock_is_identical(FileData *fd, BHead *bhead)
Definition: readfile.c:3185
void * BLO_read_get_new_data_address_no_us(BlendDataReader *reader, const void *old_address)
Definition: readfile.c:5128
static BLOExpandDoitCallback expand_doit
Definition: readfile.c:4433
void blo_lib_link_restore(Main *oldmain, Main *newmain, wmWindowManager *curwm, Scene *curscene, ViewLayer *cur_view_layer)
Definition: readfile.c:2819
static int direct_link_id_restore_recalc(const FileData *fd, const ID *id_target, const ID *id_current, const bool is_identical)
Definition: readfile.c:2175
static void lib_link_clipboard_restore(struct IDNameLib_Map *id_map)
Definition: readfile.c:2490
static ID * create_placeholder(Main *mainvar, const short idcode, const char *idname, const int tag)
Definition: readfile.c:2982
static void * read_struct(FileData *fd, BHead *bh, const char *blockname)
Definition: readfile.c:1956
void BLO_library_link_params_init_with_context(struct LibraryLink_Params *params, struct Main *bmain, const int flag, const int id_tag_extra, struct Scene *scene, struct ViewLayer *view_layer, const struct View3D *v3d)
Definition: readfile.c:4633
Main * BLO_library_link_begin(BlendHandle **bh, const char *filepath, const struct LibraryLink_Params *params)
Definition: readfile.c:4650
static void do_versions_userdef(FileData *UNUSED(fd), BlendFileData *bfd)
Definition: readfile.c:3652
static bool blo_bhead_is_id(const BHead *bhead)
Definition: readfile.c:583
static FileData * blo_decode_and_check(FileData *fd, ReportList *reports)
Definition: readfile.c:1249
static void * restore_pointer_by_name(struct IDNameLib_Map *id_map, ID *id, ePointerUserMode user)
Definition: readfile.c:2452
static void direct_link_id_embedded_id(BlendDataReader *reader, Library *current_library, ID *id, ID *id_old)
Definition: readfile.c:2133
void BLO_read_glob_list(BlendDataReader *reader, ListBase *list)
Definition: readfile.c:5298
static int has_linked_ids_to_read(Main *mainvar)
Definition: readfile.c:4807
static bool direct_link_id(FileData *fd, Main *main, const int tag, ID *id, ID *id_old)
Definition: readfile.c:3108
static void library_link_end(Main *mainl, FileData **fd, const int flag)
Definition: readfile.c:4682
static void split_libdata(ListBase *lb_src, Main **lib_main_array, const uint lib_main_array_len)
Definition: readfile.c:475
FileData * blo_filedata_from_file(const char *filepath, BlendFileReadReport *reports)
Definition: readfile.c:1357
static bool lib_link_seq_clipboard_cb(Sequence *seq, void *arg_pt)
Definition: readfile.c:2478
void BLO_read_double_array(BlendDataReader *reader, int array_size, double **ptr_p)
Definition: readfile.c:5206
static void add_main_to_main(Main *mainvar, Main *from)
Definition: readfile.c:439
bool BLO_read_data_is_undo(BlendDataReader *reader)
Definition: readfile.c:5288
static void direct_link_id_common(BlendDataReader *reader, Library *current_library, ID *id, ID *id_old, const int tag)
Definition: readfile.c:2221
static void * oldnewmap_lookup_and_inc(OldNewMap *onm, const void *addr, bool increase_users)
Definition: readfile.c:373
static void do_versions_after_linking(FileData *fd, Main *main)
Definition: readfile.c:3724
#define ENTRIES_CAPACITY(onm)
Definition: readfile.c:250
static BHead * find_bhead(FileData *fd, void *old)
Definition: readfile.c:4222
void BLO_read_float_array(BlendDataReader *reader, int array_size, float **ptr_p)
Definition: readfile.c:5193
void BLO_read_int32_array(BlendDataReader *reader, int array_size, int32_t **ptr_p)
Definition: readfile.c:5177
static const char * dataname(short id_code)
Definition: readfile.c:3021
void BLO_main_expander(BLOExpandDoitCallback expand_doit_func)
Definition: readfile.c:4472
static void lib_link_main_data_restore(struct IDNameLib_Map *id_map, Main *newmain)
Definition: readfile.c:2528
static void oldnewmap_lib_insert(FileData *fd, const void *oldaddr, ID *newaddr, int nr)
Definition: readfile.c:363
static BHead * find_bhead_from_idname(FileData *fd, const char *idname)
Definition: readfile.c:4285
static Main * library_link_begin(Main *mainvar, FileData **fd, const char *filepath, const int id_tag_extra)
Definition: readfile.c:4590
void BLO_read_list(BlendDataReader *reader, struct ListBase *list)
Definition: readfile.c:5172
static void * newdataadr_no_us(FileData *fd, const void *adr)
Definition: readfile.c:1606
struct OldNewMap OldNewMap
struct BlendDataReader BlendDataReader
void * blo_do_versions_newlibadr(FileData *fd, const void *lib, const void *adr)
Definition: readfile.c:1632
static void sort_bhead_old_map(FileData *fd)
Definition: readfile.c:4181
static bool read_libblock_undo_restore_linked(FileData *fd, Main *main, const ID *id, BHead *bhead)
Definition: readfile.c:3249
#define DEFAULT_SIZE_EXP
Definition: readfile.c:253
static void fix_relpaths_library(const char *basepath, Main *main)
Definition: readfile.c:2948
static BHead * find_previous_lib(FileData *fd, BHead *bhead)
Definition: readfile.c:4206
struct BLOCacheStorageValue BLOCacheStorageValue
static void expand_doit_library(void *fdhandle, Main *mainvar, void *old)
Definition: readfile.c:4314
static void * newdataadr(FileData *fd, const void *adr)
Definition: readfile.c:1600
static bool read_libblock_undo_restore(FileData *fd, Main *main, BHead *bhead, const int tag, ID **r_id_old)
Definition: readfile.c:3347
bool BLO_read_lib_is_undo(BlendLibReader *reader)
Definition: readfile.c:5308
static void expand_id_embedded_id(BlendExpander *expander, ID *id)
Definition: readfile.c:4437
static FileData * blo_filedata_from_file_descriptor(const char *filepath, BlendFileReadReport *reports, int filedes)
Definition: readfile.c:1276
static FileData * read_library_file_data(FileData *basefd, ListBase *mainlist, Main *mainl, Main *mainptr)
Definition: readfile.c:4947
void * BLO_read_get_new_data_address(BlendDataReader *reader, const void *old_address)
Definition: readfile.c:5123
static bool read_libblock_undo_restore_library(FileData *fd, Main *main, const ID *id)
Definition: readfile.c:3207
static void oldnewmap_free(OldNewMap *onm)
Definition: readfile.c:419
static void * oldnewmap_liblookup(OldNewMap *onm, const void *addr, const void *lib)
Definition: readfile.c:386
static void blo_cache_storage_entry_register(ID *id, const IDCacheKey *key, void **cache_p, uint UNUSED(flags), void *cache_storage_v)
Definition: readfile.c:1794
static void lib_link_id_embedded_id(BlendLibReader *reader, ID *id)
Definition: readfile.c:2070
void BLO_read_uint32_array(BlendDataReader *reader, int array_size, uint32_t **ptr_p)
Definition: readfile.c:5185
static OldNewMap * oldnewmap_new(void)
Definition: readfile.c:337
static void expand_id(BlendExpander *expander, ID *id)
Definition: readfile.c:4455
static void oldnewmap_insert(OldNewMap *onm, const void *oldaddr, void *newaddr, int nr)
Definition: readfile.c:346
static int * read_file_thumbnail(FileData *fd)
Definition: readfile.c:1138
void BLO_read_data_globmap_add(BlendDataReader *reader, void *oldaddr, void *newaddr)
Definition: readfile.c:5293
static BHead * read_userdef(BlendFileData *bfd, FileData *fd, BHead *bhead)
Definition: readfile.c:3870
static void * newpackedadr(FileData *fd, const void *adr)
Definition: readfile.c:1617
BlendThumbnail * BLO_thumbnail_from_file(const char *filepath)
Definition: readfile.c:1563
ID * BLO_read_get_new_id_address(BlendLibReader *reader, Library *lib, ID *id)
Definition: readfile.c:5138
static void read_library_linked_id(FileData *basefd, FileData *fd, Main *mainvar, ID *id, ID **r_id)
Definition: readfile.c:4823
static void read_library_linked_ids(FileData *basefd, FileData *fd, ListBase *mainlist, Main *mainvar)
Definition: readfile.c:4870
void BLO_read_list_cb(BlendDataReader *reader, ListBase *list, BlendReadListFn callback)
Definition: readfile.c:5148
static void do_versions(FileData *fd, Library *lib, Main *main)
Definition: readfile.c:3663
#define ITER_SLOTS(onm, KEY, SLOT_NAME, INDEX_NAME)
Definition: readfile.c:257
#define BHEADN_FROM_BHEAD(bh)
Definition: readfile.c:196
BHead * blo_bhead_first(FileData *fd)
Definition: readfile.c:937
static void change_link_placeholder_to_real_ID_pointer_fd(FileData *fd, const void *old, void *new)
Definition: readfile.c:1638
AssetMetaData * blo_bhead_id_asset_data_address(const FileData *fd, const BHead *bhead)
Definition: readfile.c:1036
bool BLO_library_path_explode(const char *path, char *r_dir, char **r_group, char **r_name)
Definition: readfile.c:1503
bool BLO_read_requires_endian_switch(BlendDataReader *reader)
Definition: readfile.c:5143
static void direct_link_keymapitem(BlendDataReader *reader, wmKeyMapItem *kmi)
Definition: readfile.c:3862
void * BLO_library_read_struct(FileData *fd, BHead *bh, const char *blockname)
Definition: readfile.c:4796
void blo_split_main(ListBase *mainlist, Main *main)
Definition: readfile.c:496
static int verg_bheadsort(const void *v1, const void *v2)
Definition: readfile.c:4168
struct OldNew OldNew
static bool read_file_dna(FileData *fd, const char **r_error_message)
Definition: readfile.c:1087
void blo_do_versions_key_uidgen(Key *key)
Definition: readfile.c:2323
BHead * blo_bhead_next(FileData *fd, BHead *thisblock)
Definition: readfile.c:965
static void placeholders_ensure_valid(Main *bmain)
Definition: readfile.c:3009
static BHead * find_bhead_from_code_name(FileData *fd, const short idcode, const char *name)
Definition: readfile.c:4255
void blo_cache_storage_init(FileData *fd, Main *bmain)
Definition: readfile.c:1861
void blo_make_old_idmap_from_main(FileData *fd, Main *bmain)
Definition: readfile.c:1775
static BHeadN * get_bhead(FileData *fd)
Definition: readfile.c:796
ePointerUserMode
Definition: readfile.c:2399
@ USER_REAL
Definition: readfile.c:2401
@ USER_IGNORE
Definition: readfile.c:2400
Main * BLO_read_lib_get_main(BlendLibReader *reader)
Definition: readfile.c:5313
static void oldnewmap_clear(OldNewMap *onm)
Definition: readfile.c:402
const char * blo_bhead_id_name(const FileData *fd, const BHead *bhead)
Definition: readfile.c:1031
static void oldnewmap_insert_or_replace(OldNewMap *onm, OldNew entry)
Definition: readfile.c:277
static void decode_blender_header(FileData *fd)
Definition: readfile.c:1044
static void read_libblock_undo_restore_at_old_address(FileData *fd, Main *main, ID *id, ID *id_old)
Definition: readfile.c:3315
static void bh4_from_bh8(BHead *bhead, BHead8 *bhead8, bool do_endian_swap)
Definition: readfile.c:756
void BLO_reportf_wrap(BlendFileReadReport *reports, eReportType type, const char *format,...)
Definition: readfile.c:204
void blo_end_packed_pointer_map(FileData *fd, Main *oldmain)
Definition: readfile.c:1723
static void lib_link_library(BlendLibReader *UNUSED(reader), Library *UNUSED(lib))
Definition: readfile.c:2942
#define MAP_CAPACITY(onm)
Definition: readfile.c:251
#define BHEAD_USE_READ_ON_DEMAND(bhead)
Definition: readfile.c:202
static void read_library_clear_weak_links(FileData *basefd, ListBase *mainlist, Main *mainvar)
Definition: readfile.c:4925
static void change_link_placeholder_to_real_ID_pointer(ListBase *mainlist, FileData *basefd, void *old, void *new)
Definition: readfile.c:1652
bool BLO_has_bfile_extension(const char *str)
Definition: readfile.c:1497
static CLG_LogRef LOG
Definition: readfile.c:175
static bool is_minversion_older_than_blender(FileData *fd, ReportList *reports)
Definition: readfile.c:1203
static void lib_link_id(BlendLibReader *reader, ID *id)
Definition: readfile.c:2089
BHead * blo_bhead_prev(FileData *UNUSED(fd), BHead *thisblock)
Definition: readfile.c:957
static ID * is_yet_read(FileData *fd, Main *mainvar, BHead *bhead)
Definition: readfile.c:4294
static void lib_link_seq_clipboard_pt_restore(ID *id, struct IDNameLib_Map *id_map)
Definition: readfile.c:2470
static void switch_endian_bh4(BHead4 *bhead)
Definition: readfile.c:728
void BLO_read_pointer_array(BlendDataReader *reader, void **ptr_p)
Definition: readfile.c:5245
static OldNew * oldnewmap_lookup_entry(const OldNewMap *onm, const void *addr)
Definition: readfile.c:293
static void * newlibadr(FileData *fd, const void *lib, const void *adr)
Definition: readfile.c:1627
static BHead * read_global(BlendFileData *bfd, FileData *fd, BHead *bhead)
Definition: readfile.c:3581
static void switch_endian_bh8(BHead8 *bhead)
Definition: readfile.c:742
struct BHeadN BHeadN
static bool blo_bhead_read_data(FileData *fd, BHead *thisblock, void *buf)
Definition: readfile.c:992
static Main * blo_find_main(FileData *fd, const char *filepath, const char *relabase)
Definition: readfile.c:642
ID * BLO_library_link_named_part(Main *mainl, BlendHandle **bh, const short idcode, const char *name, const struct LibraryLink_Params *params)
Definition: readfile.c:4569
static void switch_endian_structs(const struct SDNA *filesdna, BHead *bhead)
Definition: readfile.c:1940
void blo_filedata_free(FileData *fd)
Definition: readfile.c:1433
static void lib_link_wm_xr_data_restore(struct IDNameLib_Map *id_map, wmXrData *xr_data)
Definition: readfile.c:2537
static void insert_packedmap(FileData *fd, PackedFile *pf)
Definition: readfile.c:1676
static bool blo_bhead_is_id_valid_type(const BHead *bhead)
Definition: readfile.c:590
static void oldnewmap_insert_index_in_map(OldNewMap *onm, const void *ptr, int index)
Definition: readfile.c:267
static const char * library_parent_filepath(Library *lib)
Definition: readfile.c:224
static void read_libblock_undo_restore_identical(FileData *fd, Main *main, const ID *UNUSED(id), ID *id_old, const int tag)
Definition: readfile.c:3280
void blo_readfile_invalidate(FileData *fd, Main *bmain, const char *message)
Definition: readfile.c:693
static void read_file_version(FileData *fd, Main *main)
Definition: readfile.c:557
void blo_cache_storage_old_bmain_clear(FileData *fd, Main *bmain_old)
Definition: readfile.c:1897
static CLG_LogRef LOG_UNDO
Definition: readfile.c:176
static void lib_link_workspace_layout_restore(struct IDNameLib_Map *id_map, Main *newmain, WorkSpaceLayout *layout)
Definition: readfile.c:2592
BHead * blo_read_asset_data_block(FileData *fd, BHead *bhead, AssetMetaData **r_asset_data)
Definition: readfile.c:3558
void blo_add_library_pointer_map(ListBase *old_mainlist, FileData *fd)
Definition: readfile.c:1759
static FileData * blo_filedata_from_file_minimal(const char *filepath)
Definition: readfile.c:1373
void blo_join_main(ListBase *mainlist)
Definition: readfile.c:455
void * blo_read_get_new_globaldata_address(FileData *fd, const void *adr)
Definition: readfile.c:1611
static BHead * read_data_into_datamap(FileData *fd, BHead *bhead, const char *allocname)
Definition: readfile.c:3152
static void direct_link_id_override_property_operation_cb(BlendDataReader *reader, void *data)
Definition: readfile.c:2109
FileData * blo_filedata_from_memory(const void *mem, int memsize, BlendFileReadReport *reports)
Definition: readfile.c:1386
static void oldnewmap_increase_size(OldNewMap *onm)
Definition: readfile.c:313
static void blo_cache_storage_entry_restore_in_new(ID *UNUSED(id), const IDCacheKey *key, void **cache_p, uint flags, void *cache_storage_v)
Definition: readfile.c:1813
static void file_global_minversion_hotfix(FileGlobal *fg)
Definition: readfile.c:546
static const void * peek_struct_undo(FileData *fd, BHead *bhead)
Definition: readfile.c:2026
void do_versions_after_linking_250(struct Main *bmain)
void do_versions_after_linking_300(struct FileData *fd, struct Main *bmain)
void blo_do_versions_300(struct FileData *fd, struct Library *lib, struct Main *bmain)
@ FD_FLAGS_FILE_POINTSIZE_IS_4
Definition: readfile.h:34
@ FD_FLAGS_POINTSIZE_DIFFERS
Definition: readfile.h:35
@ FD_FLAGS_NOT_MY_LIBMAP
Definition: readfile.h:39
@ FD_FLAGS_IS_MEMFILE
Definition: readfile.h:37
@ FD_FLAGS_FILE_OK
Definition: readfile.h:36
@ FD_FLAGS_SWITCH_ENDIAN
Definition: readfile.h:33
void blo_do_versions_pre250(struct FileData *fd, struct Library *lib, struct Main *bmain)
void blo_do_versions_250(struct FileData *fd, struct Library *lib, struct Main *bmain)
void blo_do_versions_dna(struct SDNA *sdna, int versionfile, int subversionfile)
void blo_do_versions_cycles(struct FileData *fd, struct Library *lib, struct Main *bmain)
void do_versions_after_linking_270(struct Main *bmain)
void do_versions_after_linking_260(struct Main *bmain)
void blo_do_versions_260(struct FileData *fd, struct Library *lib, struct Main *bmain)
void do_versions_after_linking_290(struct FileData *fd, struct Main *bmain)
void blo_do_versions_290(struct FileData *fd, struct Library *lib, struct Main *bmain)
void do_versions_after_linking_cycles(struct Main *bmain)
void blo_do_versions_270(struct FileData *fd, struct Library *lib, struct Main *bmain)
#define SIZEOFBLENDERHEADER
Definition: readfile.h:109
void do_versions_after_linking_280(struct FileData *fd, struct Main *bmain)
void blo_do_versions_userdef(struct UserDef *userdef)
void blo_do_versions_280(struct FileData *fd, struct Library *lib, struct Main *bmain)
unsigned int uint32_t
Definition: stdint.h:80
__int64 int64_t
Definition: stdint.h:89
signed int int32_t
Definition: stdint.h:77
unsigned __int64 uint64_t
Definition: stdint.h:90
The meta-data of an asset. By creating and giving this for a data-block (ID.asset_data),...
uint old
uint64_t old
off64_t file_offset
Definition: readfile.c:188
struct BHeadN * prev
Definition: readfile.c:185
struct BHeadN * next
Definition: readfile.c:185
bool has_data
Definition: readfile.c:190
struct BHead bhead
Definition: readfile.c:193
bool is_memchunk_identical
Definition: readfile.c:192
const void * old
Definition: readfile.c:4165
BHead * bhead
Definition: readfile.c:4164
int SDNAnr
int code
const void * old
MemArena * memarena
Definition: readfile.c:1785
GHash * cache_map
Definition: readfile.c:1784
struct Base * next
unsigned short local_view_bits
FileData * fd
Definition: readfile.c:715
FileData * fd
Definition: readfile.c:724
Main * main
Definition: readfile.c:725
char filepath[1024]
Definition: BLO_readfile.h:61
struct bScreen * curscreen
Definition: BLO_readfile.h:63
eBlenFileType type
Definition: BLO_readfile.h:67
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
struct BlendFileReadReport::@134 count
struct BlendFileReadReport::@133 duration
Main * main
Definition: readfile.c:720
FileData * fd
Definition: readfile.c:719
char rect[0]
Definition: BKE_main.h:45
eBLOReadSkip skip_flags
Definition: readfile.h:79
int undo_direction
Definition: readfile.h:57
struct DNA_ReconstructInfo * reconstruct_info
Definition: readfile.h:67
int id_asset_data_offset
Definition: readfile.h:74
ListBase * old_mainlist
Definition: readfile.h:103
enum eFileDataFlag flags
Definition: readfile.h:50
ListBase bhead_list
Definition: readfile.h:49
int fileversion
Definition: readfile.h:69
struct OldNewMap * globmap
Definition: readfile.h:90
struct BlendFileReadReport * reports
Definition: readfile.h:106
struct OldNewMap * libmap
Definition: readfile.h:91
int fileflags
Definition: readfile.h:76
ListBase * mainlist
Definition: readfile.h:101
const struct SDNA * memsdna
Definition: readfile.h:64
struct SDNA * filesdna
Definition: readfile.h:63
int id_tag_extra
Definition: readfile.h:87
FileReader * file
Definition: readfile.h:53
char relabase[FILE_MAX]
Definition: readfile.h:60
struct OldNewMap * datamap
Definition: readfile.h:89
struct GHash * bhead_idname_hash
Definition: readfile.h:99
const char * compflags
Definition: readfile.h:66
int globalf
Definition: readfile.h:76
int id_name_offset
Definition: readfile.h:71
bool is_eof
Definition: readfile.h:51
int tot_bheadmap
Definition: readfile.h:96
struct OldNewMap * packedmap
Definition: readfile.h:92
struct BLOCacheStorage * cache_storage
Definition: readfile.h:93
struct BHeadSort * bheadmap
Definition: readfile.h:95
struct IDNameLib_Map * old_idmap
Definition: readfile.h:104
struct ViewLayer * cur_view_layer
struct Scene * curscene
uint64_t build_commit_timestamp
struct bScreen * curscreen
char filepath[1024]
FileReaderSeekFn seek
off64_t offset
FileReaderCloseFn close
FileReaderReadFn read
unsigned int id_session_uuid
Definition: BKE_idtype.h:46
struct Main * bmain
Definition: main_idmap.c:56
struct ID * storage
Definition: DNA_ID.h:308
ListBase properties
Definition: DNA_ID.h:296
struct ID * hierarchy_root
Definition: DNA_ID.h:303
struct ID * reference
Definition: DNA_ID.h:294
IDTypeBlendReadUndoPreserve blend_read_undo_preserve
Definition: BKE_idtype.h:218
IDTypeBlendReadExpandFunction blend_read_expand
Definition: BKE_idtype.h:211
struct AssetTypeInfo * asset_type_info
Definition: BKE_idtype.h:144
IDTypeForeachCacheFunction foreach_cache
Definition: BKE_idtype.h:179
IDTypeBlendReadDataFunction blend_read_data
Definition: BKE_idtype.h:201
IDTypeBlendReadLibFunction blend_read_lib
Definition: BKE_idtype.h:206
Definition: DNA_ID.h:368
int tag
Definition: DNA_ID.h:387
struct AssetMetaData * asset_data
Definition: DNA_ID.h:375
struct Library * lib
Definition: DNA_ID.h:372
int recalc_after_undo_push
Definition: DNA_ID.h:401
int recalc
Definition: DNA_ID.h:390
int us
Definition: DNA_ID.h:388
int icon_id
Definition: DNA_ID.h:389
struct ID * newid
Definition: DNA_ID.h:370
void * prev
Definition: DNA_ID.h:369
IDProperty * properties
Definition: DNA_ID.h:409
IDOverrideLibrary * override_library
Definition: DNA_ID.h:412
struct ID * orig_id
Definition: DNA_ID.h:419
short flag
Definition: DNA_ID.h:383
unsigned int session_uuid
Definition: DNA_ID.h:407
void * next
Definition: DNA_ID.h:369
char name[66]
Definition: DNA_ID.h:378
int recalc_up_to_undo_push
Definition: DNA_ID.h:400
struct LibraryWeakReference * library_weak_reference
Definition: DNA_ID.h:443
struct Scene * scene
int uidgen
ListBase block
Definition: DNA_key_types.h:84
struct PackedFile * packedfile
Definition: DNA_ID.h:476
short versionfile
Definition: DNA_ID.h:484
short subversionfile
Definition: DNA_ID.h:484
char filepath[1024]
Definition: DNA_ID.h:461
ID id
Definition: DNA_ID.h:458
int temp_index
Definition: DNA_ID.h:482
struct Library * parent
Definition: DNA_ID.h:474
struct FileData * filedata
Definition: DNA_ID.h:459
char filepath_abs[1024]
Definition: DNA_ID.h:471
void * last
Definition: DNA_listBase.h:31
void * first
Definition: DNA_listBase.h:31
Definition: BKE_main.h:121
ListBase volumes
Definition: BKE_main.h:210
ListBase scenes
Definition: BKE_main.h:168
short subversionfile
Definition: BKE_main.h:125
bool has_forward_compatibility_issues
Definition: BKE_main.h:132
ListBase texts
Definition: BKE_main.h:185
char filepath[1024]
Definition: BKE_main.h:124
ListBase fonts
Definition: BKE_main.h:184
BlendThumbnail * blen_thumb
Definition: BKE_main.h:165
short minversionfile
Definition: BKE_main.h:126
uint64_t build_commit_timestamp
Definition: BKE_main.h:134
struct Main * next
Definition: BKE_main.h:122
ListBase sounds
Definition: BKE_main.h:188
ListBase libraries
Definition: BKE_main.h:169
struct IDNameLib_Map * id_map
Definition: BKE_main.h:221
char build_hash[16]
Definition: BKE_main.h:135
short minsubversionfile
Definition: BKE_main.h:126
short versionfile
Definition: BKE_main.h:125
ListBase workspaces
Definition: BKE_main.h:203
bool is_read_invalid
Definition: BKE_main.h:163
struct Main * prev
Definition: BKE_main.h:122
ListBase images
Definition: BKE_main.h:176
ListBase objects
Definition: BKE_main.h:170
struct Library * curlib
Definition: BKE_main.h:167
struct Mask * mask
OldNew * entries
Definition: readfile.c:242
int32_t * map
Definition: readfile.c:245
int capacity_exp
Definition: readfile.c:247
int nentries
Definition: readfile.c:243
int nr
Definition: readfile.c:237
void * newp
Definition: readfile.c:235
const void * oldp
Definition: readfile.c:234
struct RegionView3D * localvd
short * types_size
SDNA_Struct ** structs
const char ** types
int pointer_size
struct Collection * master_collection
short flag
View3DCursor cursor
struct Object * camera
struct Scene * set
float * waveform_3
float * waveform_2
float * waveform_1
float * vecscope
struct MovieClip * clip
struct Scene * scene
struct Object * scene_camera
struct Mask * mask
struct bSound * sound
bAction * action
bDopeSheet ads
SpaceAction_Runtime runtime
struct MovieClipScopes scopes
struct MovieClip * clip
MaskSpaceInfo mask_info
struct wmOperator * op
struct bDopeSheet * ads
SpaceGraph_Runtime runtime
struct Scopes scopes
MaskSpaceInfo mask_info
struct ImageUser iuser
struct bGPdata * gpd
struct Image * image
struct bDopeSheet * ads
struct ID * from
ListBase treepath
struct bNodeTree * edittree
struct ID * id
struct bNodeTree * nodetree
struct TreeStoreElem search_tse
struct BLI_mempool * treestore
struct Script * script
struct bGPdata * gpd
struct ListBase addons
struct ListBase uistyles
struct ListBase user_keymaps
short edit_studio_light
struct ListBase themes
struct ListBase autoexec_paths
struct ListBase uifonts
struct ListBase user_keyconfig_prefs
struct ListBase user_menus
struct ListBase asset_libraries
char app_template[64]
UserDef_Runtime runtime
unsigned short local_view_uuid
struct Object * camera
struct View3D * localvd
short scenelock
struct Object * ob_center
ListBase object_bases
char name[64]
Wrapper for bScreen.
Object * base_pose_object
Definition: DNA_xr_types.h:25
struct Collection * filter_grp
struct bNodeTree * nodetree
struct bNodeTreePath * next
ListBase areabase
struct IDProperty * prop
struct PointerRNA * ptr
struct WorkSpaceInstanceHook * workspace_hook
XrSessionSettings session_settings
double PIL_check_seconds_timer(void)
Definition: time.c:64
PointerRNA * ptr
Definition: wm_files.c:3480