Blender V4.3
readfile.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2001-2002 NaN Holding BV. All rights reserved.
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
9#include <cctype> /* for isdigit. */
10#include <cerrno>
11#include <climits>
12#include <cstdarg> /* for va_start/end. */
13#include <cstddef> /* for offsetof. */
14#include <cstdlib> /* for atoi. */
15#include <ctime> /* for gmtime. */
16#include <fcntl.h> /* for open flags (O_BINARY, O_RDONLY). */
17
18#include "BLI_utildefines.h"
19#ifndef WIN32
20# include <unistd.h> /* for read close */
21#else
22# include "BLI_winstuff.h"
23# include "winsock2.h"
24# include <io.h> /* for open close read */
25#endif
26
27#include "CLG_log.h"
28
29#include "fmt/format.h"
30
31/* allow readfile to use deprecated functionality */
32#define DNA_DEPRECATED_ALLOW
33
34#include "DNA_anim_types.h"
35#include "DNA_asset_types.h"
36#include "DNA_cachefile_types.h"
39#include "DNA_genfile.h"
40#include "DNA_key_types.h"
41#include "DNA_layer_types.h"
42#include "DNA_node_types.h"
44#include "DNA_sdna_types.h"
45#include "DNA_sound_types.h"
46#include "DNA_vfont_types.h"
47#include "DNA_volume_types.h"
48#include "DNA_workspace_types.h"
49
51#include "MEM_guardedalloc.h"
52
53#include "BLI_blenlib.h"
54#include "BLI_endian_defines.h"
55#include "BLI_endian_switch.h"
56#include "BLI_ghash.h"
57#include "BLI_linklist.h"
58#include "BLI_map.hh"
59#include "BLI_memarena.h"
60#include "BLI_mempool.h"
61#include "BLI_threads.h"
62#include "BLI_time.h"
63
64#include "BLT_translation.hh"
65
66#include "BKE_anim_data.hh"
67#include "BKE_animsys.h"
68#include "BKE_asset.hh"
69#include "BKE_blender_version.h"
70#include "BKE_collection.hh"
71#include "BKE_global.hh" /* for G */
72#include "BKE_idprop.hh"
73#include "BKE_idtype.hh"
74#include "BKE_layer.hh"
75#include "BKE_lib_id.hh"
76#include "BKE_lib_override.hh"
77#include "BKE_lib_query.hh"
78#include "BKE_lib_remap.hh"
79#include "BKE_main.hh" /* for Main */
80#include "BKE_main_idmap.hh"
81#include "BKE_main_namemap.hh"
82#include "BKE_material.h"
83#include "BKE_mesh.hh"
84#include "BKE_modifier.hh"
85#include "BKE_node.hh" /* for tree type defines */
86#include "BKE_object.hh"
87#include "BKE_packedFile.hh"
88#include "BKE_preferences.h"
89#include "BKE_report.hh"
90#include "BKE_scene.hh"
91#include "BKE_screen.hh"
92#include "BKE_undo_system.hh"
93#include "BKE_workspace.hh"
94
95#include "DRW_engine.hh"
96
97#include "DEG_depsgraph.hh"
98
99#include "BLO_blend_defs.hh"
100#include "BLO_blend_validate.hh"
101#include "BLO_read_write.hh"
102#include "BLO_readfile.hh"
103#include "BLO_undofile.hh"
104
105#include "SEQ_iterator.hh"
106#include "SEQ_modifier.hh"
107#include "SEQ_sequencer.hh"
108#include "SEQ_utils.hh"
109
110#include "readfile.hh"
111
112/* Make preferences read-only. */
113#define U (*((const UserDef *)&U))
114
172#define USE_BHEAD_READ_ON_DEMAND
173
175#define USE_GHASH_BHEAD
176
178#define USE_GHASH_RESTORE_POINTER
179
180static CLG_LogRef LOG = {"blo.readfile"};
181static CLG_LogRef LOG_UNDO = {"blo.readfile.undo"};
182
183/* local prototypes */
184static void read_libraries(FileData *basefd, ListBase *mainlist);
185static void *read_struct(FileData *fd, BHead *bh, const char *blockname, const int id_type_index);
186static BHead *find_bhead_from_code_name(FileData *fd, const short idcode, const char *name);
187static BHead *find_bhead_from_idname(FileData *fd, const char *idname);
188
189struct BHeadN {
191#ifdef USE_BHEAD_READ_ON_DEMAND
193 off64_t file_offset;
196#endif
199};
200
201#define BHEADN_FROM_BHEAD(bh) ((BHeadN *)POINTER_OFFSET(bh, -int(offsetof(BHeadN, bhead))))
202
207#define BHEAD_USE_READ_ON_DEMAND(bhead) ((bhead)->code == BLO_CODE_DATA)
208
209/* -------------------------------------------------------------------- */
213void BLO_reportf_wrap(BlendFileReadReport *reports, eReportType type, const char *format, ...)
214{
215 char fixed_buf[1024]; /* should be long enough */
216
217 va_list args;
218
219 va_start(args, format);
220 vsnprintf(fixed_buf, sizeof(fixed_buf), format, args);
221 va_end(args);
222
223 fixed_buf[sizeof(fixed_buf) - 1] = '\0';
224
225 BKE_report(reports->reports, type, fixed_buf);
226
227 if (G.background == 0) {
228 printf("%s: %s\n", BKE_report_type_str(type), fixed_buf);
229 }
230}
231
232/* for reporting linking messages */
234{
235 return lib->runtime.parent ? lib->runtime.parent->runtime.filepath_abs : "<direct>";
236}
237
240/* -------------------------------------------------------------------- */
245 void *newp;
246
248 int nr;
249};
250
254
256{
257 return MEM_new<OldNewMap>(__func__);
258}
259
264static bool oldnewmap_insert(OldNewMap *onm, const void *oldaddr, void *newaddr, int nr)
265{
266 if (oldaddr == nullptr || newaddr == nullptr) {
267 return false;
268 }
269
270 return onm->map.add_overwrite(oldaddr, NewAddress{newaddr, nr});
271}
272
273static void oldnewmap_lib_insert(FileData *fd, const void *oldaddr, ID *newaddr, int id_code)
274{
275 oldnewmap_insert(fd->libmap, oldaddr, newaddr, id_code);
276}
277
278void blo_do_versions_oldnewmap_insert(OldNewMap *onm, const void *oldaddr, void *newaddr, int nr)
279{
280 oldnewmap_insert(onm, oldaddr, newaddr, nr);
281}
282
283static void *oldnewmap_lookup_and_inc(OldNewMap *onm, const void *addr, bool increase_users)
284{
285 NewAddress *entry = onm->map.lookup_ptr(addr);
286 if (entry == nullptr) {
287 return nullptr;
288 }
289 if (increase_users) {
290 entry->nr++;
291 }
292 return entry->newp;
293}
294
295/* for libdata, NewAddress.nr has ID code, no increment */
296static void *oldnewmap_liblookup(OldNewMap *onm, const void *addr, const bool is_linked_only)
297{
298 if (addr == nullptr) {
299 return nullptr;
300 }
301
302 ID *id = static_cast<ID *>(oldnewmap_lookup_and_inc(onm, addr, false));
303 if (id == nullptr) {
304 return nullptr;
305 }
306 if (!is_linked_only || ID_IS_LINKED(id)) {
307 return id;
308 }
309 return nullptr;
310}
311
312static void oldnewmap_clear(OldNewMap *onm)
313{
314 /* Free unused data. */
315 for (NewAddress &new_addr : onm->map.values()) {
316 if (new_addr.nr == 0) {
317 MEM_freeN(new_addr.newp);
318 }
319 }
320 onm->map.clear_and_shrink();
321}
322
323static void oldnewmap_free(OldNewMap *onm)
324{
325 MEM_delete(onm);
326}
327
330/* -------------------------------------------------------------------- */
334static void add_main_to_main(Main *mainvar, Main *from)
335{
336 ListBase *lbarray[INDEX_ID_MAX], *fromarray[INDEX_ID_MAX];
337 int a;
338
339 if (from->is_read_invalid) {
340 mainvar->is_read_invalid = true;
341 }
342
343 set_listbasepointers(mainvar, lbarray);
344 a = set_listbasepointers(from, fromarray);
345 while (a--) {
346 BLI_movelisttolist(lbarray[a], fromarray[a]);
347 }
348}
349
350void blo_join_main(ListBase *mainlist)
351{
352 Main *tojoin, *mainl;
353
354 mainl = static_cast<Main *>(mainlist->first);
355
356 if (mainl->id_map != nullptr) {
357 /* Cannot keep this since we add some IDs from joined mains. */
359 mainl->id_map = nullptr;
360 }
361
362 /* Will no longer be valid after joining. */
364
365 while ((tojoin = mainl->next)) {
367 tojoin->is_asset_edit_file);
368 add_main_to_main(mainl, tojoin);
369 BLI_remlink(mainlist, tojoin);
370 tojoin->next = tojoin->prev = nullptr;
371 BKE_main_free(tojoin);
372 }
373}
374
375static void split_libdata(ListBase *lb_src, Main **lib_main_array, const uint lib_main_array_len)
376{
377 for (ID *id = static_cast<ID *>(lb_src->first), *idnext; id; id = idnext) {
378 idnext = static_cast<ID *>(id->next);
379
380 if (id->lib) {
381 if ((uint(id->lib->runtime.temp_index) < lib_main_array_len) &&
382 /* this check should never fail, just in case 'id->lib' is a dangling pointer. */
383 (lib_main_array[id->lib->runtime.temp_index]->curlib == id->lib))
384 {
385 Main *mainvar = lib_main_array[id->lib->runtime.temp_index];
386 ListBase *lb_dst = which_libbase(mainvar, GS(id->name));
387 BLI_remlink(lb_src, id);
388 BLI_addtail(lb_dst, id);
389 }
390 else {
391 CLOG_ERROR(&LOG, "Invalid library for '%s'", id->name);
392 }
393 }
394 }
395}
396
398{
399 mainlist->first = mainlist->last = main;
400 main->next = nullptr;
401
402 if (BLI_listbase_is_empty(&main->libraries)) {
403 return;
404 }
405
406 if (main->id_map != nullptr) {
407 /* Cannot keep this since we remove some IDs from given main. */
409 main->id_map = nullptr;
410 }
411
412 /* Will no longer be valid after splitting. */
414
415 /* (Library.temp_index -> Main), lookup table */
416 const uint lib_main_array_len = BLI_listbase_count(&main->libraries);
417 Main **lib_main_array = static_cast<Main **>(
418 MEM_malloc_arrayN(lib_main_array_len, sizeof(*lib_main_array), __func__));
419
420 int i = 0;
421 for (Library *lib = static_cast<Library *>(main->libraries.first); lib;
422 lib = static_cast<Library *>(lib->id.next), i++)
423 {
424 Main *libmain = BKE_main_new();
425 libmain->curlib = lib;
426 libmain->versionfile = lib->runtime.versionfile;
427 libmain->subversionfile = lib->runtime.subversionfile;
430 libmain->is_asset_edit_file = (lib->runtime.tag & LIBRARY_IS_ASSET_EDIT_FILE) != 0;
431 BLI_addtail(mainlist, libmain);
432 lib->runtime.temp_index = i;
433 lib_main_array[i] = libmain;
434 }
435
436 ListBase *lbarray[INDEX_ID_MAX];
437 i = set_listbasepointers(main, lbarray);
438 while (i--) {
439 ID *id = static_cast<ID *>(lbarray[i]->first);
440 if (id == nullptr || GS(id->name) == ID_LI) {
441 /* No ID_LI data-block should ever be linked anyway, but just in case, better be explicit. */
442 continue;
443 }
444 split_libdata(lbarray[i], lib_main_array, lib_main_array_len);
445 }
446
447 MEM_freeN(lib_main_array);
448}
449
451{
452 BHead *bhead;
453
454 for (bhead = blo_bhead_first(fd); bhead; bhead = blo_bhead_next(fd, bhead)) {
455 if (bhead->code == BLO_CODE_GLOB) {
456 FileGlobal *fg = static_cast<FileGlobal *>(
457 read_struct(fd, bhead, "Data from Global block", INDEX_ID_NULL));
458 if (fg) {
459 main->subversionfile = fg->subversion;
460 main->minversionfile = fg->minversion;
461 main->minsubversionfile = fg->minsubversion;
462 main->is_asset_edit_file = (fg->fileflags & G_FILE_ASSET_EDIT_FILE) != 0;
463 MEM_freeN(fg);
464 }
465 else if (bhead->code == BLO_CODE_ENDB) {
466 break;
467 }
468 }
469 }
470 if (main->curlib) {
471 main->curlib->runtime.versionfile = main->versionfile;
472 main->curlib->runtime.subversionfile = main->subversionfile;
474 main->curlib->runtime.tag, main->is_asset_edit_file, LIBRARY_IS_ASSET_EDIT_FILE);
475 }
476}
477
478static bool blo_bhead_is_id(const BHead *bhead)
479{
480 /* BHead codes are four bytes (like 'ENDB', 'TEST', etc.), but if the two most-significant bytes
481 * are zero, the values actually indicate an ID type. */
482 return bhead->code <= 0xFFFF;
483}
484
485static bool blo_bhead_is_id_valid_type(const BHead *bhead)
486{
487 if (!blo_bhead_is_id(bhead)) {
488 return false;
489 }
490
491 const short id_type_code = bhead->code & 0xFFFF;
492 return BKE_idtype_idcode_is_valid(id_type_code);
493}
494
495#ifdef USE_GHASH_BHEAD
497{
498 BHead *bhead;
499
500 /* dummy values */
501 bool is_link = false;
502 int code_prev = BLO_CODE_ENDB;
503 uint reserve = 0;
504
505 for (bhead = blo_bhead_first(fd); bhead; bhead = blo_bhead_next(fd, bhead)) {
506 if (code_prev != bhead->code) {
507 code_prev = bhead->code;
508 is_link = blo_bhead_is_id_valid_type(bhead) ?
509 BKE_idtype_idcode_is_linkable(short(code_prev)) :
510 false;
511 }
512
513 if (is_link) {
514 reserve += 1;
515 }
516 }
517
518 BLI_assert(fd->bhead_idname_hash == nullptr);
519
520 fd->bhead_idname_hash = BLI_ghash_str_new_ex(__func__, reserve);
521
522 for (bhead = blo_bhead_first(fd); bhead; bhead = blo_bhead_next(fd, bhead)) {
523 if (code_prev != bhead->code) {
524 code_prev = bhead->code;
525 is_link = blo_bhead_is_id_valid_type(bhead) ?
526 BKE_idtype_idcode_is_linkable(short(code_prev)) :
527 false;
528 }
529
530 if (is_link) {
531 BLI_ghash_insert(fd->bhead_idname_hash, (void *)blo_bhead_id_name(fd, bhead), bhead);
532 }
533 }
534}
535#endif
536
537static Main *blo_find_main(FileData *fd, const char *filepath, const char *relabase)
538{
539 ListBase *mainlist = fd->mainlist;
540 Main *m;
541 Library *lib;
542 char filepath_abs[FILE_MAX];
543
544 STRNCPY(filepath_abs, filepath);
545 BLI_path_abs(filepath_abs, relabase);
546 BLI_path_normalize(filepath_abs);
547
548 // printf("blo_find_main: relabase %s\n", relabase);
549 // printf("blo_find_main: original in %s\n", filepath);
550 // printf("blo_find_main: converted to %s\n", filepath_abs);
551
552 LISTBASE_FOREACH (Main *, m, mainlist) {
553 const char *libname = (m->curlib) ? m->curlib->runtime.filepath_abs : m->filepath;
554
555 if (BLI_path_cmp(filepath_abs, libname) == 0) {
556 if (G.debug & G_DEBUG) {
557 CLOG_INFO(&LOG, 3, "Found library %s", libname);
558 }
559 return m;
560 }
561 }
562
563 m = BKE_main_new();
564 BLI_addtail(mainlist, m);
565
566 /* Add library data-block itself to 'main' Main, since libraries are **never** linked data.
567 * Fixes bug where you could end with all ID_LI data-blocks having the same name... */
568 lib = static_cast<Library *>(BKE_libblock_alloc(
569 static_cast<Main *>(mainlist->first), ID_LI, BLI_path_basename(filepath), 0));
570
571 /* Important, consistency with main ID reading code from read_libblock(). */
572 lib->id.us = ID_FAKE_USERS(lib);
573
574 /* Matches direct_link_library(). */
576
577 STRNCPY(lib->filepath, filepath);
578 STRNCPY(lib->runtime.filepath_abs, filepath_abs);
579
580 m->curlib = lib;
581
582 read_file_version(fd, m);
583
584 if (G.debug & G_DEBUG) {
585 CLOG_INFO(&LOG, 3, "Added new lib %s", filepath);
586 }
587 return m;
588}
589
590void blo_readfile_invalidate(FileData *fd, Main *bmain, const char *message)
591{
592 /* Tag given `bmain`, and 'root 'local' main one (in case given one is a library one) as invalid.
593 */
594 bmain->is_read_invalid = true;
595 for (; bmain->prev != nullptr; bmain = bmain->prev) {
596 /* Pass. */
597 }
598 bmain->is_read_invalid = true;
599
601 RPT_ERROR,
602 "A critical error happened (the blend file is likely corrupted): %s",
603 message);
604}
605
608/* -------------------------------------------------------------------- */
621
626
627static void switch_endian_bh4(BHead4 *bhead)
628{
629 /* the ID_.. codes */
630 if ((bhead->code & 0xFFFF) == 0) {
631 bhead->code >>= 16;
632 }
633
634 if (bhead->code != BLO_CODE_ENDB) {
638 }
639}
640
641static void switch_endian_bh8(BHead8 *bhead)
642{
643 /* the ID_.. codes */
644 if ((bhead->code & 0xFFFF) == 0) {
645 bhead->code >>= 16;
646 }
647
648 if (bhead->code != BLO_CODE_ENDB) {
652 }
653}
654
655static void bh4_from_bh8(BHead *bhead, BHead8 *bhead8, bool do_endian_swap)
656{
657 BHead4 *bhead4 = (BHead4 *)bhead;
658 int64_t old;
659
660 bhead4->code = bhead8->code;
661 bhead4->len = bhead8->len;
662
663 if (bhead4->code != BLO_CODE_ENDB) {
664 /* perform a endian swap on 64bit pointers, otherwise the pointer might map to zero
665 * 0x0000000000000000000012345678 would become 0x12345678000000000000000000000000
666 */
667 if (do_endian_swap) {
669 }
670
671 /* this patch is to avoid `intptr_t` being read from not-eight aligned positions
672 * is necessary on any modern 64bit architecture) */
673 memcpy(&old, &bhead8->old, 8);
674 bhead4->old = int(old >> 3);
675
676 bhead4->SDNAnr = bhead8->SDNAnr;
677 bhead4->nr = bhead8->nr;
678 }
679}
680
681static void bh8_from_bh4(BHead *bhead, BHead4 *bhead4)
682{
683 BHead8 *bhead8 = (BHead8 *)bhead;
684
685 bhead8->code = bhead4->code;
686 bhead8->len = bhead4->len;
687
688 if (bhead8->code != BLO_CODE_ENDB) {
689 bhead8->old = bhead4->old;
690 bhead8->SDNAnr = bhead4->SDNAnr;
691 bhead8->nr = bhead4->nr;
692 }
693}
694
696{
697 BHeadN *new_bhead = nullptr;
698 int64_t readsize;
699
700 if (fd) {
701 if (!fd->is_eof) {
702 /* initializing to zero isn't strictly needed but shuts valgrind up
703 * since uninitialized memory gets compared */
704 BHead8 bhead8 = {0};
705 BHead4 bhead4 = {0};
706 BHead bhead = {0};
707
708 /* First read the bhead structure.
709 * Depending on the platform the file was written on this can
710 * be a big or little endian BHead4 or BHead8 structure.
711 *
712 * As usual 'ENDB' (the last *partial* bhead of the file)
713 * needs some special handling. We don't want to EOF just yet.
714 */
716 bhead4.code = BLO_CODE_DATA;
717 readsize = fd->file->read(fd->file, &bhead4, sizeof(bhead4));
718
719 if (readsize == sizeof(bhead4) || bhead4.code == BLO_CODE_ENDB) {
720 if (fd->flags & FD_FLAGS_SWITCH_ENDIAN) {
721 switch_endian_bh4(&bhead4);
722 }
723
725 bh8_from_bh4(&bhead, &bhead4);
726 }
727 else {
728 /* std::min is only to quiet '-Warray-bounds' compiler warning. */
729 BLI_assert(sizeof(bhead) == sizeof(bhead4));
730 memcpy(&bhead, &bhead4, std::min(sizeof(bhead), sizeof(bhead4)));
731 }
732 }
733 else {
734 fd->is_eof = true;
735 bhead.len = 0;
736 }
737 }
738 else {
739 bhead8.code = BLO_CODE_DATA;
740 readsize = fd->file->read(fd->file, &bhead8, sizeof(bhead8));
741
742 if (readsize == sizeof(bhead8) || bhead8.code == BLO_CODE_ENDB) {
743 if (fd->flags & FD_FLAGS_SWITCH_ENDIAN) {
744 switch_endian_bh8(&bhead8);
745 }
746
748 bh4_from_bh8(&bhead, &bhead8, (fd->flags & FD_FLAGS_SWITCH_ENDIAN) != 0);
749 }
750 else {
751 /* std::min is only to quiet `-Warray-bounds` compiler warning. */
752 BLI_assert(sizeof(bhead) == sizeof(bhead8));
753 memcpy(&bhead, &bhead8, std::min(sizeof(bhead), sizeof(bhead8)));
754 }
755 }
756 else {
757 fd->is_eof = true;
758 bhead.len = 0;
759 }
760 }
761
762 /* make sure people are not trying to pass bad blend files */
763 if (bhead.len < 0) {
764 fd->is_eof = true;
765 }
766
767 /* bhead now contains the (converted) bhead structure. Now read
768 * the associated data and put everything in a BHeadN (creative naming !)
769 */
770 if (fd->is_eof) {
771 /* pass */
772 }
773#ifdef USE_BHEAD_READ_ON_DEMAND
774 else if (fd->file->seek != nullptr && BHEAD_USE_READ_ON_DEMAND(&bhead)) {
775 /* Delay reading bhead content. */
776 new_bhead = static_cast<BHeadN *>(MEM_mallocN(sizeof(BHeadN), "new_bhead"));
777 if (new_bhead) {
778 new_bhead->next = new_bhead->prev = nullptr;
779 new_bhead->file_offset = fd->file->offset;
780 new_bhead->has_data = false;
781 new_bhead->is_memchunk_identical = false;
782 new_bhead->bhead = bhead;
783 const off64_t seek_new = fd->file->seek(fd->file, bhead.len, SEEK_CUR);
784 if (UNLIKELY(seek_new == -1)) {
785 fd->is_eof = true;
786 MEM_freeN(new_bhead);
787 new_bhead = nullptr;
788 }
789 else {
790 BLI_assert(fd->file->offset == seek_new);
791 }
792 }
793 else {
794 fd->is_eof = true;
795 }
796 }
797#endif
798 else {
799 new_bhead = static_cast<BHeadN *>(
800 MEM_mallocN(sizeof(BHeadN) + size_t(bhead.len), "new_bhead"));
801 if (new_bhead) {
802 new_bhead->next = new_bhead->prev = nullptr;
803#ifdef USE_BHEAD_READ_ON_DEMAND
804 new_bhead->file_offset = 0; /* don't seek. */
805 new_bhead->has_data = true;
806#endif
807 new_bhead->is_memchunk_identical = false;
808 new_bhead->bhead = bhead;
809
810 readsize = fd->file->read(fd->file, new_bhead + 1, size_t(bhead.len));
811
812 if (readsize != bhead.len) {
813 fd->is_eof = true;
814 MEM_freeN(new_bhead);
815 new_bhead = nullptr;
816 }
817
818 if (fd->flags & FD_FLAGS_IS_MEMFILE) {
819 new_bhead->is_memchunk_identical = ((UndoReader *)fd->file)->memchunk_identical;
820 }
821 }
822 else {
823 fd->is_eof = true;
824 }
825 }
826 }
827 }
828
829 /* We've read a new block. Now add it to the list
830 * of blocks.
831 */
832 if (new_bhead) {
833 BLI_addtail(&fd->bhead_list, new_bhead);
834 }
835
836 return new_bhead;
837}
838
840{
841 BHeadN *new_bhead;
842 BHead *bhead = nullptr;
843
844 /* Rewind the file
845 * Read in a new block if necessary
846 */
847 new_bhead = static_cast<BHeadN *>(fd->bhead_list.first);
848 if (new_bhead == nullptr) {
849 new_bhead = get_bhead(fd);
850 }
851
852 if (new_bhead) {
853 bhead = &new_bhead->bhead;
854 }
855
856 return bhead;
857}
858
859BHead *blo_bhead_prev(FileData * /*fd*/, BHead *thisblock)
860{
861 BHeadN *bheadn = BHEADN_FROM_BHEAD(thisblock);
862 BHeadN *prev = bheadn->prev;
863
864 return (prev) ? &prev->bhead : nullptr;
865}
866
868{
869 BHeadN *new_bhead = nullptr;
870 BHead *bhead = nullptr;
871
872 if (thisblock) {
873 /* bhead is actually a sub part of BHeadN
874 * We calculate the BHeadN pointer from the BHead pointer below */
875 new_bhead = BHEADN_FROM_BHEAD(thisblock);
876
877 /* get the next BHeadN. If it doesn't exist we read in the next one */
878 new_bhead = new_bhead->next;
879 if (new_bhead == nullptr) {
880 new_bhead = get_bhead(fd);
881 }
882 }
883
884 if (new_bhead) {
885 /* here we do the reverse:
886 * go from the BHeadN pointer to the BHead pointer */
887 bhead = &new_bhead->bhead;
888 }
889
890 return bhead;
891}
892
893#ifdef USE_BHEAD_READ_ON_DEMAND
894static bool blo_bhead_read_data(FileData *fd, BHead *thisblock, void *buf)
895{
896 bool success = true;
897 BHeadN *new_bhead = BHEADN_FROM_BHEAD(thisblock);
898 BLI_assert(new_bhead->has_data == false && new_bhead->file_offset != 0);
899 off64_t offset_backup = fd->file->offset;
900 if (UNLIKELY(fd->file->seek(fd->file, new_bhead->file_offset, SEEK_SET) == -1)) {
901 success = false;
902 }
903 else {
904 if (fd->file->read(fd->file, buf, size_t(new_bhead->bhead.len)) != new_bhead->bhead.len) {
905 success = false;
906 }
907 if (fd->flags & FD_FLAGS_IS_MEMFILE) {
908 new_bhead->is_memchunk_identical = ((UndoReader *)fd->file)->memchunk_identical;
909 }
910 }
911 if (fd->file->seek(fd->file, offset_backup, SEEK_SET) == -1) {
912 success = false;
913 }
914 return success;
915}
916
917static BHead *blo_bhead_read_full(FileData *fd, BHead *thisblock)
918{
919 BHeadN *new_bhead = BHEADN_FROM_BHEAD(thisblock);
920 BHeadN *new_bhead_data = static_cast<BHeadN *>(
921 MEM_mallocN(sizeof(BHeadN) + new_bhead->bhead.len, "new_bhead"));
922 new_bhead_data->bhead = new_bhead->bhead;
923 new_bhead_data->file_offset = new_bhead->file_offset;
924 new_bhead_data->has_data = true;
925 new_bhead_data->is_memchunk_identical = false;
926 if (!blo_bhead_read_data(fd, thisblock, new_bhead_data + 1)) {
927 MEM_freeN(new_bhead_data);
928 return nullptr;
929 }
930 return &new_bhead_data->bhead;
931}
932#endif /* USE_BHEAD_READ_ON_DEMAND */
933
934const char *blo_bhead_id_name(const FileData *fd, const BHead *bhead)
935{
936 return (const char *)POINTER_OFFSET(bhead, sizeof(*bhead) + fd->id_name_offset);
937}
938
940{
942 return (fd->id_asset_data_offset >= 0) ?
943 *(AssetMetaData **)POINTER_OFFSET(bhead, sizeof(*bhead) + fd->id_asset_data_offset) :
944 nullptr;
945}
946
948{
949 char header[SIZEOFBLENDERHEADER], num[4];
950 int64_t readsize;
951
952 /* read in the header data */
953 readsize = fd->file->read(fd->file, header, sizeof(header));
954
955 if (readsize == sizeof(header) && STREQLEN(header, "BLENDER", 7) && ELEM(header[7], '_', '-') &&
956 ELEM(header[8], 'v', 'V') &&
957 (isdigit(header[9]) && isdigit(header[10]) && isdigit(header[11])))
958 {
959 fd->flags |= FD_FLAGS_FILE_OK;
960
961 /* what size are pointers in the file ? */
962 if (header[7] == '_') {
964 if (sizeof(void *) != 4) {
966 }
967 }
968 else {
969 if (sizeof(void *) != 8) {
971 }
972 }
973
974 /* is the file saved in a different endian
975 * than we need ?
976 */
977 if (((header[8] == 'v') ? L_ENDIAN : B_ENDIAN) != ENDIAN_ORDER) {
979 }
980
981 /* get the version number */
982 memcpy(num, header + 9, 3);
983 num[3] = 0;
984 fd->fileversion = atoi(num);
985 }
986 else if (STREQLEN(header, "BLENDER", 7)) {
987 /* If the first 7 bytes are BLENDER, it is very likely that this is a newer version of the
988 * blendfile format. Unreadable currently, but avoid telling the user that this is not a blend
989 * file. */
991 }
992}
993
997static bool read_file_dna(FileData *fd, const char **r_error_message)
998{
999 BHead *bhead;
1000 int subversion = 0;
1001
1002 for (bhead = blo_bhead_first(fd); bhead; bhead = blo_bhead_next(fd, bhead)) {
1003 if (bhead->code == BLO_CODE_GLOB) {
1004 /* Before this, the subversion didn't exist in 'FileGlobal' so the subversion
1005 * value isn't accessible for the purpose of DNA versioning in this case. */
1006 if (fd->fileversion <= 242) {
1007 continue;
1008 }
1009 /* We can't use read_global because this needs 'DNA1' to be decoded,
1010 * however the first 4 chars are _always_ the subversion. */
1011 const FileGlobal *fg = reinterpret_cast<const FileGlobal *>(&bhead[1]);
1012 BLI_STATIC_ASSERT(offsetof(FileGlobal, subvstr) == 0, "Must be first: subvstr")
1013 char num[5];
1014 memcpy(num, fg->subvstr, 4);
1015 num[4] = 0;
1016 subversion = atoi(num);
1017 }
1018 else if (bhead->code == BLO_CODE_DNA1) {
1019 const bool do_endian_swap = (fd->flags & FD_FLAGS_SWITCH_ENDIAN) != 0;
1020 const bool do_alias = false; /* Postpone until after #blo_do_versions_dna runs. */
1022 &bhead[1], bhead->len, do_endian_swap, true, do_alias, r_error_message);
1023 if (fd->filesdna) {
1024 blo_do_versions_dna(fd->filesdna, fd->fileversion, subversion);
1025 /* Allow aliased lookups (must be after version patching DNA). */
1027
1030 fd->filesdna, fd->memsdna, fd->compflags);
1031 /* used to retrieve ID names from (bhead+1) */
1033 fd->filesdna, "ID", "char", "name[]");
1034 BLI_assert(fd->id_name_offset != -1);
1036 fd->filesdna, "ID", "AssetMetaData", "*asset_data");
1037
1038 return true;
1039 }
1040
1041 return false;
1042 }
1043 else if (bhead->code == BLO_CODE_ENDB) {
1044 break;
1045 }
1046 }
1047
1048 *r_error_message = "Missing DNA block";
1049 return false;
1050}
1051
1053{
1054 BHead *bhead;
1055 int *blend_thumb = nullptr;
1056
1057 for (bhead = blo_bhead_first(fd); bhead; bhead = blo_bhead_next(fd, bhead)) {
1058 if (bhead->code == BLO_CODE_TEST) {
1059 const bool do_endian_swap = (fd->flags & FD_FLAGS_SWITCH_ENDIAN) != 0;
1060 int *data = (int *)(bhead + 1);
1061
1062 if (bhead->len < sizeof(int[2])) {
1063 break;
1064 }
1065
1066 if (do_endian_swap) {
1067 BLI_endian_switch_int32(&data[0]);
1068 BLI_endian_switch_int32(&data[1]);
1069 }
1070
1071 const int width = data[0];
1072 const int height = data[1];
1073 if (!BLEN_THUMB_MEMSIZE_IS_VALID(width, height)) {
1074 break;
1075 }
1076 if (bhead->len < BLEN_THUMB_MEMSIZE_FILE(width, height)) {
1077 break;
1078 }
1079
1080 blend_thumb = data;
1081 break;
1082 }
1083 if (bhead->code != BLO_CODE_REND) {
1084 /* Thumbnail is stored in TEST immediately after first REND... */
1085 break;
1086 }
1087 }
1088
1089 return blend_thumb;
1090}
1091
1094/* -------------------------------------------------------------------- */
1099{
1100 BLI_assert(reports != nullptr);
1101
1102 FileData *fd = static_cast<FileData *>(MEM_callocN(sizeof(FileData), "FileData"));
1103
1105
1106 fd->datamap = oldnewmap_new();
1107 fd->globmap = oldnewmap_new();
1108 fd->libmap = oldnewmap_new();
1109
1110 fd->reports = reports;
1111
1112 return fd;
1113}
1114
1121{
1122 BLI_assert(fd->filesdna != nullptr);
1123 for (BHead *bhead = blo_bhead_first(fd); bhead; bhead = blo_bhead_next(fd, bhead)) {
1124 if (bhead->code != BLO_CODE_GLOB) {
1125 continue;
1126 }
1127
1128 FileGlobal *fg = static_cast<FileGlobal *>(
1129 read_struct(fd, bhead, "Data from Global block", INDEX_ID_NULL));
1130 if ((fg->minversion > BLENDER_FILE_VERSION) ||
1132 {
1133 char writer_ver_str[16];
1134 char min_reader_ver_str[16];
1135 if (fd->fileversion == fg->minversion) {
1137 writer_ver_str, sizeof(writer_ver_str), short(fd->fileversion), fg->subversion);
1139 min_reader_ver_str, sizeof(min_reader_ver_str), fg->minversion, fg->minsubversion);
1140 }
1141 else {
1143 writer_ver_str, sizeof(writer_ver_str), short(fd->fileversion), -1);
1145 min_reader_ver_str, sizeof(min_reader_ver_str), fg->minversion, -1);
1146 }
1147 BKE_reportf(reports,
1148 RPT_ERROR,
1149 "The file was saved by a newer version, open it with Blender %s or later",
1150 min_reader_ver_str);
1151 CLOG_WARN(&LOG,
1152 "%s: File saved by a newer version of Blender (%s), Blender %s or later is "
1153 "needed to open it.",
1154 fd->relabase,
1155 writer_ver_str,
1156 min_reader_ver_str);
1157 MEM_freeN(fg);
1158 return true;
1159 }
1160 MEM_freeN(fg);
1161 return false;
1162 }
1163 return false;
1164}
1165
1167{
1169
1170 if (fd->flags & FD_FLAGS_FILE_OK) {
1171 const char *error_message = nullptr;
1172 if (read_file_dna(fd, &error_message) == false) {
1174 reports, RPT_ERROR, "Failed to read blend file '%s': %s", fd->relabase, error_message);
1176 fd = nullptr;
1177 }
1178 else if (is_minversion_older_than_blender(fd, reports)) {
1180 fd = nullptr;
1181 }
1182 }
1183 else if (fd->flags & FD_FLAGS_FILE_FUTURE) {
1185 reports,
1186 RPT_ERROR,
1187 "Cannot read blend file '%s', incomplete header, may be from a newer version of Blender",
1188 fd->relabase);
1190 fd = nullptr;
1191 }
1192 else {
1193 BKE_reportf(reports, RPT_ERROR, "Failed to read file '%s', not a blend file", fd->relabase);
1195 fd = nullptr;
1196 }
1197
1198 return fd;
1199}
1200
1201static FileData *blo_filedata_from_file_descriptor(const char *filepath,
1202 BlendFileReadReport *reports,
1203 int filedes)
1204{
1205 char header[7];
1206 FileReader *rawfile = BLI_filereader_new_file(filedes);
1207 FileReader *file = nullptr;
1208
1209 errno = 0;
1210 /* If opening the file failed or we can't read the header, give up. */
1211 if (rawfile == nullptr || rawfile->read(rawfile, header, sizeof(header)) != sizeof(header)) {
1212 BKE_reportf(reports->reports,
1214 "Unable to read '%s': %s",
1215 filepath,
1216 errno ? strerror(errno) : RPT_("insufficient content"));
1217 if (rawfile) {
1218 rawfile->close(rawfile);
1219 }
1220 else {
1221 close(filedes);
1222 }
1223 return nullptr;
1224 }
1225
1226 /* Rewind the file after reading the header. */
1227 rawfile->seek(rawfile, 0, SEEK_SET);
1228
1229 /* Check if we have a regular file. */
1230 if (memcmp(header, "BLENDER", sizeof(header)) == 0) {
1231 /* Try opening the file with memory-mapped IO. */
1232 file = BLI_filereader_new_mmap(filedes);
1233 if (file == nullptr) {
1234 /* `mmap` failed, so just keep using `rawfile`. */
1235 file = rawfile;
1236 rawfile = nullptr;
1237 }
1238 }
1239 else if (BLI_file_magic_is_gzip(header)) {
1240 file = BLI_filereader_new_gzip(rawfile);
1241 if (file != nullptr) {
1242 rawfile = nullptr; /* The `Gzip` #FileReader takes ownership of `rawfile`. */
1243 }
1244 }
1245 else if (BLI_file_magic_is_zstd(header)) {
1246 file = BLI_filereader_new_zstd(rawfile);
1247 if (file != nullptr) {
1248 rawfile = nullptr; /* The `Zstd` #FileReader takes ownership of `rawfile`. */
1249 }
1250 }
1251
1252 /* Clean up `rawfile` if it wasn't taken over. */
1253 if (rawfile != nullptr) {
1254 rawfile->close(rawfile);
1255 }
1256 if (file == nullptr) {
1257 BKE_reportf(reports->reports, RPT_WARNING, "Unrecognized file format '%s'", filepath);
1258 return nullptr;
1259 }
1260
1261 FileData *fd = filedata_new(reports);
1262 fd->file = file;
1263
1264 return fd;
1265}
1266
1267static FileData *blo_filedata_from_file_open(const char *filepath, BlendFileReadReport *reports)
1268{
1269 errno = 0;
1270 const int file = BLI_open(filepath, O_BINARY | O_RDONLY, 0);
1271 if (file == -1) {
1272 BKE_reportf(reports->reports,
1274 "Unable to open '%s': %s",
1275 filepath,
1276 errno ? strerror(errno) : RPT_("unknown error reading file"));
1277 return nullptr;
1278 }
1279 return blo_filedata_from_file_descriptor(filepath, reports, file);
1280}
1281
1283{
1284 FileData *fd = blo_filedata_from_file_open(filepath, reports);
1285 if (fd != nullptr) {
1286 /* needed for library_append and read_libraries */
1287 STRNCPY(fd->relabase, filepath);
1288
1289 return blo_decode_and_check(fd, reports->reports);
1290 }
1291 return nullptr;
1292}
1293
1298static FileData *blo_filedata_from_file_minimal(const char *filepath)
1299{
1300 BlendFileReadReport read_report{};
1301 FileData *fd = blo_filedata_from_file_open(filepath, &read_report);
1302 if (fd != nullptr) {
1304 if (fd->flags & FD_FLAGS_FILE_OK) {
1305 return fd;
1306 }
1308 }
1309 return nullptr;
1310}
1311
1312FileData *blo_filedata_from_memory(const void *mem, int memsize, BlendFileReadReport *reports)
1313{
1314 if (!mem || memsize < SIZEOFBLENDERHEADER) {
1315 BKE_report(
1316 reports->reports, RPT_WARNING, (mem) ? RPT_("Unable to read") : RPT_("Unable to open"));
1317 return nullptr;
1318 }
1319
1320 FileReader *mem_file = BLI_filereader_new_memory(mem, memsize);
1321 FileReader *file = mem_file;
1322
1323 if (BLI_file_magic_is_gzip(static_cast<const char *>(mem))) {
1324 file = BLI_filereader_new_gzip(mem_file);
1325 }
1326 else if (BLI_file_magic_is_zstd(static_cast<const char *>(mem))) {
1327 file = BLI_filereader_new_zstd(mem_file);
1328 }
1329
1330 if (file == nullptr) {
1331 /* Compression initialization failed. */
1332 mem_file->close(mem_file);
1333 return nullptr;
1334 }
1335
1336 FileData *fd = filedata_new(reports);
1337 fd->file = file;
1338
1339 return blo_decode_and_check(fd, reports->reports);
1340}
1341
1344 BlendFileReadReport *reports)
1345{
1346 if (!memfile) {
1347 BKE_report(reports->reports, RPT_WARNING, "Unable to open blend <memory>");
1348 return nullptr;
1349 }
1350
1351 FileData *fd = filedata_new(reports);
1352 fd->file = BLO_memfile_new_filereader(memfile, params->undo_direction);
1353 fd->undo_direction = params->undo_direction;
1355
1356 return blo_decode_and_check(fd, reports->reports);
1357}
1358
1360{
1361 /* Free all BHeadN data blocks */
1362#ifdef NDEBUG
1364#else
1365 /* Sanity check we're not keeping memory we don't need. */
1366 LISTBASE_FOREACH_MUTABLE (BHeadN *, new_bhead, &fd->bhead_list) {
1367# ifdef USE_BHEAD_READ_ON_DEMAND
1368 if (fd->file->seek != nullptr && BHEAD_USE_READ_ON_DEMAND(&new_bhead->bhead)) {
1369 BLI_assert(new_bhead->has_data == 0);
1370 }
1371# endif
1372 MEM_freeN(new_bhead);
1373 }
1374#endif
1375 fd->file->close(fd->file);
1376
1377 if (fd->filesdna) {
1379 }
1380 if (fd->compflags) {
1381 MEM_freeN((void *)fd->compflags);
1382 }
1383 if (fd->reconstruct_info) {
1385 }
1386
1387 if (fd->datamap) {
1389 }
1390 if (fd->globmap) {
1392 }
1393 if (fd->libmap) {
1395 }
1396 if (fd->old_idmap_uid != nullptr) {
1398 }
1399 if (fd->new_idmap_uid != nullptr) {
1401 }
1403 if (fd->bheadmap) {
1404 MEM_freeN(fd->bheadmap);
1405 }
1406
1407#ifdef USE_GHASH_BHEAD
1408 if (fd->bhead_idname_hash) {
1409 BLI_ghash_free(fd->bhead_idname_hash, nullptr, nullptr);
1410 }
1411#endif
1412
1413 MEM_freeN(fd);
1414}
1415
1418/* -------------------------------------------------------------------- */
1423{
1424 BlendThumbnail *data = nullptr;
1425
1427 if (fd) {
1428 if (const int *fd_data = read_file_thumbnail(fd)) {
1429 const int width = fd_data[0];
1430 const int height = fd_data[1];
1431 if (BLEN_THUMB_MEMSIZE_IS_VALID(width, height)) {
1432 const size_t data_size = BLEN_THUMB_MEMSIZE(width, height);
1433 data = static_cast<BlendThumbnail *>(MEM_mallocN(data_size, __func__));
1434 if (data) {
1435 BLI_assert((data_size - sizeof(*data)) ==
1436 (BLEN_THUMB_MEMSIZE_FILE(width, height) - (sizeof(*fd_data) * 2)));
1437 data->width = width;
1438 data->height = height;
1439 memcpy(data->rect, &fd_data[2], data_size - sizeof(*data));
1440 }
1441 }
1442 }
1444 }
1445
1446 return data;
1447}
1448
1449short BLO_version_from_file(const char *filepath)
1450{
1451 short version = 0;
1453 if (fd) {
1454 version = fd->fileversion;
1456 }
1457 return version;
1458}
1459
1462/* -------------------------------------------------------------------- */
1466/* Only direct data-blocks. */
1467static void *newdataadr(FileData *fd, const void *adr)
1468{
1469 return oldnewmap_lookup_and_inc(fd->datamap, adr, true);
1470}
1471
1472/* Only direct data-blocks. */
1473static void *newdataadr_no_us(FileData *fd, const void *adr)
1474{
1475 return oldnewmap_lookup_and_inc(fd->datamap, adr, false);
1476}
1477
1479{
1480 return oldnewmap_lookup_and_inc(fd->globmap, adr, true);
1481}
1482
1483/* only lib data */
1484static void *newlibadr(FileData *fd, ID * /*self_id*/, const bool is_linked_only, const void *adr)
1485{
1486 return oldnewmap_liblookup(fd->libmap, adr, is_linked_only);
1487}
1488
1490 ID *self_id,
1491 const bool is_linked_only,
1492 const void *adr)
1493{
1494 return newlibadr(fd, self_id, is_linked_only, adr);
1495}
1496
1497/* increases user number */
1499 const void *old,
1500 void *newp)
1501{
1502 for (NewAddress &entry : fd->libmap->map.values()) {
1503 if (old == entry.newp && entry.nr == ID_LINK_PLACEHOLDER) {
1504 entry.newp = newp;
1505 if (newp) {
1506 entry.nr = GS(((ID *)newp)->name);
1507 }
1508 }
1509 }
1510}
1511
1513 FileData *basefd,
1514 void *old,
1515 void *newp)
1516{
1517 LISTBASE_FOREACH (Main *, mainptr, mainlist) {
1518 FileData *fd;
1519
1520 if (mainptr->curlib) {
1521 fd = mainptr->curlib->runtime.filedata;
1522 }
1523 else {
1524 fd = basefd;
1525 }
1526
1527 if (fd) {
1529 }
1530 }
1531}
1532
1534{
1535 if (fd->old_idmap_uid != nullptr) {
1537 }
1538 fd->old_idmap_uid = BKE_main_idmap_create(bmain, false, nullptr, MAIN_IDMAP_TYPE_UID);
1539}
1540
1545
1550
1553 ID *id, const IDCacheKey *key, void **cache_p, uint /*flags*/, void *cache_storage_v)
1554{
1555 BLI_assert(key->id_session_uid == id->session_uid);
1557
1558 BLOCacheStorage *cache_storage = static_cast<BLOCacheStorage *>(cache_storage_v);
1559 BLI_assert(!BLI_ghash_haskey(cache_storage->cache_map, key));
1560
1561 IDCacheKey *storage_key = static_cast<IDCacheKey *>(
1562 BLI_memarena_alloc(cache_storage->memarena, sizeof(*storage_key)));
1563 *storage_key = *key;
1564 BLOCacheStorageValue *storage_value = static_cast<BLOCacheStorageValue *>(
1565 BLI_memarena_alloc(cache_storage->memarena, sizeof(*storage_value)));
1566 storage_value->cache_v = *cache_p;
1567 storage_value->new_usage_count = 0;
1568 BLI_ghash_insert(cache_storage->cache_map, storage_key, storage_value);
1569}
1570
1573 ID *id, const IDCacheKey *key, void **cache_p, uint flags, void *cache_storage_v)
1574{
1575 BLOCacheStorage *cache_storage = static_cast<BLOCacheStorage *>(cache_storage_v);
1576
1577 if (cache_storage == nullptr) {
1578 /* In non-undo case, only clear the pointer if it is a purely runtime one.
1579 * If it may be stored in a persistent way in the .blend file, direct_link code is responsible
1580 * to properly deal with it. */
1581 if ((flags & IDTYPE_CACHE_CB_FLAGS_PERSISTENT) == 0) {
1582 *cache_p = nullptr;
1583 }
1584 return;
1585 }
1586
1587 /* Assume that when ID source is tagged as changed, its caches need to be cleared.
1588 * NOTE: This is mainly a work-around for some IDs, like Image, which use a non-depsgraph-handled
1589 * process for part of their updates.
1590 */
1591 if (id->recalc & ID_RECALC_SOURCE) {
1592 *cache_p = nullptr;
1593 return;
1594 }
1595
1596 BLOCacheStorageValue *storage_value = static_cast<BLOCacheStorageValue *>(
1597 BLI_ghash_lookup(cache_storage->cache_map, key));
1598 if (storage_value == nullptr) {
1599 *cache_p = nullptr;
1600 return;
1601 }
1602 storage_value->new_usage_count++;
1603 *cache_p = storage_value->cache_v;
1604}
1605
1608 ID * /*id*/, const IDCacheKey *key, void **cache_p, uint /*flags*/, void *cache_storage_v)
1609{
1610 BLOCacheStorage *cache_storage = static_cast<BLOCacheStorage *>(cache_storage_v);
1611
1612 BLOCacheStorageValue *storage_value = static_cast<BLOCacheStorageValue *>(
1613 BLI_ghash_lookup(cache_storage->cache_map, key));
1614 if (storage_value == nullptr) {
1615 *cache_p = nullptr;
1616 return;
1617 }
1618 /* If that cache has been restored into some new ID, we want to remove it from old one, otherwise
1619 * keep it there so that it gets properly freed together with its ID. */
1620 if (storage_value->new_usage_count != 0) {
1621 *cache_p = nullptr;
1622 }
1623 else {
1624 BLI_assert(*cache_p == storage_value->cache_v);
1625 }
1626}
1627
1629{
1630 if (fd->flags & FD_FLAGS_IS_MEMFILE) {
1631 BLI_assert(fd->cache_storage == nullptr);
1632 fd->cache_storage = static_cast<BLOCacheStorage *>(
1633 MEM_mallocN(sizeof(*fd->cache_storage), __func__));
1637
1638 ListBase *lb;
1639 FOREACH_MAIN_LISTBASE_BEGIN (bmain, lb) {
1640 ID *id = static_cast<ID *>(lb->first);
1641 if (id == nullptr) {
1642 continue;
1643 }
1644
1645 const IDTypeInfo *type_info = BKE_idtype_get_info_from_id(id);
1646 if (type_info->foreach_cache == nullptr) {
1647 continue;
1648 }
1649
1651 if (ID_IS_LINKED(id)) {
1652 continue;
1653 }
1655 }
1657 }
1659 }
1660 else {
1661 fd->cache_storage = nullptr;
1662 }
1663}
1664
1666{
1667 if (fd->cache_storage != nullptr) {
1668 ListBase *lb;
1669 FOREACH_MAIN_LISTBASE_BEGIN (bmain_old, lb) {
1670 ID *id = static_cast<ID *>(lb->first);
1671 if (id == nullptr) {
1672 continue;
1673 }
1674
1675 const IDTypeInfo *type_info = BKE_idtype_get_info_from_id(id);
1676 if (type_info->foreach_cache == nullptr) {
1677 continue;
1678 }
1679
1681 if (ID_IS_LINKED(id)) {
1682 continue;
1683 }
1685 }
1687 }
1689 }
1690}
1691
1693{
1694 if (fd->cache_storage != nullptr) {
1695 BLI_ghash_free(fd->cache_storage->cache_map, nullptr, nullptr);
1698 fd->cache_storage = nullptr;
1699 }
1700}
1701
1704/* -------------------------------------------------------------------- */
1708static void switch_endian_structs(const SDNA *filesdna, BHead *bhead)
1709{
1710 int blocksize, nblocks;
1711 char *data;
1712
1713 data = (char *)(bhead + 1);
1714
1715 blocksize = DNA_struct_size(filesdna, bhead->SDNAnr);
1716
1717 nblocks = bhead->nr;
1718 while (nblocks--) {
1719 DNA_struct_switch_endian(filesdna, bhead->SDNAnr, data);
1720
1721 data += blocksize;
1722 }
1723}
1724
1731static const char *get_alloc_name(FileData *fd,
1732 BHead *bh,
1733 const char *blockname,
1734 int id_type_index = INDEX_ID_NULL)
1735{
1736#ifndef NDEBUG
1737 /* Storage key is a pair of (string , int), where the first is the concatenation of the 'owner
1738 * block' string and DNA struct type name, and the second the length of the array, as defined by
1739 * the #BHead.nr value. */
1740 using keyT = const std::pair<const std::string, const int>;
1741#else
1742 /* Storage key is simple int, which is the ID type index. */
1743 using keyT = int;
1744#endif
1745 constexpr std::string_view STORAGE_ID = "readfile";
1746
1747 /* NOTE: This is thread_local storage, so as long as the handling of a same FileData is not
1748 * spread across threads (which is not supported at all currently), this is thread-safe. */
1749 if (!fd->storage_handle) {
1751 std::string(STORAGE_ID));
1752 }
1755 fd->storage_handle);
1756
1757 const bool is_id_data = !blockname && (id_type_index >= 0 && id_type_index < INDEX_ID_MAX);
1758
1759#ifndef NDEBUG
1760 /* Local storage of id type names, for fast access to this info. */
1761 static const std::array<std::string, INDEX_ID_MAX> id_alloc_names = [] {
1762 auto n = decltype(id_alloc_names)();
1763 for (int idtype_index = 0; idtype_index < INDEX_ID_MAX; idtype_index++) {
1764 const IDTypeInfo *idtype_info = BKE_idtype_get_info_from_idtype_index(idtype_index);
1765 BLI_assert(idtype_info);
1766 if (idtype_index == INDEX_ID_NULL) {
1767 /* #INDEX_ID_NULL returns the #IDType_ID_LINK_PLACEHOLDER type info, here we will rather
1768 * use it for unknown/invalid ID types. */
1769 n[size_t(idtype_index)] = "UNKNWOWN";
1770 }
1771 else {
1772 n[size_t(idtype_index)] = idtype_info->name;
1773 }
1774 }
1775 return n;
1776 }();
1777
1778 const std::string block_alloc_name = is_id_data ? id_alloc_names[id_type_index] : blockname;
1779 const std::string struct_name = DNA_struct_identifier(fd->filesdna, bh->SDNAnr);
1780 keyT key{block_alloc_name + struct_name, bh->nr};
1781 if (!storage.contains(key)) {
1782 const std::string alloc_string = fmt::format(
1783 (is_id_data ? "{}{} (for ID type '{}')" : "{}{} (for block '{}')"),
1784 struct_name,
1785 bh->nr > 1 ? fmt::format("[{}]", bh->nr) : "",
1786 block_alloc_name);
1787 return storage.insert(key, alloc_string);
1788 }
1789 return storage.find(key);
1790#else
1791 /* Simple storage for pure release builds, using integer as key, one entry for each ID type. */
1793 if (is_id_data) {
1794 if (UNLIKELY(!storage.contains(id_type_index))) {
1795 if (id_type_index == INDEX_ID_NULL) {
1796 return storage.insert(id_type_index, "Data from UNKNOWN");
1797 }
1798 const IDTypeInfo *id_type = BKE_idtype_get_info_from_idtype_index(id_type_index);
1799 const std::string alloc_string = fmt::format("Data from '{}' ID type", id_type->name);
1800 return storage.insert(id_type_index, alloc_string);
1801 }
1802 return storage.find(id_type_index);
1803 }
1804 return blockname;
1805#endif
1806}
1807
1808static void *read_struct(FileData *fd, BHead *bh, const char *blockname, const int id_type_index)
1809{
1810 void *temp = nullptr;
1811
1812 if (bh->len) {
1813#ifdef USE_BHEAD_READ_ON_DEMAND
1814 BHead *bh_orig = bh;
1815#endif
1816
1817 /* Endianness switch is based on file DNA.
1818 *
1819 * NOTE: raw data (aka #SDNA_RAW_DATA_STRUCT_INDEX #SDNAnr) is not handled here, it's up to
1820 * the calling code to manage this. */
1821 BLI_STATIC_ASSERT(SDNA_RAW_DATA_STRUCT_INDEX == 0, "'raw data' SDNA struct index should be 0")
1823#ifdef USE_BHEAD_READ_ON_DEMAND
1824 if (BHEADN_FROM_BHEAD(bh)->has_data == false) {
1825 bh = blo_bhead_read_full(fd, bh);
1826 if (UNLIKELY(bh == nullptr)) {
1827 fd->flags &= ~FD_FLAGS_FILE_OK;
1828 return nullptr;
1829 }
1830 }
1831#endif
1833 }
1834
1835 if (fd->compflags[bh->SDNAnr] != SDNA_CMP_REMOVED) {
1836 const char *alloc_name = get_alloc_name(fd, bh, blockname, id_type_index);
1837 if (fd->compflags[bh->SDNAnr] == SDNA_CMP_NOT_EQUAL) {
1838#ifdef USE_BHEAD_READ_ON_DEMAND
1839 if (BHEADN_FROM_BHEAD(bh)->has_data == false) {
1840 bh = blo_bhead_read_full(fd, bh);
1841 if (UNLIKELY(bh == nullptr)) {
1842 fd->flags &= ~FD_FLAGS_FILE_OK;
1843 return nullptr;
1844 }
1845 }
1846#endif
1848 fd->reconstruct_info, bh->SDNAnr, bh->nr, (bh + 1), alloc_name);
1849 }
1850 else {
1851 /* SDNA_CMP_EQUAL */
1852 const int alignment = DNA_struct_alignment(fd->filesdna, bh->SDNAnr);
1853 temp = MEM_mallocN_aligned(bh->len, alignment, alloc_name);
1854#ifdef USE_BHEAD_READ_ON_DEMAND
1855 if (BHEADN_FROM_BHEAD(bh)->has_data) {
1856 memcpy(temp, (bh + 1), bh->len);
1857 }
1858 else {
1859 /* Instead of allocating the bhead, then copying it,
1860 * read the data from the file directly into the memory. */
1861 if (UNLIKELY(!blo_bhead_read_data(fd, bh, temp))) {
1862 fd->flags &= ~FD_FLAGS_FILE_OK;
1863 MEM_freeN(temp);
1864 temp = nullptr;
1865 }
1866 }
1867#else
1868 memcpy(temp, (bh + 1), bh->len);
1869#endif
1870 }
1871 }
1872
1873#ifdef USE_BHEAD_READ_ON_DEMAND
1874 if (bh_orig != bh) {
1876 }
1877#endif
1878 }
1879
1880 return temp;
1881}
1882
1883/* Like read_struct, but gets a pointer without allocating. Only works for
1884 * undo since DNA must match. */
1885static const void *peek_struct_undo(FileData *fd, BHead *bhead)
1886{
1889 return (bhead->len) ? (const void *)(bhead + 1) : nullptr;
1890}
1891
1892static void link_glob_list(FileData *fd, ListBase *lb) /* for glob data */
1893{
1894 Link *ln, *prev;
1895 void *poin;
1896
1897 if (BLI_listbase_is_empty(lb)) {
1898 return;
1899 }
1900 poin = newdataadr(fd, lb->first);
1901 if (lb->first) {
1902 oldnewmap_insert(fd->globmap, lb->first, poin, 0);
1903 }
1904 lb->first = poin;
1905
1906 ln = static_cast<Link *>(lb->first);
1907 prev = nullptr;
1908 while (ln) {
1909 poin = newdataadr(fd, ln->next);
1910 if (ln->next) {
1911 oldnewmap_insert(fd->globmap, ln->next, poin, 0);
1912 }
1913 ln->next = static_cast<Link *>(poin);
1914 ln->prev = prev;
1915 prev = ln;
1916 ln = ln->next;
1917 }
1918 lb->last = prev;
1919}
1920
1923/* -------------------------------------------------------------------- */
1927static void after_liblink_id_process(BlendLibReader *reader, ID *id);
1928
1930{
1931
1932 /* Handle 'private IDs'. */
1934 if (nodetree != nullptr) {
1935 after_liblink_id_process(reader, &nodetree->id);
1936
1937 if (nodetree->owner_id == nullptr) {
1938 CLOG_WARN(&LOG,
1939 "NULL owner_id pointer for embedded NodeTree of %s, should never happen",
1940 id->name);
1941 nodetree->owner_id = id;
1942 }
1943 else if (nodetree->owner_id != id) {
1944 CLOG_WARN(&LOG,
1945 "Inconsistent owner_id pointer for embedded NodeTree of %s, should never happen",
1946 id->name);
1947 nodetree->owner_id = id;
1948 }
1949 }
1950
1951 if (GS(id->name) == ID_SCE) {
1952 Scene *scene = (Scene *)id;
1953 if (scene->master_collection != nullptr) {
1954 after_liblink_id_process(reader, &scene->master_collection->id);
1955
1956 if (scene->master_collection->owner_id == nullptr) {
1957 CLOG_WARN(&LOG,
1958 "NULL owner_id pointer for embedded Scene Collection of %s, should never happen",
1959 id->name);
1960 scene->master_collection->owner_id = id;
1961 }
1962 else if (scene->master_collection->owner_id != id) {
1963 CLOG_WARN(&LOG,
1964 "Inconsistent owner_id pointer for embedded Scene Collection of %s, should "
1965 "never happen",
1966 id->name);
1967 scene->master_collection->owner_id = id;
1968 }
1969 }
1970 }
1971}
1972
1974{
1975 /* NOTE: WM IDProperties are never written to file, hence they should always be nullptr here. */
1976 BLI_assert((GS(id->name) != ID_WM) || id->properties == nullptr);
1977
1979
1980 const IDTypeInfo *id_type = BKE_idtype_get_info_from_id(id);
1981 if (id_type->blend_read_after_liblink != nullptr) {
1982 id_type->blend_read_after_liblink(reader, id);
1983 }
1984}
1985
1988{
1989 BLO_read_string(reader, &op->rna_path);
1990
1991 op->tag = 0; /* Runtime only. */
1992
1994
1996 BLO_read_string(reader, &opop->subitem_reference_name);
1997 BLO_read_string(reader, &opop->subitem_local_name);
1998
1999 opop->tag = 0; /* Runtime only. */
2000 }
2001}
2002
2003static void direct_link_id_common(
2004 BlendDataReader *reader, Library *current_library, ID *id, ID *id_old, const int id_tag);
2005
2007 Library *current_library,
2008 ID *id,
2009 ID *id_old)
2010{
2011 /* Handle 'private IDs'. */
2013 if (nodetree != nullptr && *nodetree != nullptr) {
2014 BLO_read_struct(reader, bNodeTree, nodetree);
2015 direct_link_id_common(reader,
2016 current_library,
2017 (ID *)*nodetree,
2018 id_old != nullptr ? (ID *)blender::bke::node_tree_from_id(id_old) :
2019 nullptr,
2020 0);
2021 blender::bke::node_tree_blend_read_data(reader, id, *nodetree);
2022 }
2023
2024 if (GS(id->name) == ID_SCE) {
2025 Scene *scene = (Scene *)id;
2026 if (scene->master_collection != nullptr) {
2027 BLO_read_struct(reader, Collection, &scene->master_collection);
2028 direct_link_id_common(reader,
2029 current_library,
2030 &scene->master_collection->id,
2031 id_old != nullptr ? &((Scene *)id_old)->master_collection->id :
2032 nullptr,
2033 0);
2034 BKE_collection_blend_read_data(reader, scene->master_collection, &scene->id);
2035 }
2036 }
2037}
2038
2040{
2041 /* Exception for armature objects, where the pose has direct points to the
2042 * armature data-block. */
2043 if (GS(id_current->name) == ID_OB && ((Object *)id_current)->pose) {
2044 return ID_RECALC_GEOMETRY;
2045 }
2046
2047 return 0;
2048}
2049
2051 const ID *id_target,
2052 const ID *id_current,
2053 const bool is_identical)
2054{
2055 /* These are the evaluations that had not been performed yet at the time the
2056 * target undo state was written. These need to be done again, since they may
2057 * flush back changes to the original datablock. */
2058 int recalc = id_target->recalc;
2059
2060 if (id_current == nullptr) {
2061 /* ID does not currently exist in the database, so also will not exist in
2062 * the dependency graphs. That means it will be newly created and as a
2063 * result also fully re-evaluated regardless of the recalc flag set here. */
2064 recalc |= ID_RECALC_ALL;
2065 }
2066 else {
2067 /* If the contents datablock changed, the depsgraph needs to copy the
2068 * datablock again to ensure it matches the original datablock. */
2069 if (!is_identical) {
2070 recalc |= ID_RECALC_SYNC_TO_EVAL;
2071 }
2072
2073 /* Special exceptions. */
2074 recalc |= direct_link_id_restore_recalc_exceptions(id_current);
2075
2076 /* Evaluations for the current state that have not been performed yet
2077 * by the time we are performing this undo step. */
2078 recalc |= id_current->recalc;
2079
2080 /* Tags that were set between the target state and the current state,
2081 * that we need to perform again. */
2082 if (fd->undo_direction == STEP_UNDO) {
2083 /* Undo: tags from target to the current state. */
2084 recalc |= id_current->recalc_up_to_undo_push;
2085 }
2086 else {
2088 /* Redo: tags from current to the target state. */
2089 recalc |= id_target->recalc_up_to_undo_push;
2090 }
2091 }
2092
2093 return recalc;
2094}
2095
2097 BlendDataReader *reader, Library *current_library, ID *id, ID *id_old, const int id_tag)
2098{
2099 if (!BLO_read_data_is_undo(reader)) {
2100 /* When actually reading a file, we do want to reset/re-generate session UIDS.
2101 * In undo case, we want to re-use existing ones. */
2102 id->session_uid = MAIN_ID_SESSION_UID_UNSET;
2103 }
2104
2105 id->lib = current_library;
2106 if (id->lib) {
2107 /* Always fully clear fake user flag for linked data. */
2108 id->flag &= ~ID_FLAG_FAKEUSER;
2109 }
2110 id->us = ID_FAKE_USERS(id);
2111 id->icon_id = 0;
2112 id->newid = nullptr; /* Needed because .blend may have been saved with crap value here... */
2113 id->orig_id = nullptr;
2114 id->py_instance = nullptr;
2115
2116 /* Initialize with provided tag. */
2117 if (BLO_read_data_is_undo(reader)) {
2118 id->tag = (id_tag & ~ID_TAG_KEEP_ON_UNDO) | (id->tag & ID_TAG_KEEP_ON_UNDO);
2119 }
2120 else {
2121 id->tag = id_tag;
2122 }
2123
2124 if ((id_tag & ID_TAG_TEMP_MAIN) == 0) {
2126 }
2127
2128 if (ID_IS_LINKED(id)) {
2129 id->library_weak_reference = nullptr;
2130 }
2131 else {
2132 BLO_read_struct(reader, LibraryWeakReference, &id->library_weak_reference);
2133 }
2134
2135 if (id_tag & ID_TAG_ID_LINK_PLACEHOLDER) {
2136 /* For placeholder we only need to set the tag and properly initialize generic ID fields above,
2137 * no further data to read. */
2138 return;
2139 }
2140
2141 BKE_animdata_blend_read_data(reader, id);
2142
2143 if (id->asset_data) {
2144 BLO_read_struct(reader, AssetMetaData, &id->asset_data);
2145 BKE_asset_metadata_read(reader, id->asset_data);
2146 /* Restore runtime asset type info. */
2147 const IDTypeInfo *id_type = BKE_idtype_get_info_from_id(id);
2148 id->asset_data->local_type_info = id_type->asset_type_info;
2149 }
2150
2151 /* Link direct data of ID properties. */
2152 if (id->properties) {
2153 BLO_read_struct(reader, IDProperty, &id->properties);
2154 /* this case means the data was written incorrectly, it should not happen */
2155 IDP_BlendDataRead(reader, &id->properties);
2156 }
2157
2158 id->flag &= ~ID_FLAG_INDIRECT_WEAK_LINK;
2159
2160 /* NOTE: It is important to not clear the recalc flags for undo/redo.
2161 * Preserving recalc flags on redo/undo is the only way to make dependency graph detect
2162 * that animation is to be evaluated on undo/redo. If this is not enforced by the recalc
2163 * flags dependency graph does not do animation update to avoid loss of unkeyed changes.,
2164 * which conflicts with undo/redo of changes to animation data itself.
2165 *
2166 * But for regular file load we clear the flag, since the flags might have been changed since
2167 * the version the file has been saved with. */
2168 if (!BLO_read_data_is_undo(reader)) {
2169 id->recalc = 0;
2170 id->recalc_after_undo_push = 0;
2171 }
2172 else if ((reader->fd->skip_flags & BLO_READ_SKIP_UNDO_OLD_MAIN) == 0) {
2173 id->recalc = direct_link_id_restore_recalc(reader->fd, id, id_old, false);
2174 id->recalc_after_undo_push = 0;
2175 }
2176
2177 /* Link direct data of overrides. */
2178 if (id->override_library) {
2179 BLO_read_struct(reader, IDOverrideLibrary, &id->override_library);
2180 /* Work around file corruption on writing, see #86853. */
2181 if (id->override_library != nullptr) {
2182 BLO_read_struct_list(reader, IDOverrideLibraryProperty, &id->override_library->properties);
2183 LISTBASE_FOREACH (IDOverrideLibraryProperty *, op, &id->override_library->properties) {
2185 }
2186 id->override_library->runtime = nullptr;
2187 }
2188 }
2189
2190 DrawDataList *drawdata = DRW_drawdatalist_from_id(id);
2191 if (drawdata) {
2192 BLI_listbase_clear((ListBase *)drawdata);
2193 }
2194
2195 /* Handle 'private IDs'. */
2196 direct_link_id_embedded_id(reader, current_library, id, id_old);
2197}
2198
2201/* -------------------------------------------------------------------- */
2207/* -------------------------------------------------------------------- */
2212{
2213 key->uidgen = 1;
2214 LISTBASE_FOREACH (KeyBlock *, block, &key->block) {
2215 block->uid = key->uidgen++;
2216 }
2217}
2218
2221/* -------------------------------------------------------------------- */
2225#ifdef USE_SETSCENE_CHECK
2229static bool scene_validate_setscene__liblink(Scene *sce, const int totscene)
2230{
2231 Scene *sce_iter;
2232 int a;
2233
2234 if (sce->set == nullptr) {
2235 return true;
2236 }
2237
2238 for (a = 0, sce_iter = sce; sce_iter->set; sce_iter = sce_iter->set, a++) {
2239 /* This runs per library (before each libraries #Main has been joined),
2240 * so we can't step into other libraries since `totscene` is only for this library.
2241 *
2242 * Also, other libraries may not have been linked yet,
2243 * while we could check #ID_TAG_NEED_LINK the library pointer check is sufficient. */
2244 if (sce->id.lib != sce_iter->id.lib) {
2245 return true;
2246 }
2248 return true;
2249 }
2250
2251 if (a > totscene) {
2252 sce->set = nullptr;
2253 return false;
2254 }
2255 }
2256
2257 return true;
2258}
2259#endif
2260
2262{
2263#ifdef USE_SETSCENE_CHECK
2264 const int totscene = BLI_listbase_count(&bmain->scenes);
2265 LISTBASE_FOREACH (Scene *, sce, &bmain->scenes) {
2267 sce->flag &= ~SCE_READFILE_LIBLINK_NEED_SETSCENE_CHECK;
2268 if (!scene_validate_setscene__liblink(sce, totscene)) {
2269 CLOG_WARN(&LOG, "Found cyclic background scene when linking %s", sce->id.name + 2);
2270 }
2271 }
2272 }
2273#else
2274 UNUSED_VARS(bmain, totscene);
2275#endif
2276}
2277
2278#undef USE_SETSCENE_CHECK
2279
2282/* -------------------------------------------------------------------- */
2283
2288{
2289 /* Make sure we have full path in lib->runtime.filepath_abs */
2290 /* NOTE: Since existing libraries are searched by their absolute path, this has to be generated
2291 * before the lookup below. Otherwise, in case the stored absolute filepath is not 'correct' (may
2292 * be empty, or have been stored in a different 'relative path context'), the comparison below
2293 * will always fail, leading to creating duplicates IDs of a same library. */
2294 /* TODO: May be worth checking whether comparison below could use `lib->filepath` instead? */
2295 STRNCPY(lib->runtime.filepath_abs, lib->filepath);
2296 BLI_path_abs(lib->runtime.filepath_abs, fd->relabase);
2297 BLI_path_normalize(lib->runtime.filepath_abs);
2298
2299 /* check if the library was already read */
2300 LISTBASE_FOREACH (Main *, newmain, fd->mainlist) {
2301 if (newmain->curlib) {
2302 if (BLI_path_cmp(newmain->curlib->runtime.filepath_abs, lib->runtime.filepath_abs) == 0) {
2305 RPT_("Library '%s', '%s' had multiple instances, save and reload!"),
2306 lib->filepath,
2307 lib->runtime.filepath_abs);
2308
2309 change_link_placeholder_to_real_ID_pointer(fd->mainlist, fd, lib, newmain->curlib);
2310 // change_link_placeholder_to_real_ID_pointer_fd(fd, lib, newmain->curlib);
2311
2312 BLI_remlink(&main->libraries, lib);
2313 MEM_freeN(lib);
2314
2315 /* Now, since Blender always expect **latest** Main pointer from fd->mainlist
2316 * to be the active library Main pointer,
2317 * where to add all non-library data-blocks found in file next, we have to switch that
2318 * 'dupli' found Main to latest position in the list!
2319 * Otherwise, you get weird disappearing linked data on a rather inconsistent basis.
2320 * See also #53977 for reproducible case. */
2321 BLI_remlink(fd->mainlist, newmain);
2322 BLI_addtail(fd->mainlist, newmain);
2323
2324 return;
2325 }
2326 }
2327 }
2328
2329 // printf("direct_link_library: filepath %s\n", lib->filepath);
2330 // printf("direct_link_library: filepath_abs %s\n", lib->runtime.filepath_abs);
2331
2332 BlendDataReader reader = {fd};
2333 BKE_packedfile_blend_read(&reader, &lib->packedfile, lib->filepath);
2334
2335 /* new main */
2336 Main *newmain = BKE_main_new();
2337 BLI_addtail(fd->mainlist, newmain);
2338 newmain->curlib = lib;
2339
2340 lib->runtime.parent = nullptr;
2341
2342 id_us_ensure_real(&lib->id);
2343}
2344
2345/* Always call this once you have loaded new library data to set the relative paths correctly
2346 * in relation to the blend file. */
2347static void fix_relpaths_library(const char *basepath, Main *main)
2348{
2349 /* #BLO_read_from_memory uses a blank file-path. */
2350 if (basepath == nullptr || basepath[0] == '\0') {
2351 LISTBASE_FOREACH (Library *, lib, &main->libraries) {
2352 /* when loading a linked lib into a file which has not been saved,
2353 * there is nothing we can be relative to, so instead we need to make
2354 * it absolute. This can happen when appending an object with a relative
2355 * link into an unsaved blend file. See #27405.
2356 * The remap relative option will make it relative again on save - campbell */
2357 if (BLI_path_is_rel(lib->filepath)) {
2358 STRNCPY(lib->filepath, lib->runtime.filepath_abs);
2359 }
2360 }
2361 }
2362 else {
2363 LISTBASE_FOREACH (Library *, lib, &main->libraries) {
2364 /* Libraries store both relative and abs paths, recreate relative paths,
2365 * relative to the blend file since indirectly linked libraries will be
2366 * relative to their direct linked library. */
2367 if (BLI_path_is_rel(lib->filepath)) { /* if this is relative to begin with? */
2368 STRNCPY(lib->filepath, lib->runtime.filepath_abs);
2369 BLI_path_rel(lib->filepath, basepath);
2370 }
2371 }
2372 }
2373}
2374
2377/* -------------------------------------------------------------------- */
2381static ID *create_placeholder(Main *mainvar,
2382 const short idcode,
2383 const char *idname,
2384 const int tag,
2385 const bool was_liboverride)
2386{
2387 ListBase *lb = which_libbase(mainvar, idcode);
2388 ID *ph_id = static_cast<ID *>(BKE_libblock_alloc_notest(idcode));
2389
2390 *((short *)ph_id->name) = idcode;
2391 BLI_strncpy(ph_id->name + 2, idname, sizeof(ph_id->name) - 2);
2393 ph_id->lib = mainvar->curlib;
2394 ph_id->tag = tag | ID_TAG_MISSING;
2395 ph_id->us = ID_FAKE_USERS(ph_id);
2396 ph_id->icon_id = 0;
2397
2398 if (was_liboverride) {
2399 /* 'Abuse' `ID_TAG_LIBOVERRIDE_NEED_RESYNC` to mark that placeholder missing linked ID as
2400 * being a liboverride.
2401 *
2402 * This will be used by the liboverride resync process, see #lib_override_library_resync. */
2404 }
2405
2406 BLI_addtail(lb, ph_id);
2407 id_sort_by_name(lb, ph_id, nullptr);
2408
2409 if (mainvar->id_map != nullptr) {
2410 BKE_main_idmap_insert_id(mainvar->id_map, ph_id);
2411 }
2412
2413 if ((tag & ID_TAG_TEMP_MAIN) == 0) {
2415 }
2416
2417 return ph_id;
2418}
2419
2421{
2422 /* Placeholder ObData IDs won't have any material, we have to update their objects for that,
2423 * otherwise the inconsistency between both will lead to crashes (especially in Eevee?). */
2424 LISTBASE_FOREACH (Object *, ob, &bmain->objects) {
2425 ID *obdata = static_cast<ID *>(ob->data);
2426 if (obdata != nullptr && obdata->tag & ID_TAG_MISSING) {
2427 BKE_object_materials_test(bmain, ob, obdata);
2428 }
2429 }
2430}
2431
2432static bool direct_link_id(FileData *fd, Main *main, const int tag, ID *id, ID *id_old)
2433{
2434 BlendDataReader reader = {fd};
2435 /* Sharing is only allowed within individual data-blocks currently. The clearing is done
2436 * explicitly here, in case the `reader` is used by multiple IDs in the future. */
2438
2439 /* Read part of datablock that is common between real and embedded datablocks. */
2440 direct_link_id_common(&reader, main->curlib, id, id_old, tag);
2441
2442 if (tag & ID_TAG_ID_LINK_PLACEHOLDER) {
2443 /* For placeholder we only need to set the tag, no further data to read. */
2444 id->tag = tag;
2445 return true;
2446 }
2447
2448 const IDTypeInfo *id_type = BKE_idtype_get_info_from_id(id);
2449 if (id_type->blend_read_data != nullptr) {
2450 id_type->blend_read_data(&reader, id);
2451 }
2452
2453 /* XXX Very weakly handled currently, see comment in read_libblock() before trying to
2454 * use it for anything new. */
2455 bool success = true;
2456
2457 switch (GS(id->name)) {
2458 case ID_SCR:
2459 success = BKE_screen_blend_read_data(&reader, (bScreen *)id);
2460 break;
2461 case ID_LI:
2462 direct_link_library(fd, (Library *)id, main);
2463 break;
2464 default:
2465 /* Do nothing. Handled by IDTypeInfo callback. */
2466 break;
2467 }
2468
2469 /* try to restore (when undoing) or clear ID's cache pointers. */
2470 if (id_type->foreach_cache != nullptr) {
2473 }
2474
2475 return success;
2476}
2477
2478/* Read all data associated with a datablock into datamap. */
2480 BHead *bhead,
2481 const char *allocname,
2482 const int id_type_index)
2483{
2484 bhead = blo_bhead_next(fd, bhead);
2485
2486 while (bhead && bhead->code == BLO_CODE_DATA) {
2487 void *data = read_struct(fd, bhead, allocname, id_type_index);
2488 if (data) {
2489 const bool is_new = oldnewmap_insert(fd->datamap, bhead->old, data, 0);
2490 if (!is_new) {
2491 CLOG_ERROR(&LOG,
2492 "Blendfile corruption: Invalid, or multiple `bhead` with same old address "
2493 "value (%p) for a given ID.",
2494 bhead->old);
2495 }
2496 }
2497
2498 bhead = blo_bhead_next(fd, bhead);
2499 }
2500
2501 return bhead;
2502}
2503
2504/* Verify if the datablock and all associated data is identical. */
2506{
2507 /* Test ID itself. */
2508 if (bhead->len && !BHEADN_FROM_BHEAD(bhead)->is_memchunk_identical) {
2509 return false;
2510 }
2511
2512 /* Test any other data that is part of ID (logic must match read_data_into_datamap). */
2513 bhead = blo_bhead_next(fd, bhead);
2514
2515 while (bhead && bhead->code == BLO_CODE_DATA) {
2516 if (bhead->len && !BHEADN_FROM_BHEAD(bhead)->is_memchunk_identical) {
2517 return false;
2518 }
2519
2520 bhead = blo_bhead_next(fd, bhead);
2521 }
2522
2523 return true;
2524}
2525
2526/* Re-use the whole 'noundo' local IDs by moving them from old to new main. Linked ones are handled
2527 * separately together with their libraries.
2528 *
2529 * NOTE: While in theory Library IDs (and their related linked IDs) are also 'noundo' data, in
2530 * practice they need to be handled separately, to ensure that their order in the new bmain list
2531 * matches the one from the read blend-file. Reading linked 'placeholder' entries in a memfile
2532 * relies on current library being the last item in the new main list. */
2534{
2535 Main *old_bmain = static_cast<Main *>(fd->old_mainlist->first);
2536 ListBase *lbarray[INDEX_ID_MAX];
2537
2538 BLI_assert(old_bmain->curlib == nullptr);
2540
2541 int i = set_listbasepointers(old_bmain, lbarray);
2542 while (i--) {
2543 if (BLI_listbase_is_empty(lbarray[i])) {
2544 continue;
2545 }
2546
2547 /* Only move 'noundo' local IDs. */
2548 ID *id = static_cast<ID *>(lbarray[i]->first);
2549 const IDTypeInfo *id_type = BKE_idtype_get_info_from_id(id);
2550 if ((id_type->flags & IDTYPE_FLAGS_NO_MEMFILE_UNDO) == 0) {
2551 continue;
2552 }
2553
2554 Main *new_bmain = static_cast<Main *>(fd->mainlist->first);
2555 ListBase *new_lb = which_libbase(new_bmain, id_type->id_code);
2557 BLI_movelisttolist(new_lb, lbarray[i]);
2558
2559 /* Update mappings accordingly. */
2560 LISTBASE_FOREACH (ID *, id_iter, new_lb) {
2562 id_iter->tag |= ID_TAG_UNDO_OLD_ID_REUSED_NOUNDO;
2563 }
2564 }
2565}
2566
2568 FileData *fd, Main *new_main, Main *old_main, Main *libmain, BHead *bhead)
2569{
2570 Library *curlib = libmain->curlib;
2571
2572 BLI_remlink(fd->old_mainlist, libmain);
2573 BLI_remlink_safe(&old_main->libraries, libmain->curlib);
2574 BLI_addtail(fd->mainlist, libmain);
2575 BLI_addtail(&new_main->libraries, libmain->curlib);
2576
2579 if (bhead != nullptr) {
2580 oldnewmap_lib_insert(fd, bhead->old, &curlib->id, GS(curlib->id.name));
2581 }
2582
2583 ID *id_iter;
2584 FOREACH_MAIN_ID_BEGIN (libmain, id_iter) {
2586 }
2588}
2589
2590/* For undo, restore matching library datablock from the old main. */
2592 FileData *fd, Main *new_main, const ID *id, ID *id_old, BHead *bhead)
2593{
2594 /* In undo case, most libraries and linked data should be kept as is from previous state
2595 * (see BLO_read_from_memfile).
2596 * However, some needed by the snapshot being read may have been removed in previous one,
2597 * and would go missing.
2598 * This leads e.g. to disappearing objects in some undo/redo case, see #34446.
2599 * That means we have to carefully check whether current lib or
2600 * libdata already exits in old main, if it does we merely copy it over into new main area,
2601 * otherwise we have to do a full read of that bhead... */
2602 CLOG_INFO(&LOG_UNDO, 2, "UNDO: restore library %s", id->name);
2603
2604 if (id_old == nullptr) {
2605 CLOG_INFO(&LOG_UNDO, 2, " -> NO match");
2606 return false;
2607 }
2608
2609 Main *libmain = static_cast<Main *>(fd->old_mainlist->first);
2610 /* Skip `oldmain` itself. */
2611 for (libmain = libmain->next; libmain; libmain = libmain->next) {
2612 if (&libmain->curlib->id == id_old) {
2613 Main *old_main = static_cast<Main *>(fd->old_mainlist->first);
2615 2,
2616 " compare with %s -> match (existing libpath: %s)",
2617 libmain->curlib ? libmain->curlib->id.name : "<none>",
2618 libmain->curlib ? libmain->curlib->runtime.filepath_abs : "<none>");
2619 /* In case of a library, we need to re-add its main to fd->mainlist,
2620 * because if we have later a missing ID_LINK_PLACEHOLDER,
2621 * we need to get the correct lib it is linked to!
2622 * Order is crucial, we cannot bulk-add it in BLO_read_from_memfile()
2623 * like it used to be. */
2624 read_undo_move_libmain_data(fd, new_main, old_main, libmain, bhead);
2625 return true;
2626 }
2627 }
2628
2629 return false;
2630}
2631
2632static ID *library_id_is_yet_read(FileData *fd, Main *mainvar, BHead *bhead);
2633
2634/* For undo, restore existing linked datablock from the old main.
2635 *
2636 * Note that IDs from existing libs have already been moved into the new main when their (local)
2637 * ID_LI library ID was handled by #read_libblock_undo_restore_library, so this function has very
2638 * little to do. */
2640 FileData *fd, Main *libmain, const ID *id, ID **r_id_old, BHead *bhead)
2641{
2642 CLOG_INFO(&LOG_UNDO, 2, "UNDO: restore linked datablock %s", id->name);
2643
2644 if (*r_id_old == nullptr) {
2645 /* If the linked ID had to be re-read at some point, its session_uid may not be the same as
2646 * its reference stored in the memfile anymore. Do a search by name then. */
2647 *r_id_old = library_id_is_yet_read(fd, libmain, bhead);
2648
2649 if (*r_id_old == nullptr) {
2651 2,
2652 " from %s (%s): NOT found",
2653 libmain->curlib ? libmain->curlib->id.name : "<nullptr>",
2654 libmain->curlib ? libmain->curlib->filepath : "<nullptr>");
2655 return false;
2656 }
2657
2659 2,
2660 " from %s (%s): found by name",
2661 libmain->curlib ? libmain->curlib->id.name : "<nullptr>",
2662 libmain->curlib ? libmain->curlib->filepath : "<nullptr>");
2663 /* The Library ID 'owning' this linked ID should already have been moved to new main by a call
2664 * to #read_libblock_undo_restore_library. */
2665 BLI_assert(*r_id_old == static_cast<ID *>(BKE_main_idmap_lookup_uid(
2666 fd->new_idmap_uid, (*r_id_old)->session_uid)));
2667 }
2668 else {
2670 2,
2671 " from %s (%s): found by session_uid",
2672 libmain->curlib ? libmain->curlib->id.name : "<nullptr>",
2673 libmain->curlib ? libmain->curlib->filepath : "<nullptr>");
2674 /* The Library ID 'owning' this linked ID should already have been moved to new main by a call
2675 * to #read_libblock_undo_restore_library. */
2676 BLI_assert(*r_id_old ==
2677 static_cast<ID *>(BKE_main_idmap_lookup_uid(fd->new_idmap_uid, id->session_uid)));
2678 }
2679
2680 oldnewmap_lib_insert(fd, bhead->old, *r_id_old, GS((*r_id_old)->name));
2681
2682 /* No need to do anything else for ID_LINK_PLACEHOLDER, it's assumed
2683 * already present in its lib's main. */
2684 return true;
2685}
2686
2687/* For undo, restore unchanged local datablock from old main. */
2689 FileData *fd, Main *main, const ID * /*id*/, ID *id_old, BHead *bhead, const int id_tag)
2690{
2692 BLI_assert(id_old != nullptr);
2693
2694 /* Do not add ID_TAG_NEW here, this should not be needed/used in undo case anyway (as
2695 * this is only for do_version-like code), but for sake of consistency, and also because
2696 * it will tell us which ID is re-used from old Main, and which one is actually newly read. */
2697 /* Also do not add ID_TAG_NEED_LINK, this ID will never be re-liblinked, hence that tag will
2698 * never be cleared, leading to critical issue in link/append code. */
2699 /* Some tags need to be preserved here. */
2701 (id_old->tag & ID_TAG_KEEP_ON_UNDO);
2702 id_old->lib = main->curlib;
2703 id_old->us = ID_FAKE_USERS(id_old);
2704 /* Do not reset id->icon_id here, memory allocated for it remains valid. */
2705 /* Needed because .blend may have been saved with crap value here... */
2706 id_old->newid = nullptr;
2707 id_old->orig_id = nullptr;
2708
2709 const short idcode = GS(id_old->name);
2710 Main *old_bmain = static_cast<Main *>(fd->old_mainlist->first);
2711 ListBase *old_lb = which_libbase(old_bmain, idcode);
2712 ListBase *new_lb = which_libbase(main, idcode);
2713 BLI_remlink(old_lb, id_old);
2714 BLI_addtail(new_lb, id_old);
2715
2716 /* Recalc flags, mostly these just remain as they are. */
2718 id_old->recalc_after_undo_push = 0;
2719
2720 /* Insert into library map for lookup by newly read datablocks (with pointer value bhead->old).
2721 * Note that existing datablocks in memory (which pointer value would be id_old) are not
2722 * remapped, so no need to store this info here. */
2723 oldnewmap_lib_insert(fd, bhead->old, id_old, bhead->code);
2724
2726
2727 if (GS(id_old->name) == ID_OB) {
2728 Object *ob = (Object *)id_old;
2729 /* For undo we stay in object mode during undo presses, so keep editmode disabled for re-used
2730 * data-blocks too. */
2731 ob->mode &= ~OB_MODE_EDIT;
2732 }
2733}
2734
2735/* For undo, store changed datablock at old address. */
2737{
2738 /* During memfile undo, if an ID changed and we cannot directly re-use existing one from old
2739 * bmain, we do a full read of the new id from the memfile, and then fully swap its content
2740 * with the old id. This allows us to keep the same pointer even for modified data, which
2741 * helps reducing further detected changes by the depsgraph (since unchanged IDs remain fully
2742 * unchanged, even if they are using/pointing to a changed one). */
2744 BLI_assert(id_old != nullptr);
2745
2746 const short idcode = GS(id->name);
2747
2748 Main *old_bmain = static_cast<Main *>(fd->old_mainlist->first);
2749 ListBase *old_lb = which_libbase(old_bmain, idcode);
2750 ListBase *new_lb = which_libbase(main, idcode);
2751 BLI_remlink(old_lb, id_old);
2752 BLI_remlink(new_lb, id);
2753
2754 /* We do need remapping of internal pointers to the ID itself here.
2755 *
2756 * Passing a null #Main means that not all potential runtime data (like collections' parent
2757 * pointers etc.) will be up-to-date. However, this should not be a problem here, since these
2758 * data are re-generated later in file-read process anyway. */
2759 BKE_lib_id_swap_full(nullptr,
2760 id,
2761 id_old,
2762 true,
2766
2767 /* Special temporary usage of this pointer, necessary for the `undo_preserve` call after
2768 * lib-linking to restore some data that should never be affected by undo, e.g. the 3D cursor of
2769 * #Scene. */
2770 id_old->orig_id = id;
2772
2773 BLI_addtail(new_lb, id_old);
2774 BLI_addtail(old_lb, id);
2775}
2776
2778 FileData *fd, Main *main, BHead *bhead, int id_tag, ID **r_id_old)
2779{
2780 BLI_assert(fd->old_idmap_uid != nullptr);
2781
2782 /* Get pointer to memory of new ID that we will be reading. */
2783 const ID *id = static_cast<const ID *>(peek_struct_undo(fd, bhead));
2784 const IDTypeInfo *id_type = BKE_idtype_get_info_from_id(id);
2785
2786 const bool do_partial_undo = (fd->skip_flags & BLO_READ_SKIP_UNDO_OLD_MAIN) == 0;
2787#ifndef NDEBUG
2788 if (do_partial_undo && (bhead->code != ID_LINK_PLACEHOLDER)) {
2789 /* This code should only ever be reached for local data-blocks. */
2790 BLI_assert(main->curlib == nullptr);
2791 }
2792#endif
2793
2794 /* Find the 'current' existing ID we want to reuse instead of the one we
2795 * would read from the undo memfile. */
2796 ID *id_old = (fd->old_idmap_uid != nullptr) ?
2797 BKE_main_idmap_lookup_uid(fd->old_idmap_uid, id->session_uid) :
2798 nullptr;
2799
2800 if (bhead->code == ID_LI) {
2801 /* Restore library datablock, if possible. */
2802 if (read_libblock_undo_restore_library(fd, main, id, id_old, bhead)) {
2803 return true;
2804 }
2805 }
2806 else if (bhead->code == ID_LINK_PLACEHOLDER) {
2807 /* Restore linked datablock. */
2808 if (read_libblock_undo_restore_linked(fd, main, id, &id_old, bhead)) {
2809 return true;
2810 }
2811 }
2812 else if (id_type->flags & IDTYPE_FLAGS_NO_MEMFILE_UNDO) {
2813 CLOG_INFO(
2814 &LOG_UNDO, 2, "UNDO: skip restore datablock %s, 'NO_MEMFILE_UNDO' type of ID", id->name);
2815
2816 /* If that local noundo ID still exists currently, the call to
2817 * #read_undo_reuse_noundo_local_ids at the beginning of #blo_read_file_internal will already
2818 * have moved it into the new main, and populated accordingly the new_idmap_uid.
2819 *
2820 * If this is the case, it can also be remapped for newly read data. Otherwise, this is 'lost'
2821 * data that cannot be restored on undo, so no remapping should exist for it in the ID
2822 * oldnewmap. */
2823 if (id_old) {
2824 BLI_assert(id_old ==
2825 static_cast<ID *>(BKE_main_idmap_lookup_uid(fd->new_idmap_uid, id->session_uid)));
2826 oldnewmap_lib_insert(fd, bhead->old, id_old, bhead->code);
2827 }
2828 return true;
2829 }
2830
2831 if (!do_partial_undo) {
2833 2,
2834 "UNDO: read %s (uid %u) -> no partial undo, always read at new address",
2835 id->name,
2836 id->session_uid);
2837 return false;
2838 }
2839
2840 /* Restore local datablocks. */
2841 if (id_old != nullptr && read_libblock_is_identical(fd, bhead)) {
2842 /* Local datablock was unchanged, restore from the old main. */
2844 2,
2845 "UNDO: read %s (uid %u) -> keep identical datablock",
2846 id->name,
2847 id->session_uid);
2848
2849 read_libblock_undo_restore_identical(fd, main, id, id_old, bhead, id_tag);
2850
2851 *r_id_old = id_old;
2852 return true;
2853 }
2854 if (id_old != nullptr) {
2855 /* Local datablock was changed. Restore at the address of the old datablock. */
2857 2,
2858 "UNDO: read %s (uid %u) -> read to old existing address",
2859 id->name,
2860 id->session_uid);
2861 *r_id_old = id_old;
2862 return false;
2863 }
2864
2865 /* Local datablock does not exist in the undo step, so read from scratch. */
2866 CLOG_INFO(
2867 &LOG_UNDO, 2, "UNDO: read %s (uid %u) -> read at new address", id->name, id->session_uid);
2868 return false;
2869}
2870
2871/* This routine reads a datablock and its direct data, and advances bhead to
2872 * the next datablock. For library linked datablocks, only a placeholder will
2873 * be generated, to be replaced in read_library_linked_ids.
2874 *
2875 * When reading for undo, libraries, linked datablocks and unchanged datablocks
2876 * will be restored from the old database. Only new or changed datablocks will
2877 * actually be read. */
2879 Main *main,
2880 BHead *bhead,
2881 int id_tag,
2882 const bool placeholder_set_indirect_extern,
2883 ID **r_id)
2884{
2885 const bool do_partial_undo = (fd->skip_flags & BLO_READ_SKIP_UNDO_OLD_MAIN) == 0;
2886
2887 /* First attempt to restore existing datablocks for undo.
2888 * When datablocks are changed but still exist, we restore them at the old
2889 * address and inherit recalc flags for the dependency graph. */
2890 ID *id_old = nullptr;
2891 if (fd->flags & FD_FLAGS_IS_MEMFILE) {
2892 if (read_libblock_undo_restore(fd, main, bhead, id_tag, &id_old)) {
2893 if (r_id) {
2894 *r_id = id_old;
2895 }
2896 if (main->id_map != nullptr && id_old != nullptr) {
2897 BKE_main_idmap_insert_id(main->id_map, id_old);
2898 }
2899
2900 return blo_bhead_next(fd, bhead);
2901 }
2902 }
2903
2904 /* Read libblock struct. */
2905 const int id_type_index = BKE_idtype_idcode_to_index(bhead->code);
2906#ifndef NDEBUG
2907 const char *blockname = nullptr;
2908#else
2909 /* Avoid looking up in the mapping for all read BHead, since this only contains the ID type name
2910 * in release builds. */
2911 const char *blockname = get_alloc_name(fd, bhead, nullptr, id_type_index);
2912#endif
2913 ID *id = static_cast<ID *>(read_struct(fd, bhead, blockname, id_type_index));
2914 if (id == nullptr) {
2915 if (r_id) {
2916 *r_id = nullptr;
2917 }
2918 return blo_bhead_next(fd, bhead);
2919 }
2920
2921 /* Determine ID type and add to main database list. */
2922 const short idcode = GS(id->name);
2923 ListBase *lb = which_libbase(main, idcode);
2924 if (lb == nullptr) {
2925 /* Unknown ID type. */
2926 CLOG_WARN(&LOG, "Unknown id code '%c%c'", (idcode & 0xff), (idcode >> 8));
2927 MEM_freeN(id);
2928 if (r_id) {
2929 *r_id = nullptr;
2930 }
2931 return blo_bhead_next(fd, bhead);
2932 }
2933
2934 /* NOTE: id must be added to the list before direct_link_id(), since
2935 * direct_link_library() may remove it from there in case of duplicates. */
2936 BLI_addtail(lb, id);
2937
2938 /* Insert into library map for lookup by newly read datablocks (with pointer value bhead->old).
2939 * Note that existing datablocks in memory (which pointer value would be id_old) are not remapped
2940 * remapped anymore, so no need to store this info here. */
2941 ID *id_target = (do_partial_undo && id_old != nullptr) ? id_old : id;
2942 oldnewmap_lib_insert(fd, bhead->old, id_target, bhead->code);
2943
2944 if (r_id) {
2945 *r_id = id_target;
2946 }
2947
2948 /* Set tag for new datablock to indicate lib linking and versioning needs
2949 * to be done still. */
2950 id_tag |= (ID_TAG_NEED_LINK | ID_TAG_NEW);
2951
2952 if (bhead->code == ID_LINK_PLACEHOLDER) {
2953 /* Read placeholder for linked datablock. */
2955
2956 if (placeholder_set_indirect_extern) {
2957 if (id->flag & ID_FLAG_INDIRECT_WEAK_LINK) {
2958 id_tag |= ID_TAG_INDIRECT;
2959 }
2960 else {
2961 id_tag |= ID_TAG_EXTERN;
2962 }
2963 }
2964
2965 direct_link_id(fd, main, id_tag, id, id_old);
2966
2967 if (main->id_map != nullptr) {
2968 BKE_main_idmap_insert_id(main->id_map, id);
2969 }
2970
2971 return blo_bhead_next(fd, bhead);
2972 }
2973
2974 /* Read datablock contents.
2975 * Use convenient malloc name for debugging and better memory link prints. */
2976 bhead = read_data_into_datamap(fd, bhead, blockname, id_type_index);
2977 const bool success = direct_link_id(fd, main, id_tag, id, id_old);
2979
2980 if (!success) {
2981 /* XXX This is probably working OK currently given the very limited scope of that flag.
2982 * However, it is absolutely **not** handled correctly: it is freeing an ID pointer that has
2983 * been added to the fd->libmap mapping, which in theory could lead to nice crashes...
2984 * This should be properly solved at some point. */
2985 BKE_id_free(main, id);
2986 if (r_id != nullptr) {
2987 *r_id = nullptr;
2988 }
2989 }
2990 else {
2991 if (do_partial_undo && id_old != nullptr) {
2992 /* For undo, store contents read into id at id_old. */
2994 }
2995 if (fd->new_idmap_uid != nullptr) {
2997 }
2998 if (main->id_map != nullptr) {
2999 BKE_main_idmap_insert_id(main->id_map, id_target);
3000 }
3001 }
3002
3003 return bhead;
3004}
3005
3008/* -------------------------------------------------------------------- */
3013{
3015
3016 bhead = read_data_into_datamap(fd, bhead, "Data for Asset meta-data", INDEX_ID_NULL);
3017
3018 BlendDataReader reader = {fd};
3019 BLO_read_struct(&reader, AssetMetaData, r_asset_data);
3020 BKE_asset_metadata_read(&reader, *r_asset_data);
3021
3023
3024 return bhead;
3025}
3026
3029/* -------------------------------------------------------------------- */
3033/* NOTE: this has to be kept for reading older files... */
3034/* also version info is written here */
3036{
3037 FileGlobal *fg = static_cast<FileGlobal *>(
3038 read_struct(fd, bhead, "Data from Global block", INDEX_ID_NULL));
3039
3040 /* NOTE: `bfd->main->versionfile` is supposed to have already been set from `fd->fileversion`
3041 * beforehand by calling code. */
3042 bfd->main->subversionfile = fg->subversion;
3045
3046 bfd->main->minversionfile = fg->minversion;
3048
3050 STRNCPY(bfd->main->build_hash, fg->build_hash);
3052
3053 bfd->fileflags = fg->fileflags;
3054 bfd->globalf = fg->globalf;
3055
3056 /* NOTE: since 88b24bc6bb, `fg->filepath` is only written for crash recovery and autosave files,
3057 * so only overwrite `fd->relabase` if it is not empty, in case a regular blendfile is opened
3058 * through one of the 'recover' operators.
3059 *
3060 * In all other cases, the path is just set to the current path of the blendfile being read, so
3061 * there is no need to handle anymore older files (pre-2.65) that did not store (correctly) their
3062 * path. */
3063 if (G.fileflags & G_FILE_RECOVER_READ) {
3064 if (fg->filepath[0] != '\0') {
3065 STRNCPY(fd->relabase, fg->filepath);
3066 /* Used to set expected original filepath in read Main, instead of the path of the recovery
3067 * file itself. */
3068 STRNCPY(bfd->filepath, fg->filepath);
3069 }
3070 }
3071
3072 bfd->curscreen = fg->curscreen;
3073 bfd->curscene = fg->curscene;
3074 bfd->cur_view_layer = fg->cur_view_layer;
3075
3076 MEM_freeN(fg);
3077
3078 fd->globalf = bfd->globalf;
3079 fd->fileflags = bfd->fileflags;
3080
3081 return blo_bhead_next(fd, bhead);
3082}
3083
3084/* NOTE: this has to be kept for reading older files... */
3085static void link_global(FileData *fd, BlendFileData *bfd)
3086{
3087 bfd->cur_view_layer = static_cast<ViewLayer *>(
3089 bfd->curscreen = static_cast<bScreen *>(newlibadr(fd, nullptr, false, bfd->curscreen));
3090 bfd->curscene = static_cast<Scene *>(newlibadr(fd, nullptr, false, bfd->curscene));
3091 /* this happens in files older than 2.35 */
3092 if (bfd->curscene == nullptr) {
3093 if (bfd->curscreen) {
3094 bfd->curscene = bfd->curscreen->scene;
3095 }
3096 }
3097 if (bfd->curscene == nullptr) {
3098 bfd->curscene = static_cast<Scene *>(bfd->main->scenes.first);
3099 }
3100}
3101
3104/* -------------------------------------------------------------------- */
3108static void do_versions_userdef(FileData * /*fd*/, BlendFileData *bfd)
3109{
3110 UserDef *user = bfd->user;
3111
3112 if (user == nullptr) {
3113 return;
3114 }
3115
3117}
3118
3120{
3121 /* WATCH IT!!!: pointers from libdata have not been converted */
3122
3123 /* Don't allow versioning to create new data-blocks. */
3124 main->is_locked_for_linking = true;
3125
3126 if (G.debug & G_DEBUG) {
3127 char build_commit_datetime[32];
3128 time_t temp_time = main->build_commit_timestamp;
3129 tm *tm = (temp_time) ? gmtime(&temp_time) : nullptr;
3130 if (LIKELY(tm)) {
3131 strftime(build_commit_datetime, sizeof(build_commit_datetime), "%Y-%m-%d %H:%M", tm);
3132 }
3133 else {
3134 STRNCPY(build_commit_datetime, "unknown");
3135 }
3136
3137 CLOG_INFO(&LOG, 0, "Read file %s", fd->relabase);
3138 CLOG_INFO(&LOG,
3139 0,
3140 " Version %d sub %d date %s hash %s",
3141 main->versionfile,
3142 main->subversionfile,
3143 build_commit_datetime,
3144 main->build_hash);
3145 }
3146
3147 if (!main->is_read_invalid) {
3149 }
3150 if (!main->is_read_invalid) {
3152 }
3153 if (!main->is_read_invalid) {
3155 }
3156 if (!main->is_read_invalid) {
3158 }
3159 if (!main->is_read_invalid) {
3161 }
3162 if (!main->is_read_invalid) {
3164 }
3165 if (!main->is_read_invalid) {
3167 }
3168 if (!main->is_read_invalid) {
3170 }
3171
3172 /* WATCH IT!!!: pointers from libdata have not been converted yet here! */
3173 /* WATCH IT 2!: Userdef struct init see do_versions_userdef() above! */
3174
3175 /* don't forget to set version number in BKE_blender_version.h! */
3176
3177 main->is_locked_for_linking = false;
3178}
3179
3181{
3182 BLI_assert(fd != nullptr);
3183
3184 CLOG_INFO(&LOG,
3185 2,
3186 "Processing %s (%s), %d.%d",
3187 main->curlib ? main->curlib->filepath : main->filepath,
3188 main->curlib ? "LIB" : "MAIN",
3189 main->versionfile,
3190 main->subversionfile);
3191
3192 /* Don't allow versioning to create new data-blocks. */
3193 main->is_locked_for_linking = true;
3194
3195 if (!main->is_read_invalid) {
3197 }
3198 if (!main->is_read_invalid) {
3200 }
3201 if (!main->is_read_invalid) {
3203 }
3204 if (!main->is_read_invalid) {
3206 }
3207 if (!main->is_read_invalid) {
3209 }
3210 if (!main->is_read_invalid) {
3212 }
3213 if (!main->is_read_invalid) {
3215 }
3216
3217 main->is_locked_for_linking = false;
3218}
3219
3222/* -------------------------------------------------------------------- */
3227{
3228 /* Embedded IDs are not known by lib_link code, so they would be remapped to `nullptr`. But there
3229 * is no need to process them anyway, as they are already handled during the 'read_data' phase.
3230 *
3231 * NOTE: Some external non-owning pointers to embedded IDs (like the node-tree pointers of the
3232 * Node editor) will not be detected as embedded ones though at 'lib_link' stage (because their
3233 * source data cannot be accessed). This is handled on a case-by-case basis in 'after_lib_link'
3234 * validation code. */
3236 return IDWALK_RET_NOP;
3237 }
3238
3239 /* Explicitly requested to be ignored during readfile processing. Means the read_data code
3240 * already handled this pointer. Typically, the 'owner_id' pointer of an embedded ID. */
3241 if (cb_data->cb_flag & IDWALK_CB_READFILE_IGNORE) {
3242 return IDWALK_RET_NOP;
3243 }
3244
3245 BlendLibReader *reader = static_cast<BlendLibReader *>(cb_data->user_data);
3246 ID **id_ptr = cb_data->id_pointer;
3247 ID *owner_id = cb_data->owner_id;
3248
3249 *id_ptr = BLO_read_get_new_id_address(reader, owner_id, ID_IS_LINKED(owner_id), *id_ptr);
3250
3251 return IDWALK_RET_NOP;
3252}
3253
3254static void lib_link_all(FileData *fd, Main *bmain)
3255{
3256 BlendLibReader reader = {fd, bmain};
3257
3258 ID *id;
3259 FOREACH_MAIN_ID_BEGIN (bmain, id) {
3260 const IDTypeInfo *id_type = BKE_idtype_get_info_from_id(id);
3261
3263 {
3265 /* This ID has been re-used from 'old' bmain. Since it was therefore unchanged across
3266 * current undo step, and old IDs re-use their old memory address, we do not need to liblink
3267 * it at all. */
3268 BLI_assert((id->tag & ID_TAG_NEED_LINK) == 0);
3269
3270 /* Some data that should be persistent, like the 3DCursor or the tool settings, are
3271 * stored in IDs affected by undo, like Scene. So this requires some specific handling. */
3272 /* NOTE: even though the ID may have been detected as unchanged, the 'undo_preserve' may have
3273 * to actually change some of its ID pointers, it's e.g. the case with Scene's tool-settings
3274 * Brush/Palette pointers. This is the case where both new and old ID may be the same. */
3275 if (id_type->blend_read_undo_preserve != nullptr) {
3277 id_type->blend_read_undo_preserve(&reader, id, id->orig_id ? id->orig_id : id);
3278 }
3279 continue;
3280 }
3281
3282 if ((id->tag & ID_TAG_NEED_LINK) != 0) {
3283 /* Not all original pointer values can be considered as valid.
3284 * Handling of DNA deprecated data should never be needed in undo case. */
3287 BKE_library_foreach_ID_link(bmain, id, lib_link_cb, &reader, flag);
3288
3289 after_liblink_id_process(&reader, id);
3290
3291 id->tag &= ~ID_TAG_NEED_LINK;
3292 }
3293
3294 /* Some data that should be persistent, like the 3DCursor or the tool settings, are
3295 * stored in IDs affected by undo, like Scene. So this requires some specific handling. */
3296 if (id_type->blend_read_undo_preserve != nullptr && id->orig_id != nullptr) {
3298 id_type->blend_read_undo_preserve(&reader, id, id->orig_id);
3299 }
3300 }
3302
3303 /* Cleanup `ID.orig_id`, this is now reserved for depsgraph/copy-on-eval usage only. */
3304 FOREACH_MAIN_ID_BEGIN (bmain, id) {
3305 id->orig_id = nullptr;
3306 }
3308
3309#ifndef NDEBUG
3310 /* Double check we do not have any 'need link' tag remaining, this should never be the case once
3311 * this function has run. */
3312 FOREACH_MAIN_ID_BEGIN (bmain, id) {
3313 BLI_assert((id->tag & ID_TAG_NEED_LINK) == 0);
3314 }
3316#endif
3317}
3318
3325{
3326 /* We only expect a merged Main here, not a split one. */
3327 BLI_assert((bmain->prev == nullptr) && (bmain->next == nullptr));
3328
3330 BKE_report(
3331 reports ? reports->reports : nullptr,
3332 RPT_ERROR,
3333 "Critical blend-file corruption: Conflicts and/or otherwise invalid data-blocks names "
3334 "(see console for details)");
3335 }
3336
3337 /* Check for possible cycles in scenes' 'set' background property. */
3339
3340 /* We could integrate that to mesh/curve/lattice lib_link, but this is really cheap process,
3341 * so simpler to just use it directly in this single call. */
3342 BLO_main_validate_shapekeys(bmain, reports ? reports->reports : nullptr);
3343
3344 BLO_main_validate_embedded_flag(bmain, reports ? reports->reports : nullptr);
3345 BLO_main_validate_embedded_liboverrides(bmain, reports ? reports->reports : nullptr);
3346
3347 /* We have to rebuild that runtime information *after* all data-blocks have been properly linked.
3348 */
3350}
3351
3354/* -------------------------------------------------------------------- */
3359{
3360 BLO_read_struct(reader, IDProperty, &kmi->properties);
3361 IDP_BlendDataRead(reader, &kmi->properties);
3362 kmi->ptr = nullptr;
3363 kmi->flag &= ~KMI_UPDATE;
3364}
3365
3367{
3368 UserDef *user;
3369 bfd->user = user = static_cast<UserDef *>(
3370 read_struct(fd, bhead, "Data for User Def", INDEX_ID_NULL));
3371
3372 /* User struct has separate do-version handling */
3373 user->versionfile = bfd->main->versionfile;
3374 user->subversionfile = bfd->main->subversionfile;
3375
3376 /* read all data into fd->datamap */
3377 bhead = read_data_into_datamap(fd, bhead, "Data for User Def", INDEX_ID_NULL);
3378
3379 BlendDataReader reader_ = {fd};
3380 BlendDataReader *reader = &reader_;
3381
3382 BLO_read_struct_list(reader, bTheme, &user->themes);
3385 BLO_read_struct_list(reader, bUserMenu, &user->user_menus);
3386 BLO_read_struct_list(reader, bAddon, &user->addons);
3392
3393 LISTBASE_FOREACH (wmKeyMap *, keymap, &user->user_keymaps) {
3394 keymap->modal_items = nullptr;
3395 keymap->poll = nullptr;
3396 keymap->flag &= ~KEYMAP_UPDATE;
3397
3398 BLO_read_struct_list(reader, wmKeyMapDiffItem, &keymap->diff_items);
3399 BLO_read_struct_list(reader, wmKeyMapItem, &keymap->items);
3400
3401 LISTBASE_FOREACH (wmKeyMapDiffItem *, kmdi, &keymap->diff_items) {
3402 BLO_read_struct(reader, wmKeyMapItem, &kmdi->remove_item);
3403 BLO_read_struct(reader, wmKeyMapItem, &kmdi->add_item);
3404
3405 if (kmdi->remove_item) {
3406 direct_link_keymapitem(reader, kmdi->remove_item);
3407 }
3408 if (kmdi->add_item) {
3409 direct_link_keymapitem(reader, kmdi->add_item);
3410 }
3411 }
3412
3413 LISTBASE_FOREACH (wmKeyMapItem *, kmi, &keymap->items) {
3414 direct_link_keymapitem(reader, kmi);
3415 }
3416 }
3417
3419 BLO_read_struct(reader, IDProperty, &kpt->prop);
3420 IDP_BlendDataRead(reader, &kpt->prop);
3421 }
3422
3423 LISTBASE_FOREACH (bUserMenu *, um, &user->user_menus) {
3424 BLO_read_struct_list(reader, bUserMenuItem, &um->items);
3425 LISTBASE_FOREACH (bUserMenuItem *, umi, &um->items) {
3426 if (umi->type == USER_MENU_TYPE_OPERATOR) {
3427 bUserMenuItem_Op *umi_op = (bUserMenuItem_Op *)umi;
3428 BLO_read_struct(reader, IDProperty, &umi_op->prop);
3429 IDP_BlendDataRead(reader, &umi_op->prop);
3430 }
3431 }
3432 }
3433
3434 LISTBASE_FOREACH (bAddon *, addon, &user->addons) {
3435 BLO_read_struct(reader, IDProperty, &addon->prop);
3436 IDP_BlendDataRead(reader, &addon->prop);
3437 }
3438
3441 }
3442
3444 BKE_asset_catalog_path_list_blend_read_data(reader, shelf_settings->enabled_catalog_paths);
3445 }
3446
3447 /* XXX */
3448 user->uifonts.first = user->uifonts.last = nullptr;
3449
3450 BLO_read_struct_list(reader, uiStyle, &user->uistyles);
3451
3452 /* Don't read the active app template, use the default one. */
3453 user->app_template[0] = '\0';
3454
3455 /* Clear runtime data. */
3456 user->runtime.is_dirty = false;
3457 user->edit_studio_light = 0;
3458
3459 /* free fd->datamap again */
3461
3462 return bhead;
3463}
3464
3467/* -------------------------------------------------------------------- */
3472{
3474 return IDWALK_RET_NOP;
3475 }
3476
3477 IDNameLib_Map *new_idmap_uid = static_cast<IDNameLib_Map *>(cb_data->user_data);
3478 ID **id_pointer = cb_data->id_pointer;
3479 if (*id_pointer != nullptr) {
3480 *id_pointer = BKE_main_idmap_lookup_uid(new_idmap_uid, (*id_pointer)->session_uid);
3481 }
3482
3483 return IDWALK_RET_NOP;
3484}
3485
3486/* Remap 'no undo' ID usages to matching IDs in new main.
3487 *
3488 * 'no undo' IDs have simply be moved from old to new main so far. However, unlike the other
3489 * re-used IDs (the 'unchanged' ones), there is no guarantee that all the ID pointers they use are
3490 * still valid.
3491 *
3492 * This code performs a remapping based on the session_uid. */
3494{
3495 Main *new_bmain = static_cast<Main *>(fd->mainlist->first);
3496 ID *id_iter;
3497 FOREACH_MAIN_ID_BEGIN (new_bmain, id_iter) {
3498 if (ID_IS_LINKED(id_iter)) {
3499 continue;
3500 }
3501 if ((id_iter->tag & ID_TAG_UNDO_OLD_ID_REUSED_NOUNDO) == 0) {
3502 continue;
3503 }
3504
3507 }
3509}
3510
3515static void blo_read_file_checks(Main *bmain)
3516{
3517#ifndef NDEBUG
3518 BLI_assert(bmain->next == nullptr);
3519 BLI_assert(!bmain->is_read_invalid);
3520
3521 LISTBASE_FOREACH (wmWindowManager *, wm, &bmain->wm) {
3522 LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
3523 /* This pointer is deprecated and should always be nullptr. */
3524 BLI_assert(win->screen == nullptr);
3525 }
3526 }
3527#endif
3528 UNUSED_VARS_NDEBUG(bmain);
3529}
3530
3532{
3533 BHead *bhead = blo_bhead_first(fd);
3534 BlendFileData *bfd;
3535 ListBase mainlist = {nullptr, nullptr};
3536
3537 const bool is_undo = (fd->flags & FD_FLAGS_IS_MEMFILE) != 0;
3538 if (is_undo) {
3539 CLOG_INFO(&LOG_UNDO, 2, "UNDO: read step");
3540 }
3541
3542 /* Prevent any run of layer collections rebuild during readfile process, and the do_versions
3543 * calls.
3544 *
3545 * NOTE: Typically readfile code should not trigger such updates anyway. But some calls to
3546 * non-BLO functions (e.g. ID deletion) can indirectly trigger it. */
3548
3549 bfd = static_cast<BlendFileData *>(MEM_callocN(sizeof(BlendFileData), "blendfiledata"));
3550
3551 bfd->main = BKE_main_new();
3552 bfd->main->versionfile = fd->fileversion;
3553 STRNCPY(bfd->filepath, filepath);
3554
3555 bfd->type = BLENFILETYPE_BLEND;
3556
3557 if ((fd->skip_flags & BLO_READ_SKIP_DATA) == 0) {
3558 BLI_addtail(&mainlist, bfd->main);
3559 fd->mainlist = &mainlist;
3560 STRNCPY(bfd->main->filepath, filepath);
3561 }
3562
3563 if (G.background) {
3564 /* We only read & store .blend thumbnail in background mode
3565 * (because we cannot re-generate it, no OpenGL available).
3566 */
3567 const int *data = read_file_thumbnail(fd);
3568
3569 if (data) {
3570 const int width = data[0];
3571 const int height = data[1];
3572 if (BLEN_THUMB_MEMSIZE_IS_VALID(width, height)) {
3573 const size_t data_size = BLEN_THUMB_MEMSIZE(width, height);
3574 bfd->main->blen_thumb = static_cast<BlendThumbnail *>(MEM_mallocN(data_size, __func__));
3575
3576 BLI_assert((data_size - sizeof(*bfd->main->blen_thumb)) ==
3577 (BLEN_THUMB_MEMSIZE_FILE(width, height) - (sizeof(*data) * 2)));
3578 bfd->main->blen_thumb->width = width;
3579 bfd->main->blen_thumb->height = height;
3580 memcpy(bfd->main->blen_thumb->rect, &data[2], data_size - sizeof(*bfd->main->blen_thumb));
3581 }
3582 }
3583 }
3584
3585 if (is_undo) {
3586 /* This idmap will store uids of all IDs ending up in the new main, whether they are newly
3587 * read, or re-used from the old main. */
3589 static_cast<Main *>(fd->mainlist->first), false, nullptr, MAIN_IDMAP_TYPE_UID);
3590
3591 /* Copy all 'no undo' local data from old to new bmain. */
3593 }
3594
3595 while (bhead) {
3596 switch (bhead->code) {
3597 case BLO_CODE_DATA:
3598 case BLO_CODE_DNA1:
3599 case BLO_CODE_TEST: /* used as preview since 2.5x */
3600 case BLO_CODE_REND:
3601 bhead = blo_bhead_next(fd, bhead);
3602 break;
3603 case BLO_CODE_GLOB:
3604 bhead = read_global(bfd, fd, bhead);
3605 break;
3606 case BLO_CODE_USER:
3608 bhead = blo_bhead_next(fd, bhead);
3609 }
3610 else {
3611 bhead = read_userdef(bfd, fd, bhead);
3612 }
3613 break;
3614 case BLO_CODE_ENDB:
3615 bhead = nullptr;
3616 break;
3617
3619 if (fd->skip_flags & BLO_READ_SKIP_DATA) {
3620 bhead = blo_bhead_next(fd, bhead);
3621 }
3622 else {
3623 /* Add link placeholder to the main of the library it belongs to.
3624 * The library is the most recently loaded ID_LI block, according
3625 * to the file format definition. So we can use the entry at the
3626 * end of mainlist, added in direct_link_library. */
3627 Main *libmain = static_cast<Main *>(mainlist.last);
3628 bhead = read_libblock(fd, libmain, bhead, 0, true, nullptr);
3629 }
3630 break;
3631 /* in 2.50+ files, the file identifier for screens is patched, forward compatibility */
3632 case ID_SCRN:
3633 bhead->code = ID_SCR;
3634 /* pass on to default */
3636 default: {
3637 if (blo_bhead_is_id_valid_type(bhead)) {
3638 /* BHead is a valid known ID type one, read the whole ID and its sub-data, unless reading
3639 * actual data is skipped. */
3640 if (fd->skip_flags & BLO_READ_SKIP_DATA) {
3641 bhead = blo_bhead_next(fd, bhead);
3642 }
3643 else {
3644 bhead = read_libblock(fd, bfd->main, bhead, ID_TAG_LOCAL, false, nullptr);
3645 }
3646 }
3647 else {
3648 /* Unknown BHead type (or ID type), ignore it and skip to next BHead. */
3649 bhead = blo_bhead_next(fd, bhead);
3650 }
3651 }
3652 }
3653
3654 if (bfd->main->is_read_invalid) {
3655 return bfd;
3656 }
3657 }
3658
3659 if (is_undo) {
3660 /* Move the remaining Library IDs and their linked data to the new main.
3661 *
3662 * NOTE: These linked IDs have not been detected as used in newly read main. However, they
3663 * could be dependencies from some 'no undo' IDs that were unconditionally moved from the old
3664 * to the new main.
3665 *
3666 * While there could be some more refined check here to detect such cases and only move these
3667 * into the new bmain, in practice it is simpler to systematically move all linked data. The
3668 * handling of libraries already moves all their linked IDs too, regardless of whether they are
3669 * effectively used or not. */
3670
3671 Main *new_main = bfd->main;
3672 Main *old_main = static_cast<Main *>(fd->old_mainlist->first);
3673 BLI_assert(old_main != nullptr);
3674 BLI_assert(old_main->curlib == nullptr);
3675 Main *libmain, *libmain_next;
3676 for (libmain = old_main->next; libmain != nullptr; libmain = libmain_next) {
3677 libmain_next = libmain->next;
3678 read_undo_move_libmain_data(fd, new_main, old_main, libmain, nullptr);
3679 }
3680 }
3681
3682 /* Do versioning before read_libraries, but skip in undo case. */
3683 if (!is_undo) {
3684 if ((fd->skip_flags & BLO_READ_SKIP_DATA) == 0) {
3685 do_versions(fd, nullptr, bfd->main);
3686 }
3687
3688 if ((fd->skip_flags & BLO_READ_SKIP_USERDEF) == 0) {
3689 do_versions_userdef(fd, bfd);
3690 }
3691 }
3692
3693 if (bfd->main->is_read_invalid) {
3694 return bfd;
3695 }
3696
3697 if ((fd->skip_flags & BLO_READ_SKIP_DATA) == 0) {
3699 read_libraries(fd, &mainlist);
3700
3701 blo_join_main(&mainlist);
3702
3703 lib_link_all(fd, bfd->main);
3705
3706 if (is_undo) {
3707 /* Ensure ID usages of reused 'no undo' IDs remain valid. */
3708 /* Although noundo data was reused as-is from the old main, it may have ID pointers to data
3709 * that has been removed, or that have a new address. */
3711 }
3712
3714
3715 /* Skip in undo case. */
3716 if (!is_undo) {
3717 /* Note that we can't recompute user-counts at this point in undo case, we play too much with
3718 * IDs from different memory realms, and Main database is not in a fully valid state yet.
3719 */
3720 /* Some versioning code does expect some proper user-reference-counting, e.g. in conversion
3721 * from groups to collections... We could optimize out that first call when we are reading a
3722 * current version file, but again this is really not a bottle neck currently.
3723 * So not worth it. */
3725
3726 /* Necessary to allow 2.80 layer collections conversion code to work. */
3728
3729 /* Yep, second splitting... but this is a very cheap operation, so no big deal. */
3730 blo_split_main(&mainlist, bfd->main);
3731 LISTBASE_FOREACH (Main *, mainvar, &mainlist) {
3732 /* Do versioning for newly added linked data-blocks. If no data-blocks were read from a
3733 * library versionfile will still be zero and we can skip it. */
3734 if (mainvar->versionfile == 0) {
3735 continue;
3736 }
3737 do_versions_after_linking((mainvar->curlib && mainvar->curlib->runtime.filedata) ?
3738 mainvar->curlib->runtime.filedata :
3739 fd,
3740 mainvar);
3741 }
3742 blo_join_main(&mainlist);
3743
3745
3746 /* And we have to compute those user-reference-counts again, as `do_versions_after_linking()`
3747 * does not always properly handle user counts, and/or that function does not take into
3748 * account old, deprecated data. */
3750 }
3751
3753 /* Now we can clear this runtime library filedata, it is not needed anymore. */
3754 if (lib->runtime.filedata) {
3755 BLI_assert(lib->runtime.versionfile != 0);
3756 blo_filedata_free(lib->runtime.filedata);
3757 lib->runtime.filedata = nullptr;
3758 }
3759 /* If no data-blocks were read from a library (should only happen when all references to a
3760 * library's data are `ID_FLAG_INDIRECT_WEAK_LINK`), its versionfile will still be zero and
3761 * it can be deleted.
3762 *
3763 * NOTES:
3764 * - In case the library blendfile exists but is missing all the referenced linked IDs, the
3765 * placeholders IDs created will reference the library ID, and the library ID will have a
3766 * valid version number as the file was read to search for the linked IDs.
3767 * - In case the library blendfile does not exist, its local Library ID will get the version
3768 * of the current local Main (i.e. the loaded blendfile). */
3769 else if (lib->runtime.versionfile == 0) {
3770#ifndef NDEBUG
3771 ID *id_iter;
3772 FOREACH_MAIN_ID_BEGIN (bfd->main, id_iter) {
3773 BLI_assert(id_iter->lib != lib);
3774 }
3776#endif
3777 BKE_id_delete(bfd->main, lib);
3778 }
3779 }
3780
3781 if (bfd->main->is_read_invalid) {
3782 return bfd;
3783 }
3784
3785 /* After all data has been read and versioned, uses ID_TAG_NEW. Theoretically this should
3786 * not be calculated in the undo case, but it is currently needed even on undo to recalculate
3787 * a cache. */
3789
3791
3792 BKE_main_id_tag_all(bfd->main, ID_TAG_NEW, false);
3793
3794 /* Must happen before applying liboverrides, as this process may fully invalidate e.g. view
3795 * layer pointers in case a Scene is a liboverride. */
3796 link_global(fd, bfd);
3797
3798 /* Now that all our data-blocks are loaded,
3799 * we can re-generate overrides from their references. */
3800 if (!is_undo) {
3801 /* Do not apply in undo case! */
3803
3804 std::string cur_view_layer_name = bfd->cur_view_layer != nullptr ?
3805 bfd->cur_view_layer->name :
3806 "";
3807
3810
3811 /* In case the current scene is a liboverride, while the ID pointer itself remains valid,
3812 * above update of liboverrides will have completely invalidated its old content, so the
3813 * current view-layer needs to be searched for again. */
3814 if (bfd->cur_view_layer != nullptr) {
3815 bfd->cur_view_layer = BKE_view_layer_find(bfd->curscene, cur_view_layer_name.c_str());
3816 }
3817
3818 /* FIXME Temporary 'fix' to a problem in how temp ID are copied in
3819 * `BKE_lib_override_library_main_update`, see #103062.
3820 * Proper fix involves first addressing #90610. */
3822
3825 }
3826
3828
3830
3831 /* Make all relative paths, relative to the open blend file. */
3833 }
3834 else {
3836 }
3837
3838 fd->mainlist = nullptr; /* Safety, this is local variable, shall not be used afterward. */
3839
3840 BLI_assert(bfd->main->id_map == nullptr);
3841
3842 /* Sanity checks. */
3844
3845 return bfd;
3846}
3847
3850/* -------------------------------------------------------------------- */
3858 const void *old;
3859};
3860
3861static int verg_bheadsort(const void *v1, const void *v2)
3862{
3863 const BHeadSort *x1 = static_cast<const BHeadSort *>(v1),
3864 *x2 = static_cast<const BHeadSort *>(v2);
3865
3866 if (x1->old > x2->old) {
3867 return 1;
3868 }
3869 if (x1->old < x2->old) {
3870 return -1;
3871 }
3872 return 0;
3873}
3874
3876{
3877 BHead *bhead;
3878 BHeadSort *bhs;
3879 int tot = 0;
3880
3881 for (bhead = blo_bhead_first(fd); bhead; bhead = blo_bhead_next(fd, bhead)) {
3882 tot++;
3883 }
3884
3885 fd->tot_bheadmap = tot;
3886 if (tot == 0) {
3887 return;
3888 }
3889
3890 bhs = fd->bheadmap = static_cast<BHeadSort *>(
3891 MEM_malloc_arrayN(tot, sizeof(BHeadSort), "BHeadSort"));
3892
3893 for (bhead = blo_bhead_first(fd); bhead; bhead = blo_bhead_next(fd, bhead), bhs++) {
3894 bhs->bhead = bhead;
3895 bhs->old = bhead->old;
3896 }
3897
3898 qsort(fd->bheadmap, tot, sizeof(BHeadSort), verg_bheadsort);
3899}
3900
3902{
3903 /* Skip library data-blocks in undo, see comment in read_libblock. */
3904 if (fd->flags & FD_FLAGS_IS_MEMFILE) {
3905 return nullptr;
3906 }
3907
3908 for (; bhead; bhead = blo_bhead_prev(fd, bhead)) {
3909 if (bhead->code == ID_LI) {
3910 break;
3911 }
3912 }
3913
3914 return bhead;
3915}
3916
3917static BHead *find_bhead(FileData *fd, void *old)
3918{
3919#if 0
3920 BHead *bhead;
3921#endif
3922 BHeadSort *bhs, bhs_s;
3923
3924 if (!old) {
3925 return nullptr;
3926 }
3927
3928 if (fd->bheadmap == nullptr) {
3930 }
3931
3932 bhs_s.old = old;
3933 bhs = static_cast<BHeadSort *>(
3934 bsearch(&bhs_s, fd->bheadmap, fd->tot_bheadmap, sizeof(BHeadSort), verg_bheadsort));
3935
3936 if (bhs) {
3937 return bhs->bhead;
3938 }
3939
3940#if 0
3941 for (bhead = blo_bhead_first(fd); bhead; bhead = blo_bhead_next(fd, bhead)) {
3942 if (bhead->old == old) {
3943 return bhead;
3944 }
3945 }
3946#endif
3947
3948 return nullptr;
3949}
3950
3951static BHead *find_bhead_from_code_name(FileData *fd, const short idcode, const char *name)
3952{
3953#ifdef USE_GHASH_BHEAD
3954
3955 char idname_full[MAX_ID_NAME];
3956
3957 *((short *)idname_full) = idcode;
3958 BLI_strncpy(idname_full + 2, name, sizeof(idname_full) - 2);
3959
3960 return static_cast<BHead *>(BLI_ghash_lookup(fd->bhead_idname_hash, idname_full));
3961
3962#else
3963 BHead *bhead;
3964
3965 for (bhead = blo_bhead_first(fd); bhead; bhead = blo_bhead_next(fd, bhead)) {
3966 if (bhead->code == idcode) {
3967 const char *idname_test = blo_bhead_id_name(fd, bhead);
3968 if (STREQ(idname_test + 2, name)) {
3969 return bhead;
3970 }
3971 }
3972 else if (bhead->code == ENDB) {
3973 break;
3974 }
3975 }
3976
3977 return nullptr;
3978#endif
3979}
3980
3981static BHead *find_bhead_from_idname(FileData *fd, const char *idname)
3982{
3983#ifdef USE_GHASH_BHEAD
3984 return static_cast<BHead *>(BLI_ghash_lookup(fd->bhead_idname_hash, idname));
3985#else
3986 return find_bhead_from_code_name(fd, GS(idname), idname + 2);
3987#endif
3988}
3989
3990static ID *library_id_is_yet_read(FileData *fd, Main *mainvar, BHead *bhead)
3991{
3992 if (mainvar->id_map == nullptr) {
3993 mainvar->id_map = BKE_main_idmap_create(mainvar, false, nullptr, MAIN_IDMAP_TYPE_NAME);
3994 }
3995 BLI_assert(BKE_main_idmap_main_get(mainvar->id_map) == mainvar);
3996
3997 const char *idname = blo_bhead_id_name(fd, bhead);
3998
3999 ID *id = BKE_main_idmap_lookup_name(mainvar->id_map, GS(idname), idname + 2, mainvar->curlib);
4000 BLI_assert(id == BLI_findstring(which_libbase(mainvar, GS(idname)), idname, offsetof(ID, name)));
4001 return id;
4002}
4003
4006/* -------------------------------------------------------------------- */
4015
4016static void expand_doit_library(void *fdhandle, Main *mainvar, void *old)
4017{
4018 FileData *fd = static_cast<FileData *>(fdhandle);
4019
4020 if (mainvar->is_read_invalid) {
4021 return;
4022 }
4023
4024 BHead *bhead = find_bhead(fd, old);
4025 if (bhead == nullptr) {
4026 return;
4027 }
4028 /* In 2.50+ file identifier for screens is patched, forward compatibility. */
4029 if (bhead->code == ID_SCRN) {
4030 bhead->code = ID_SCR;
4031 }
4032 if (!blo_bhead_is_id_valid_type(bhead)) {
4033 return;
4034 }
4035
4036 if (bhead->code == ID_LINK_PLACEHOLDER) {
4037 /* Placeholder link to data-block in another library. */
4038 BHead *bheadlib = find_previous_lib(fd, bhead);
4039 if (bheadlib == nullptr) {
4040 return;
4041 }
4042
4043 Library *lib = static_cast<Library *>(
4044 read_struct(fd, bheadlib, "Data for Library ID type", INDEX_ID_NULL));
4045 Main *libmain = blo_find_main(fd, lib->filepath, fd->relabase);
4046
4047 if (libmain->curlib == nullptr) {
4048 const char *idname = blo_bhead_id_name(fd, bhead);
4049
4052 RPT_("LIB: Data refers to main .blend file: '%s' from %s"),
4053 idname,
4054 mainvar->curlib->runtime.filepath_abs);
4055 return;
4056 }
4057
4058 ID *id = library_id_is_yet_read(fd, libmain, bhead);
4059
4060 if (id == nullptr) {
4061 /* ID has not been read yet, add placeholder to the main of the
4062 * library it belongs to, so that it will be read later. */
4063 read_libblock(fd, libmain, bhead, fd->id_tag_extra | ID_TAG_INDIRECT, false, &id);
4064 BLI_assert(id != nullptr);
4065 id_sort_by_name(which_libbase(libmain, GS(id->name)), id, static_cast<ID *>(id->prev));
4066
4067 /* commented because this can print way too much */
4068 // if (G.debug & G_DEBUG) printf("expand_doit: other lib %s\n", lib->filepath);
4069
4070 /* for outliner dependency only */
4071 libmain->curlib->runtime.parent = mainvar->curlib;
4072 }
4073 else {
4074 /* Convert any previously read weak link to regular link
4075 * to signal that we want to read this data-block. */
4076 if (id->tag & ID_TAG_ID_LINK_PLACEHOLDER) {
4077 id->flag &= ~ID_FLAG_INDIRECT_WEAK_LINK;
4078 }
4079
4080 /* "id" is either a placeholder or real ID that is already in the
4081 * main of the library (A) it belongs to. However it might have been
4082 * put there by another library (C) which only updated its own
4083 * fd->libmap. In that case we also need to update the fd->libmap
4084 * of the current library (B) so we can find it for lookups.
4085 *
4086 * An example of such a setup is:
4087 * (A) tree.blend: contains Tree object.
4088 * (B) forest.blend: contains Forest collection linking in Tree from tree.blend.
4089 * (C) shot.blend: links in both Tree from tree.blend and Forest from forest.blend.
4090 */
4091 oldnewmap_lib_insert(fd, bhead->old, id, bhead->code);
4092
4093 /* Commented because this can print way too much. */
4094#if 0
4095 if (G.debug & G_DEBUG) {
4096 printf("expand_doit: already linked: %s lib: %s\n", id->name, lib->filepath);
4097 }
4098#endif
4099 }
4100
4101 MEM_freeN(lib);
4102 }
4103 else {
4104 /* Data-block in same library. */
4105 ID *id = library_id_is_yet_read(fd, mainvar, bhead);
4106 if (id == nullptr) {
4108 fd, mainvar, bhead, fd->id_tag_extra | ID_TAG_NEED_EXPAND | ID_TAG_INDIRECT, false, &id);
4109 BLI_assert(id != nullptr);
4110 id_sort_by_name(which_libbase(mainvar, GS(id->name)), id, static_cast<ID *>(id->prev));
4111 }
4112 else {
4113 /* Convert any previously read weak link to regular link
4114 * to signal that we want to read this data-block. */
4115 if (id->tag & ID_TAG_ID_LINK_PLACEHOLDER) {
4116 id->flag &= ~ID_FLAG_INDIRECT_WEAK_LINK;
4117 }
4118
4119 /* this is actually only needed on UI call? when ID was already read before,
4120 * and another append happens which invokes same ID...
4121 * in that case the lookup table needs this entry */
4122 oldnewmap_lib_insert(fd, bhead->old, id, bhead->code);
4123 /* commented because this can print way too much */
4124 // if (G.debug & G_DEBUG) printf("expand: already read %s\n", id->name);
4125 }
4126 }
4127}
4128
4130{
4131 /* Embedded IDs are not known by lib_link code, so they would be remapped to `nullptr`. But there
4132 * is no need to process them anyway, as they are already handled during the 'read_data' phase.
4133 */
4135 return IDWALK_RET_NOP;
4136 }
4137
4138 /* Explicitly requested to be ignored during readfile processing. Means the read_data code
4139 * already handled this pointer. Typically, the 'owner_id' pointer of an embedded ID. */
4140 if (cb_data->cb_flag & IDWALK_CB_READFILE_IGNORE) {
4141 return IDWALK_RET_NOP;
4142 }
4143
4144 /* Expand process can be re-entrant or have other complex interactions that will not work well
4145 * with loop-back pointers. Further more, processing such data should not be needed here anyway.
4146 */
4147 if (cb_data->cb_flag & (IDWALK_CB_LOOPBACK)) {
4148 return IDWALK_RET_NOP;
4149 }
4150
4151 BlendExpander *expander = static_cast<BlendExpander *>(cb_data->user_data);
4152 ID *id = *(cb_data->id_pointer);
4153
4154 expander->callback(expander->fd, expander->main, id);
4155
4156 return IDWALK_RET_NOP;
4157}
4158
4160{
4161 FileData *fd = static_cast<FileData *>(fdhandle);
4162 BlendExpander expander = {fd, mainvar, callback};
4163
4164 for (bool do_it = true; do_it;) {
4165 do_it = false;
4166 ID *id_iter;
4167
4168 FOREACH_MAIN_ID_BEGIN (mainvar, id_iter) {
4169 if ((id_iter->tag & ID_TAG_NEED_EXPAND) == 0) {
4170 continue;
4171 }
4172
4173 /* Original (current) ID pointer can be considered as valid, but _not_ its own pointers to
4174 * other IDs - the already loaded ones will be valid, but the yet-to-be-read ones will not.
4175 * Expanding should _not_ require processing of UI ID pointers.
4176 * Expanding should never modify ID pointers themselves.
4177 * Handling of DNA deprecated data should never be needed in undo case. */
4179 ((!fd || (fd->flags & FD_FLAGS_IS_MEMFILE)) ?
4180 0 :
4182 BKE_library_foreach_ID_link(nullptr, id_iter, expand_cb, &expander, flag);
4183
4184 do_it = true;
4185 id_iter->tag &= ~ID_TAG_NEED_EXPAND;
4186 }
4188 }
4189}
4190
4193/* -------------------------------------------------------------------- */
4197/* returns true if the item was found
4198 * but it may already have already been appended/linked */
4200 Main *mainl, FileData *fd, const short idcode, const char *name, const int flag)
4201{
4202 BHead *bhead = find_bhead_from_code_name(fd, idcode, name);
4203 ID *id;
4204
4205 const bool use_placeholders = (flag & BLO_LIBLINK_USE_PLACEHOLDERS) != 0;
4206 const bool force_indirect = (flag & BLO_LIBLINK_FORCE_INDIRECT) != 0;
4207
4209
4210 if (bhead && blo_bhead_is_id_valid_type(bhead)) {
4211 id = library_id_is_yet_read(fd, mainl, bhead);
4212 if (id == nullptr) {
4213 /* not read yet */
4214 const int tag = ((force_indirect ? ID_TAG_INDIRECT : ID_TAG_EXTERN) | fd->id_tag_extra);
4215 read_libblock(fd, mainl, bhead, tag | ID_TAG_NEED_EXPAND, false, &id);
4216
4217 if (id) {
4218 /* sort by name in list */
4219 ListBase *lb = which_libbase(mainl, idcode);
4220 id_sort_by_name(lb, id, nullptr);
4221 }
4222 }
4223 else {
4224 /* already linked */
4225 CLOG_WARN(&LOG, "Append: ID '%s' is already linked", id->name);
4226 oldnewmap_lib_insert(fd, bhead->old, id, bhead->code);
4227 if (!force_indirect && (id->tag & ID_TAG_INDIRECT)) {
4228 id->tag &= ~ID_TAG_INDIRECT;
4229 id->flag &= ~ID_FLAG_INDIRECT_WEAK_LINK;
4230 id->tag |= ID_TAG_EXTERN;
4231 }
4232 }
4233 }
4234 else if (use_placeholders) {
4235 /* XXX flag part is weak! */
4236 id = create_placeholder(
4237 mainl, idcode, name, force_indirect ? ID_TAG_INDIRECT : ID_TAG_EXTERN, false);
4238 }
4239 else {
4240 id = nullptr;
4241 }
4242
4243 /* NOTE: `id` may be `nullptr` even if a BHead was found, in case e.g. it is an invalid BHead. */
4244
4245 return id;
4246}
4247
4249 BlendHandle **bh,
4250 const short idcode,
4251 const char *name,
4253{
4254 FileData *fd = (FileData *)(*bh);
4255
4256 ID *ret_id = nullptr;
4257 if (!mainl->is_read_invalid) {
4258 ret_id = link_named_part(mainl, fd, idcode, name, params->flag);
4259 }
4260
4261 if (mainl->is_read_invalid) {
4262 return nullptr;
4263 }
4264 return ret_id;
4265}
4266
4267/* common routine to append/link something from a library */
4268
4270 FileData *fd,
4271 const char *filepath,
4272 const int id_tag_extra)
4273{
4274 Main *mainl;
4275
4276 /* Only allow specific tags to be set as extra,
4277 * otherwise this could conflict with library loading logic.
4278 * Other flags can be added here, as long as they are safe. */
4279 BLI_assert((id_tag_extra & ~ID_TAG_TEMP_MAIN) == 0);
4280
4281 fd->id_tag_extra = id_tag_extra;
4282
4283 fd->mainlist = static_cast<ListBase *>(MEM_callocN(sizeof(ListBase), "FileData.mainlist"));
4284
4285 /* make mains */
4286 blo_split_main(fd->mainlist, mainvar);
4287
4288 /* which one do we need? */
4289 mainl = blo_find_main(fd, filepath, BKE_main_blendfile_path(mainvar));
4290 if (mainl->curlib) {
4291 mainl->curlib->runtime.filedata = fd;
4292 }
4293
4294 /* needed for do_version */
4295 mainl->versionfile = short(fd->fileversion);
4296 read_file_version(fd, mainl);
4297#ifdef USE_GHASH_BHEAD
4299#endif
4300
4301 return mainl;
4302}
4303
4305 Main *bmain,
4306 const int flag,
4307 const int id_tag_extra)
4308{
4309 memset(params, 0, sizeof(*params));
4310 params->bmain = bmain;
4311 params->flag = flag;
4312 params->id_tag_extra = id_tag_extra;
4313}
4314
4316 Main *bmain,
4317 const int flag,
4318 const int id_tag_extra,
4319 /* Context arguments. */
4320 Scene *scene,
4321 ViewLayer *view_layer,
4322 const View3D *v3d)
4323{
4324 BLO_library_link_params_init(params, bmain, flag, id_tag_extra);
4325 if (scene != nullptr) {
4326 params->context.scene = scene;
4327 params->context.view_layer = view_layer;
4328 params->context.v3d = v3d;
4329 }
4330}
4331
4333 const char *filepath,
4335{
4336 FileData *fd = reinterpret_cast<FileData *>(*bh);
4337 return library_link_begin(params->bmain, fd, filepath, params->id_tag_extra);
4338}
4339
4340static void split_main_newid(Main *mainptr, Main *main_newid)
4341{
4342 /* We only copy the necessary subset of data in this temp main. */
4343 main_newid->versionfile = mainptr->versionfile;
4344 main_newid->subversionfile = mainptr->subversionfile;
4345 STRNCPY(main_newid->filepath, mainptr->filepath);
4346 main_newid->curlib = mainptr->curlib;
4347
4348 ListBase *lbarray[INDEX_ID_MAX];
4349 ListBase *lbarray_newid[INDEX_ID_MAX];
4350 int i = set_listbasepointers(mainptr, lbarray);
4351 set_listbasepointers(main_newid, lbarray_newid);
4352 while (i--) {
4353 BLI_listbase_clear(lbarray_newid[i]);
4354
4355 LISTBASE_FOREACH_MUTABLE (ID *, id, lbarray[i]) {
4356 if (id->tag & ID_TAG_NEW) {
4357 BLI_remlink(lbarray[i], id);
4358 BLI_addtail(lbarray_newid[i], id);
4359 }
4360 }
4361 }
4362}
4363
4364static void library_link_end(Main *mainl, FileData **fd, const int flag)
4365{
4366 Main *mainvar;
4367 Library *curlib;
4368
4369 if (mainl->id_map == nullptr) {
4370 mainl->id_map = BKE_main_idmap_create(mainl, false, nullptr, MAIN_IDMAP_TYPE_NAME);
4371 }
4372
4373 /* make main consistent */
4375
4376 /* Do this when expand found other libraries. */
4377 read_libraries(*fd, (*fd)->mainlist);
4378
4379 curlib = mainl->curlib;
4380
4381 /* make the lib path relative if required */
4382 if (flag & FILE_RELPATH) {
4383 /* use the full path, this could have been read by other library even */
4384 STRNCPY(curlib->filepath, curlib->runtime.filepath_abs);
4385
4386 /* uses current .blend file as reference */
4388 }
4389
4390 blo_join_main((*fd)->mainlist);
4391 mainvar = static_cast<Main *>((*fd)->mainlist->first);
4392 mainl = nullptr; /* blo_join_main free's mainl, can't use anymore */
4393
4394 if (mainvar->is_read_invalid) {
4395 return;
4396 }
4397
4398 lib_link_all(*fd, mainvar);
4399 after_liblink_merged_bmain_process(mainvar, (*fd)->reports);
4400
4401 /* Some versioning code does expect some proper userrefcounting, e.g. in conversion from
4402 * groups to collections... We could optimize out that first call when we are reading a
4403 * current version file, but again this is really not a bottle neck currently. So not worth
4404 * it. */
4405 BKE_main_id_refcount_recompute(mainvar, false);
4406
4407 /* FIXME: This is suspiciously early call compared to similar process in
4408 * #blo_read_file_internal, where it is called towards the very end, after all do_version,
4409 * liboverride updates etc. have been done. */
4410 /* FIXME: Probably also need to forbid layer collections updates until this call, as done in
4411 * #blo_read_file_internal? */
4413
4414 /* Yep, second splitting... but this is a very cheap operation, so no big deal. */
4415 blo_split_main((*fd)->mainlist, mainvar);
4416 Main *main_newid = BKE_main_new();
4417 for (mainvar = ((Main *)(*fd)->mainlist->first)->next; mainvar; mainvar = mainvar->next) {
4418 BLI_assert(mainvar->versionfile != 0);
4419 /* We need to split out IDs already existing,
4420 * or they will go again through do_versions - bad, very bad! */
4421 split_main_newid(mainvar, main_newid);
4422
4423 do_versions_after_linking((main_newid->curlib && main_newid->curlib->runtime.filedata) ?
4424 main_newid->curlib->runtime.filedata :
4425 *fd,
4426 main_newid);
4427
4428 add_main_to_main(mainvar, main_newid);
4429
4430 if (mainvar->is_read_invalid) {
4431 break;
4432 }
4433 }
4434
4435 blo_join_main((*fd)->mainlist);
4436 mainvar = static_cast<Main *>((*fd)->mainlist->first);
4437 MEM_freeN((*fd)->mainlist);
4438
4439 if (mainvar->is_read_invalid) {
4440 BKE_main_free(main_newid);
4441 return;
4442 }
4443
4444 /* This does not take into account old, deprecated data, so we also have to do it after
4445 * `do_versions_after_linking()`. */
4446 BKE_main_id_refcount_recompute(mainvar, false);
4447
4448 /* After all data has been read and versioned, uses ID_TAG_NEW. */
4450
4452
4453 /* Apply overrides of newly linked data if needed. Already existing IDs need to split out, to
4454 * avoid re-applying their own overrides. */
4455 BLI_assert(BKE_main_is_empty(main_newid));
4456 split_main_newid(mainvar, main_newid);
4457 BKE_lib_override_library_main_validate(main_newid, (*fd)->reports->reports);
4459 add_main_to_main(mainvar, main_newid);
4460 BKE_main_free(main_newid);
4461
4462 BKE_main_id_tag_all(mainvar, ID_TAG_NEW, false);
4463
4464 /* FIXME Temporary 'fix' to a problem in how temp ID are copied in
4465 * `BKE_lib_override_library_main_update`, see #103062.
4466 * Proper fix involves first addressing #90610. */
4468
4469 /* Make all relative paths, relative to the open blend file. */
4471
4472 /* patch to prevent switch_endian happens twice */
4473 /* FIXME This is extremely bad design, #library_link_end should probably _always_ free the file
4474 * data? */
4475 if ((*fd)->flags & FD_FLAGS_SWITCH_ENDIAN) {
4476 blo_filedata_free(*fd);
4477 *fd = nullptr;
4478 }
4479
4480 /* Sanity checks. */
4481 blo_read_file_checks(mainvar);
4482}
4483
4484void BLO_library_link_end(Main *mainl, BlendHandle **bh, const LibraryLink_Params *params)
4485{
4486 FileData *fd = reinterpret_cast<FileData *>(*bh);
4487
4488 if (!mainl->is_read_invalid) {
4489 library_link_end(mainl, &fd, params->flag);
4490 }
4491
4492 LISTBASE_FOREACH (Library *, lib, &params->bmain->libraries) {
4493 /* Now we can clear this runtime library filedata, it is not needed anymore. */
4494 if (lib->runtime.filedata == reinterpret_cast<FileData *>(*bh)) {
4495 /* The filedata is owned and managed by caller code, only clear matching library pointer. */
4496 lib->runtime.filedata = nullptr;
4497 }
4498 else if (lib->runtime.filedata) {
4499 /* In case other libraries had to be read as dependencies of the main linked one, they need
4500 * to be cleared here.
4501 *
4502 * TODO: In the future, could be worth keeping them in case data are linked from several
4503 * libraries at once? To avoid closing and re-opening the same file several times. Would need
4504 * a global cleanup callback then once all linking is done, though. */
4505 blo_filedata_free(lib->runtime.filedata);
4506 lib->runtime.filedata = nullptr;
4507 }
4508 }
4509
4510 *bh = reinterpret_cast<BlendHandle *>(fd);
4511}
4512
4513void *BLO_library_read_struct(FileData *fd, BHead *bh, const char *blockname)
4514{
4515 return read_struct(fd, bh, blockname, INDEX_ID_NULL);
4516}
4517
4520/* -------------------------------------------------------------------- */
4524static int has_linked_ids_to_read(Main *mainvar)
4525{
4526 ListBase *lbarray[INDEX_ID_MAX];
4527 int a = set_listbasepointers(mainvar, lbarray);
4528
4529 while (a--) {
4530 LISTBASE_FOREACH (ID *, id, lbarray[a]) {
4531 if ((id->tag & ID_TAG_ID_LINK_PLACEHOLDER) && !(id->flag & ID_FLAG_INDIRECT_WEAK_LINK)) {
4532 return true;
4533 }
4534 }
4535 }
4536
4537 return false;
4538}
4539
4541 FileData *basefd, FileData *fd, Main *mainvar, ID *id, ID **r_id)
4542{
4543 BHead *bhead = nullptr;
4544 const bool is_valid = BKE_idtype_idcode_is_linkable(GS(id->name)) ||
4545 ((id->tag & ID_TAG_EXTERN) == 0);
4546
4547 if (fd) {
4548 bhead = find_bhead_from_idname(fd, id->name);
4549 }
4550
4551 if (!is_valid) {
4552 BLO_reportf_wrap(basefd->reports,
4553 RPT_ERROR,
4554 RPT_("LIB: %s: '%s' is directly linked from '%s' (parent '%s'), but is a "
4555 "non-linkable data type"),
4556 BKE_idtype_idcode_to_name(GS(id->name)),
4557 id->name + 2,
4558 mainvar->curlib->runtime.filepath_abs,
4560 }
4561
4562 id->tag &= ~ID_TAG_ID_LINK_PLACEHOLDER;
4563 id->flag &= ~ID_FLAG_INDIRECT_WEAK_LINK;
4564
4565 if (bhead) {
4566 id->tag |= ID_TAG_NEED_EXPAND;
4567 // printf("read lib block %s\n", id->name);
4568 read_libblock(fd, mainvar, bhead, id->tag, false, r_id);
4569 }
4570 else {
4571 CLOG_INFO(&LOG,
4572 3,
4573 "LIB: %s: '%s' missing from '%s', parent '%s'",
4574 BKE_idtype_idcode_to_name(GS(id->name)),
4575 id->name + 2,
4576 mainvar->curlib->runtime.filepath_abs,
4578 basefd->reports->count.missing_linked_id++;
4579
4580 /* Generate a placeholder for this ID (simplified version of read_libblock actually...). */
4581 if (r_id) {
4582 *r_id = is_valid ? create_placeholder(mainvar,
4583 GS(id->name),
4584 id->name + 2,
4585 id->tag,
4586 id->override_library != nullptr) :
4587 nullptr;
4588 }
4589 }
4590}
4591
4593 FileData *fd,
4594 ListBase *mainlist,
4595 Main *mainvar)
4596{
4598
4599 ListBase *lbarray[INDEX_ID_MAX];
4600 int a = set_listbasepointers(mainvar, lbarray);
4601
4602 while (a--) {
4603 ID *id = static_cast<ID *>(lbarray[a]->first);
4604
4605 while (id) {
4606 ID *id_next = static_cast<ID *>(id->next);
4607 if ((id->tag & ID_TAG_ID_LINK_PLACEHOLDER) && !(id->flag & ID_FLAG_INDIRECT_WEAK_LINK)) {
4608 BLI_remlink(lbarray[a], id);
4609 if (mainvar->id_map != nullptr) {
4610 BKE_main_idmap_remove_id(mainvar->id_map, id);
4611 }
4612
4613 /* When playing with lib renaming and such, you may end with cases where
4614 * you have more than one linked ID of the same data-block from same
4615 * library. This is absolutely horrible, hence we use a ghash to ensure
4616 * we go back to a single linked data when loading the file. */
4617 ID *realid = loaded_ids.lookup_default(id->name, nullptr);
4618 if (!realid) {
4619 read_library_linked_id(basefd, fd, mainvar, id, &realid);
4620 loaded_ids.add_overwrite(id->name, realid);
4621 }
4622
4623 /* `realid` shall never be nullptr - unless some source file/lib is broken
4624 * (known case: some directly linked shape-key from a missing lib...). */
4625 // BLI_assert(*realid != nullptr);
4626
4627 /* Now that we have a real ID, replace all pointers to placeholders in
4628 * fd->libmap with pointers to the real data-blocks. We do this for all
4629 * libraries since multiple might be referencing this ID. */
4630 change_link_placeholder_to_real_ID_pointer(mainlist, basefd, id, realid);
4631
4632 MEM_freeN(id);
4633 }
4634 id = id_next;
4635 }
4636
4637 loaded_ids.clear();
4638 }
4639}
4640
4641static void read_library_clear_weak_links(FileData *basefd, ListBase *mainlist, Main *mainvar)
4642{
4643 /* Any remaining weak links at this point have been lost, silently drop
4644 * those by setting them to nullptr pointers. */
4645 ListBase *lbarray[INDEX_ID_MAX];
4646 int a = set_listbasepointers(mainvar, lbarray);
4647
4648 while (a--) {
4649 ID *id = static_cast<ID *>(lbarray[a]->first);
4650
4651 while (id) {
4652 ID *id_next = static_cast<ID *>(id->next);
4653 if ((id->tag & ID_TAG_ID_LINK_PLACEHOLDER) && (id->flag & ID_FLAG_INDIRECT_WEAK_LINK)) {
4654 CLOG_INFO(&LOG, 3, "Dropping weak link to '%s'", id->name);
4655 change_link_placeholder_to_real_ID_pointer(mainlist, basefd, id, nullptr);
4656 BLI_freelinkN(lbarray[a], id);
4657 }
4658 id = id_next;
4659 }
4660 }
4661}
4662
4664 ListBase *mainlist,
4665 Main *mainl,
4666 Main *mainptr)
4667{
4668 FileData *fd = mainptr->curlib->runtime.filedata;
4669
4670 if (fd != nullptr) {
4671 /* File already open. */
4672 return fd;
4673 }
4674
4675 if (mainptr->curlib->packedfile) {
4676 /* Read packed file. */
4677 const PackedFile *pf = mainptr->curlib->packedfile;
4678
4679 BLO_reportf_wrap(basefd->reports,
4680 RPT_INFO,
4681 RPT_("Read packed library: '%s', parent '%s'"),
4682 mainptr->curlib->filepath,
4684 fd = blo_filedata_from_memory(pf->data, pf->size, basefd->reports);
4685
4686 /* Needed for library_append and read_libraries. */
4687 STRNCPY(fd->relabase, mainptr->curlib->runtime.filepath_abs);
4688 }
4689 else {
4690 /* Read file on disk. */
4691 BLO_reportf_wrap(basefd->reports,
4692 RPT_INFO,
4693 RPT_("Read library: '%s', '%s', parent '%s'"),
4694 mainptr->curlib->runtime.filepath_abs,
4695 mainptr->curlib->filepath,
4697 fd = blo_filedata_from_file(mainptr->curlib->runtime.filepath_abs, basefd->reports);
4698 }
4699
4700 if (fd) {
4701 /* Share the mainlist, so all libraries are added immediately in a
4702 * single list. It used to be that all FileData's had their own list,
4703 * but with indirectly linking this meant we didn't catch duplicate
4704 * libraries properly. */
4705 fd->mainlist = mainlist;
4706
4707 fd->reports = basefd->reports;
4708
4709 if (fd->libmap) {
4711 }
4712
4713 fd->libmap = oldnewmap_new();
4714
4715 mainptr->curlib->runtime.filedata = fd;
4716 mainptr->versionfile = fd->fileversion;
4717
4718 /* subversion */
4719 read_file_version(fd, mainptr);
4720#ifdef USE_GHASH_BHEAD
4722#endif
4723 }
4724 else {
4725 mainptr->curlib->runtime.filedata = nullptr;
4726 mainptr->curlib->id.tag |= ID_TAG_MISSING;
4727 /* Set lib version to current main one... Makes assert later happy. */
4728 mainptr->versionfile = mainptr->curlib->runtime.versionfile = mainl->versionfile;
4729 mainptr->subversionfile = mainptr->curlib->runtime.subversionfile = mainl->subversionfile;
4730 }
4731
4732 if (fd == nullptr) {
4733 BLO_reportf_wrap(basefd->reports,
4734 RPT_INFO,
4735 RPT_("Cannot find lib '%s'"),
4736 mainptr->curlib->runtime.filepath_abs);
4737 basefd->reports->count.missing_libraries++;
4738 }
4739
4740 return fd;
4741}
4742
4743static void read_libraries(FileData *basefd, ListBase *mainlist)
4744{
4745 Main *mainl = static_cast<Main *>(mainlist->first);
4746 bool do_it = true;
4747
4748 /* At this point the base blend file has been read, and each library blend
4749 * encountered so far has a main with placeholders for linked data-blocks.
4750 *
4751 * Now we will read the library blend files and replace the placeholders
4752 * with actual data-blocks. We loop over library mains multiple times in
4753 * case a library needs to link additional data-blocks from another library
4754 * that had been read previously. */
4755 while (do_it) {
4756 do_it = false;
4757
4758 /* Loop over mains of all library blend files encountered so far. Note
4759 * this list gets longer as more indirectly library blends are found. */
4760 for (Main *mainptr = mainl->next; mainptr; mainptr = mainptr->next) {
4761 /* Does this library have any more linked data-blocks we need to read? */
4762 if (has_linked_ids_to_read(mainptr)) {
4763 CLOG_INFO(&LOG,
4764 3,
4765 "Reading linked data-blocks from %s (%s)",
4766 mainptr->curlib->id.name,
4767 mainptr->curlib->filepath);
4768
4769 /* Open file if it has not been done yet. */
4770 FileData *fd = read_library_file_data(basefd, mainlist, mainl, mainptr);
4771
4772 if (fd) {
4773 do_it = true;
4774
4775 if (mainptr->id_map == nullptr) {
4776 mainptr->id_map = BKE_main_idmap_create(mainptr, false, nullptr, MAIN_IDMAP_TYPE_NAME);
4777 }
4778 }
4779
4780 /* Read linked data-blocks for each link placeholder, and replace
4781 * the placeholder with the real data-block. */
4782 read_library_linked_ids(basefd, fd, mainlist, mainptr);
4783
4784 /* Test if linked data-blocks need to read further linked data-blocks
4785 * and create link placeholders for them. */
4787 }
4788 }
4789 }
4790
4791 for (Main *mainptr = mainl->next; mainptr; mainptr = mainptr->next) {
4792 /* Drop weak links for which no data-block was found.
4793 * Since this can remap pointers in `libmap` of all libraries, it needs to be performed in its
4794 * own loop, before any call to `lib_link_all` (and the freeing of the libraries' filedata). */
4795 read_library_clear_weak_links(basefd, mainlist, mainptr);
4796 }
4797
4798 Main *main_newid = BKE_main_new();
4799 for (Main *mainptr = mainl->next; mainptr; mainptr = mainptr->next) {
4800 /* Do versioning for newly added linked data-blocks. If no data-blocks
4801 * were read from a library versionfile will still be zero and we can
4802 * skip it. */
4803 if (mainptr->versionfile) {
4804 /* Split out already existing IDs to avoid them going through
4805 * do_versions multiple times, which would have bad consequences. */
4806 split_main_newid(mainptr, main_newid);
4807
4808 /* `filedata` can be NULL when loading linked data from nonexistent or invalid library
4809 * reference. Or during linking/appending, when processing data from a library not involved
4810 * in the current linking/appending operation.
4811 *
4812 * Skip versioning in these cases, since the only IDs here will be placeholders (missing
4813 * lib), or already existing IDs (linking/appending). */
4814 if (mainptr->curlib->runtime.filedata) {
4815 do_versions(mainptr->curlib->runtime.filedata, mainptr->curlib, main_newid);
4816 }
4817
4818 add_main_to_main(mainptr, main_newid);
4819 }
4820
4821 /* Lib linking. */
4822 if (mainptr->curlib->runtime.filedata) {
4823 lib_link_all(mainptr->curlib->runtime.filedata, mainptr);
4824 }
4825
4826 /* NOTE: No need to call #do_versions_after_linking() or #BKE_main_id_refcount_recompute()
4827 * here, as this function is only called for library 'subset' data handling, as part of
4828 * either full blend-file reading (#blo_read_file_internal()), or library-data linking
4829 * (#library_link_end()).
4830 *
4831 * For this to work reliably, `mainptr->curlib->runtime.filedata` also needs to be freed after
4832 * said versioning code has run. */
4833 }
4834 BKE_main_free(main_newid);
4835}
4836
4837static void *blo_verify_data_address(void *new_address,
4838 const void * /*old_address*/,
4839 const size_t expected_size)
4840{
4841 if (new_address != nullptr) {
4842 /* Not testing equality, since size might have been aligned up,
4843 * or might be passed the size of a base struct with inheritance. */
4844 BLI_assert_msg(MEM_allocN_len(new_address) >= expected_size,
4845 "Corrupt .blend file, unexpected data size.");
4846 UNUSED_VARS_NDEBUG(expected_size);
4847 }
4848
4849 return new_address;
4850}
4851
4852void *BLO_read_get_new_data_address(BlendDataReader *reader, const void *old_address)
4853{
4854 return newdataadr(reader->fd, old_address);
4855}
4856
4858 const void *old_address,
4859 const size_t expected_size)
4860{
4861 void *new_address = newdataadr_no_us(reader->fd, old_address);
4862 return blo_verify_data_address(new_address, old_address, expected_size);
4863}
4864
4866 const void *old_address,
4867 const size_t expected_size)
4868{
4869 void *new_address = newdataadr(reader->fd, old_address);
4870 return blo_verify_data_address(new_address, old_address, expected_size);
4871}
4872
4874 const char *struct_name,
4875 const uint32_t items_num,
4876 const void *old_address)
4877{
4878 const int struct_index = DNA_struct_find_with_alias(reader->fd->memsdna, struct_name);
4879 BLI_assert(STREQ(DNA_struct_identifier(const_cast<SDNA *>(reader->fd->memsdna), struct_index),
4880 struct_name));
4881 const size_t struct_size = size_t(DNA_struct_size(reader->fd->memsdna, struct_index));
4882 return BLO_read_struct_array_with_size(reader, old_address, struct_size * items_num);
4883}
4884
4886 ID *self_id,
4887 const bool is_linked_only,
4888 ID *id)
4889{
4890 return static_cast<ID *>(newlibadr(reader->fd, self_id, is_linked_only, id));
4891}
4892
4894{
4895 return BKE_main_idmap_lookup_uid(reader->fd->new_idmap_uid, session_uid);
4896}
4897
4899{
4900 return reader->fd->fileversion;
4901}
4902
4904{
4905 return (reader->fd->flags & FD_FLAGS_SWITCH_ENDIAN) != 0;
4906}
4907
4909 const size_t expected_elem_size,
4910 ListBase *list)
4911{
4912 if (BLI_listbase_is_empty(list)) {
4913 return;
4914 }
4915
4916 list->first = BLO_read_struct_array_with_size(reader, list->first, expected_elem_size);
4917 Link *ln = static_cast<Link *>(list->first);
4918 Link *prev = nullptr;
4919 while (ln) {
4920 ln->next = static_cast<Link *>(
4921 BLO_read_struct_array_with_size(reader, ln->next, expected_elem_size));
4922 ln->prev = prev;
4923 prev = ln;
4924 ln = ln->next;
4925 }
4926 list->last = prev;
4927}
4928
4929void BLO_read_char_array(BlendDataReader *reader, int array_size, char **ptr_p)
4930{
4931 *ptr_p = reinterpret_cast<char *>(
4932 BLO_read_struct_array_with_size(reader, *((void **)ptr_p), sizeof(char) * array_size));
4933}
4934
4935void BLO_read_uint8_array(BlendDataReader *reader, int array_size, uint8_t **ptr_p)
4936{
4937 *ptr_p = reinterpret_cast<uint8_t *>(
4938 BLO_read_struct_array_with_size(reader, *((void **)ptr_p), sizeof(uint8_t) * array_size));
4939}
4940
4941void BLO_read_int8_array(BlendDataReader *reader, int array_size, int8_t **ptr_p)
4942{
4943 *ptr_p = reinterpret_cast<int8_t *>(
4944 BLO_read_struct_array_with_size(reader, *((void **)ptr_p), sizeof(int8_t) * array_size));
4945}
4946
4947void BLO_read_int32_array(BlendDataReader *reader, int array_size, int32_t **ptr_p)
4948{
4949 *ptr_p = reinterpret_cast<int32_t *>(
4950 BLO_read_struct_array_with_size(reader, *((void **)ptr_p), sizeof(int32_t) * array_size));
4951
4952 if (*ptr_p && BLO_read_requires_endian_switch(reader)) {
4953 BLI_endian_switch_int32_array(*ptr_p, array_size);
4954 }
4955}
4956
4957void BLO_read_uint32_array(BlendDataReader *reader, int array_size, uint32_t **ptr_p)
4958{
4959 *ptr_p = reinterpret_cast<uint32_t *>(
4960 BLO_read_struct_array_with_size(reader, *((void **)ptr_p), sizeof(uint32_t) * array_size));
4961
4962 if (*ptr_p && BLO_read_requires_endian_switch(reader)) {
4963 BLI_endian_switch_uint32_array(*ptr_p, array_size);
4964 }
4965}
4966
4967void BLO_read_float_array(BlendDataReader *reader, int array_size, float **ptr_p)
4968{
4969 *ptr_p = reinterpret_cast<float *>(
4970 BLO_read_struct_array_with_size(reader, *((void **)ptr_p), sizeof(float) * array_size));
4971
4972 if (*ptr_p && BLO_read_requires_endian_switch(reader)) {
4973 BLI_endian_switch_float_array(*ptr_p, array_size);
4974 }
4975}
4976
4977void BLO_read_float3_array(BlendDataReader *reader, int array_size, float **ptr_p)
4978{
4979 BLO_read_float_array(reader, array_size * 3, ptr_p);
4980}
4981
4982void BLO_read_double_array(BlendDataReader *reader, int array_size, double **ptr_p)
4983{
4984 *ptr_p = reinterpret_cast<double *>(
4985 BLO_read_struct_array_with_size(reader, *((void **)ptr_p), sizeof(double) * array_size));
4986
4987 if (*ptr_p && BLO_read_requires_endian_switch(reader)) {
4988 BLI_endian_switch_double_array(*ptr_p, array_size);
4989 }
4990}
4991
4992void BLO_read_string(BlendDataReader *reader, char **ptr_p)
4993{
4994 BLO_read_data_address(reader, ptr_p);
4995
4996#ifndef NDEBUG
4997 const char *str = *ptr_p;
4998 if (str) {
4999 /* Verify that we have a null terminator. */
5000 for (size_t len = MEM_allocN_len(str); len > 0; len--) {
5001 if (str[len - 1] == '\0') {
5002 return;
5003 }
5004 }
5005
5006 BLI_assert_msg(0, "Corrupt .blend file, expected string to be null terminated.");
5007 }
5008#endif
5009}
5010
5011void BLO_read_string(BlendDataReader *reader, char *const *ptr_p)
5012{
5013 BLO_read_string(reader, const_cast<char **>(ptr_p));
5014}
5015
5016void BLO_read_string(BlendDataReader *reader, const char **ptr_p)
5017{
5018 BLO_read_string(reader, const_cast<char **>(ptr_p));
5019}
5020
5022 uint array_size,
5023 const uint64_t *src,
5024 uint32_t *dst)
5025{
5026 /* Match pointer conversion rules from bh4_from_bh8 and cast_pointer. */
5027 if (BLO_read_requires_endian_switch(reader)) {
5028 for (int i = 0; i < array_size; i++) {
5029 uint64_t ptr = src[i];
5031 dst[i] = uint32_t(ptr >> 3);
5032 }
5033 }
5034 else {
5035 for (int i = 0; i < array_size; i++) {
5036 dst[i] = uint32_t(src[i] >> 3);
5037 }
5038 }
5039}
5040
5042 uint array_size,
5043 const uint32_t *src,
5044 uint64_t *dst)
5045{
5046 /* Match pointer conversion rules from bh8_from_bh4 and cast_pointer_32_to_64. */
5047 for (int i = 0; i < array_size; i++) {
5048 dst[i] = src[i];
5049 }
5050}
5051
5052void BLO_read_pointer_array(BlendDataReader *reader, const int array_size, void **ptr_p)
5053{
5054 FileData *fd = reader->fd;
5055
5056 void *orig_array = newdataadr(fd, *ptr_p);
5057 if (orig_array == nullptr) {
5058 *ptr_p = nullptr;
5059 return;
5060 }
5061
5062 int file_pointer_size = fd->filesdna->pointer_size;
5063 int current_pointer_size = fd->memsdna->pointer_size;
5064
5065 void *final_array = nullptr;
5066
5067 if (file_pointer_size == current_pointer_size) {
5068 /* No pointer conversion necessary. */
5069 final_array = orig_array;
5070 }
5071 else if (file_pointer_size == 8 && current_pointer_size == 4) {
5072 /* Convert pointers from 64 to 32 bit. */
5073 final_array = MEM_malloc_arrayN(array_size, 4, "new pointer array");
5075 reader, array_size, (uint64_t *)orig_array, (uint32_t *)final_array);
5076 MEM_freeN(orig_array);
5077 }
5078 else if (file_pointer_size == 4 && current_pointer_size == 8) {
5079 /* Convert pointers from 32 to 64 bit. */
5080 final_array = MEM_malloc_arrayN(array_size, 8, "new pointer array");
5082 reader, array_size, (uint32_t *)orig_array, (uint64_t *)final_array);
5083 MEM_freeN(orig_array);
5084 }
5085 else {
5087 }
5088
5089 *ptr_p = final_array;
5090}
5091
5093 BlendDataReader *reader,
5094 const void **ptr_p,
5095 const blender::FunctionRef<const blender::ImplicitSharingInfo *()> read_fn)
5096{
5097 const void *old_address = *ptr_p;
5098 if (BLO_read_data_is_undo(reader)) {
5099 if (reader->fd->flags & FD_FLAGS_IS_MEMFILE) {
5100 UndoReader *undo_reader = reinterpret_cast<UndoReader *>(reader->fd->file);
5101 const MemFile &memfile = *undo_reader->memfile;
5102 if (memfile.shared_storage) {
5103 /* Check if the data was saved with sharing-info. */
5104 if (const blender::ImplicitSharingInfo *sharing_info =
5105 memfile.shared_storage->map.lookup_default(old_address, nullptr))
5106 {
5107 /* Add a new owner of the data that is passed to the caller. */
5108 sharing_info->add_user();
5109 return {sharing_info, old_address};
5110 }
5111 }
5112 }
5113 }
5114
5115 if (const blender::ImplicitSharingInfoAndData *shared_data =
5116 reader->shared_data_by_stored_address.lookup_ptr(old_address))
5117 {
5118 /* The data was loaded before. No need to load it again. Just increase the user count to
5119 * indicate that it is shared. */
5120 if (shared_data->sharing_info) {
5121 shared_data->sharing_info->add_user();
5122 }
5123 return *shared_data;
5124 }
5125
5126 /* This is the first time this data is loaded. The callback also creates the corresponding
5127 * sharing info which may be reused later. */
5128 const blender::ImplicitSharingInfo *sharing_info = read_fn();
5129 const void *new_address = *ptr_p;
5130 const blender::ImplicitSharingInfoAndData shared_data{sharing_info, new_address};
5131 reader->shared_data_by_stored_address.add(old_address, shared_data);
5132 return shared_data;
5133}
5134
5136{
5137 return (reader->fd->flags & FD_FLAGS_IS_MEMFILE);
5138}
5139
5140void BLO_read_data_globmap_add(BlendDataReader *reader, void *oldaddr, void *newaddr)
5141{
5142 oldnewmap_insert(reader->fd->globmap, oldaddr, newaddr, 0);
5143}
5144
5146{
5147 link_glob_list(reader->fd, list);
5148}
5149
5151{
5152 return reader->fd->reports;
5153}
5154
5156{
5157 return (reader->fd->flags & FD_FLAGS_IS_MEMFILE);
5158}
5159
5161{
5162 return reader->main;
5163}
5164
5166{
5167 return reader->fd->reports;
5168}
5169
void BKE_animdata_blend_read_data(BlendDataReader *reader, ID *id)
void BKE_asset_metadata_read(BlendDataReader *reader, AssetMetaData *asset_data)
Definition asset.cc:222
void BKE_asset_catalog_path_list_blend_read_data(BlendDataReader *reader, ListBase &catalog_path_list)
#define BLENDER_FILE_SUBVERSION
void BKE_blender_version_blendfile_string_from_values(char *str_buff, const size_t str_buff_maxncpy, const short file_version, const short file_subversion)
Definition blender.cc:149
#define BLENDER_FILE_VERSION
void BKE_collections_after_lib_link(Main *bmain)
void BKE_collection_blend_read_data(BlendDataReader *reader, Collection *collection, ID *owner_id)
void BKE_main_collections_parent_relations_rebuild(Main *bmain)
@ G_FILE_ASSET_EDIT_FILE
@ G_FILE_RECOVER_READ
@ G_DEBUG
#define IDP_BlendDataRead(reader, prop)
@ IDTYPE_FLAGS_NO_MEMFILE_UNDO
Definition BKE_idtype.hh:50
const IDTypeInfo * BKE_idtype_get_info_from_idtype_index(const int idtype_index)
Definition idtype.cc:133
const IDTypeInfo * BKE_idtype_get_info_from_id(const ID *id)
Definition idtype.cc:150
bool BKE_idtype_cache_key_cmp(const void *key_a_v, const void *key_b_v)
Definition idtype.cc:41
const char * BKE_idtype_idcode_to_name(short idcode)
Definition idtype.cc:168
bool BKE_idtype_idcode_is_linkable(short idcode)
Definition idtype.cc:201
void BKE_idtype_id_foreach_cache(ID *id, IDTypeForeachCacheFunctionCallback function_callback, void *user_data)
Definition idtype.cc:385
int BKE_idtype_idcode_to_index(short idcode)
Definition idtype.cc:232
uint BKE_idtype_cache_key_hash(const void *key_v)
Definition idtype.cc:33
bool BKE_idtype_idcode_is_valid(short idcode)
Definition idtype.cc:196
@ IDTYPE_CACHE_CB_FLAGS_PERSISTENT
Definition BKE_idtype.hh:96
void BKE_layer_collection_resync_forbid()
void BKE_layer_collection_resync_allow()
ViewLayer * BKE_view_layer_find(const Scene *scene, const char *layer_name)
void BKE_id_delete(Main *bmain, void *idv) ATTR_NONNULL()
void * BKE_libblock_alloc(Main *bmain, short type, const char *name, int flag) ATTR_WARN_UNUSED_RESULT
Definition lib_id.cc:1415
void BKE_id_free(Main *bmain, void *idv)
void id_sort_by_name(ListBase *lb, ID *id, ID *id_sorting_hint)
Definition lib_id.cc:1737
#define MAIN_ID_SESSION_UID_UNSET
void BKE_libblock_init_empty(ID *id) ATTR_NONNULL(1)
Definition lib_id.cc:1420
void BKE_lib_libblock_session_uid_ensure(ID *id)
Definition lib_id.cc:1445
void id_us_ensure_real(ID *id)
Definition lib_id.cc:306
void BKE_lib_id_swap_full(Main *bmain, ID *id_a, ID *id_b, const bool do_self_remap, const int self_remap_flags)
Definition lib_id.cc:1028
void * BKE_libblock_alloc_notest(short type) ATTR_WARN_UNUSED_RESULT
Definition lib_id.cc:1310
void BKE_main_id_refcount_recompute(Main *bmain, bool do_linked_only)
Definition lib_id.cc:1981
void BKE_main_id_tag_all(Main *mainvar, int tag, bool value)
Definition lib_id.cc:1198
void BKE_lib_override_library_main_validate(Main *bmain, ReportList *reports)
void BKE_lib_override_library_main_update(Main *bmain)
@ IDWALK_RET_NOP
@ IDWALK_CB_LOOPBACK
@ IDWALK_CB_EMBEDDED_NOT_OWNING
@ IDWALK_CB_EMBEDDED
@ IDWALK_CB_READFILE_IGNORE
void BKE_library_foreach_ID_link(Main *bmain, ID *id, blender::FunctionRef< LibraryIDLinkCallback > callback, void *user_data, int flag)
Definition lib_query.cc:416
@ IDWALK_DO_DEPRECATED_POINTERS
@ IDWALK_INCLUDE_UI
@ IDWALK_READONLY
@ IDWALK_NO_ORIG_POINTERS_ACCESS
@ ID_REMAP_SKIP_USER_CLEAR
@ ID_REMAP_SKIP_USER_REFCOUNT
@ ID_REMAP_SKIP_NEVER_NULL_USAGE
@ ID_REMAP_SKIP_UPDATE_TAGGING
@ ID_REMAP_NO_ORIG_POINTERS_ACCESS
#define FOREACH_MAIN_ID_END
Definition BKE_main.hh:500
ListBase * which_libbase(Main *bmain, short type)
Definition main.cc:842
#define FOREACH_MAIN_LISTBASE_ID_END
Definition BKE_main.hh:469
#define FOREACH_MAIN_LISTBASE_ID_BEGIN(_lb, _id)
Definition BKE_main.hh:463
#define FOREACH_MAIN_LISTBASE_END
Definition BKE_main.hh:481
int set_listbasepointers(Main *bmain, ListBase *lb[])
Definition main.cc:929
Main * BKE_main_new(void)
Definition main.cc:45
#define FOREACH_MAIN_LISTBASE_BEGIN(_bmain, _lb)
Definition BKE_main.hh:474
void BKE_main_free(Main *bmain)
Definition main.cc:175
#define FOREACH_MAIN_ID_BEGIN(_bmain, _id)
Definition BKE_main.hh:494
#define MAIN_VERSION_FILE_OLDER_OR_EQUAL(main, ver, subver)
Definition BKE_main.hh:580
#define BLEN_THUMB_MEMSIZE(_x, _y)
Definition BKE_main.hh:597
const char * BKE_main_blendfile_path(const Main *bmain) ATTR_NONNULL()
Definition main.cc:832
#define BLEN_THUMB_MEMSIZE_IS_VALID(_x, _y)
Definition BKE_main.hh:600
bool BKE_main_is_empty(Main *bmain)
Definition main.cc:457
const char * BKE_main_blendfile_path_from_global()
Definition main.cc:837
ID ID ID * BKE_main_idmap_lookup_uid(IDNameLib_Map *id_map, uint session_uid) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Main * BKE_main_idmap_main_get(IDNameLib_Map *id_map) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
IDNameLib_Map * BKE_main_idmap_create(Main *bmain, bool create_valid_ids_set, Main *old_bmain, int idmap_types) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition main_idmap.cc:77
@ MAIN_IDMAP_TYPE_UID
@ MAIN_IDMAP_TYPE_NAME
void BKE_main_idmap_remove_id(IDNameLib_Map *id_map, const ID *id) ATTR_NONNULL()
void BKE_main_idmap_destroy(IDNameLib_Map *id_map) ATTR_NONNULL()
void BKE_main_idmap_insert_id(IDNameLib_Map *id_map, ID *id) ATTR_NONNULL()
ID * BKE_main_idmap_lookup_name(IDNameLib_Map *id_map, short id_type, const char *name, const Library *lib) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1
bool BKE_main_namemap_validate_and_fix(Main *bmain) ATTR_NONNULL()
void BKE_main_namemap_clear(Main *bmain) ATTR_NONNULL()
General operations, lookup, etc. for materials.
void BKE_object_materials_test(struct Main *bmain, struct Object *ob, struct ID *id)
General operations, lookup, etc. for blender objects.
void BKE_packedfile_blend_read(BlendDataReader *reader, PackedFile **pf_p, blender::StringRefNull filepath)
void BKE_preferences_extension_repo_read_data(struct BlendDataReader *reader, bUserExtensionRepo *repo)
void BKE_reportf(ReportList *reports, eReportType type, const char *format,...) ATTR_PRINTF_FORMAT(3
const char * BKE_report_type_str(eReportType type)
Definition report.cc:28
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition report.cc:125
bool BKE_screen_blend_read_data(BlendDataReader *reader, bScreen *screen)
Definition screen.cc:128
@ STEP_UNDO
@ STEP_REDO
#define BLI_assert_unreachable()
Definition BLI_assert.h:97
#define BLI_STATIC_ASSERT(a, msg)
Definition BLI_assert.h:87
#define BLI_assert(a)
Definition BLI_assert.h:50
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:57
#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)
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)
void BLI_endian_switch_uint32_array(unsigned int *val, int size) ATTR_NONNULL(1)
void BLI_endian_switch_double_array(double *val, int size) ATTR_NONNULL(1)
#define O_BINARY
bool BLI_file_magic_is_gzip(const char header[4])
Definition fileops_c.cc:257
bool BLI_file_magic_is_zstd(const char header[4])
Definition fileops_c.cc:264
int BLI_open(const char *filepath, int oflag, int pmode) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
FileReader * BLI_filereader_new_mmap(int filedes) ATTR_WARN_UNUSED_RESULT
FileReader * BLI_filereader_new_zstd(FileReader *base) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
FileReader * BLI_filereader_new_file(int filedes) ATTR_WARN_UNUSED_RESULT
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()
bool BLI_ghash_haskey(const GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.c:819
GHash * BLI_ghash_new(GHashHashFP hashfp, GHashCmpFP cmpfp, const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.c:686
GHash * BLI_ghash_str_new_ex(const char *info, unsigned int nentries_reserve) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
void * BLI_ghash_lookup(const GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.c:731
void BLI_ghash_insert(GHash *gh, void *key, void *val)
Definition BLI_ghash.c:707
void BLI_ghash_free(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
Definition BLI_ghash.c:860
BLI_INLINE bool BLI_listbase_is_empty(const struct ListBase *lb)
void * BLI_findstring(const struct ListBase *listbase, const char *id, int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
#define LISTBASE_FOREACH(type, var, list)
void BLI_freelinkN(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:269
#define LISTBASE_FOREACH_MUTABLE(type, var, list)
BLI_INLINE void BLI_listbase_clear(struct ListBase *lb)
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.cc:153
void void BLI_freelistN(struct ListBase *listbase) ATTR_NONNULL(1)
Definition listbase.cc:496
void void BLI_INLINE bool BLI_listbase_is_single(const struct ListBase *lb)
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:110
void BLI_remlink(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:130
int BLI_listbase_count(const struct ListBase *listbase) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
void * BLI_memarena_alloc(struct MemArena *ma, size_t size) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1) ATTR_MALLOC ATTR_ALLOC_SIZE(2)
void BLI_memarena_free(struct MemArena *ma) ATTR_NONNULL(1)
struct MemArena * BLI_memarena_new(size_t bufsize, const char *name) ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL ATTR_NONNULL(2) ATTR_MALLOC
#define BLI_MEMARENA_STD_BUFSIZE
bool BLI_path_abs(char path[FILE_MAX], const char *basepath) ATTR_NONNULL(1
void void void const char * BLI_path_basename(const char *path) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT
#define FILE_MAX
int BLI_path_normalize(char *path) ATTR_NONNULL(1)
bool BLI_path_is_rel(const char *path) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT
bool void BLI_path_rel(char path[FILE_MAX], const char *basepath) ATTR_NONNULL(1)
#define BLI_path_cmp
#define STRNCPY(dst, src)
Definition BLI_string.h:593
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, size_t dst_maxncpy) ATTR_NONNULL(1
unsigned int uint
Platform independent time functions.
double BLI_time_now_seconds(void)
Definition time.c:65
#define UNUSED_VARS(...)
#define STREQLEN(a, b, n)
#define UNUSED_VARS_NDEBUG(...)
#define SET_FLAG_FROM_TEST(value, test, flag)
#define UNLIKELY(x)
#define ELEM(...)
#define POINTER_OFFSET(v, ofs)
#define STREQ(a, b)
#define LIKELY(x)
Compatibility-like things for windows.
defines for blend-file codes.
#define BLEN_THUMB_MEMSIZE_FILE(_x, _y)
@ BLO_CODE_ENDB
@ BLO_CODE_REND
@ BLO_CODE_TEST
@ BLO_CODE_GLOB
@ BLO_CODE_DATA
@ BLO_CODE_DNA1
@ BLO_CODE_USER
Utilities ensuring .blend file (i.e. Main) is in valid state during write and/or read process.
void BLO_main_validate_embedded_flag(Main *bmain, ReportList *reports)
bool BLO_main_validate_shapekeys(Main *bmain, ReportList *reports)
void BLO_main_validate_embedded_liboverrides(Main *bmain, ReportList *reports)
#define BLO_read_data_address(reader, ptr_p)
#define BLO_read_struct_list(reader, struct_name, list)
#define BLO_read_struct(reader, struct_name, ptr_p)
external readfile function prototypes.
void(*)(void *fdhandle, Main *mainvar, void *idv) BLOExpandDoitCallback
@ BLO_LIBLINK_USE_PLACEHOLDERS
@ BLO_LIBLINK_FORCE_INDIRECT
@ BLO_READ_SKIP_DATA
@ BLO_READ_SKIP_USERDEF
@ BLO_READ_SKIP_UNDO_OLD_MAIN
@ BLENFILETYPE_BLEND
FileReader * BLO_memfile_new_filereader(MemFile *memfile, int undo_direction)
Definition undofile.cc:269
#define RPT_(msgid)
#define CLOG_ERROR(clg_ref,...)
Definition CLG_log.h:182
#define CLOG_WARN(clg_ref,...)
Definition CLG_log.h:181
#define CLOG_INFO(clg_ref, level,...)
Definition CLG_log.h:179
#define ID_FAKE_USERS(id)
Definition DNA_ID.h:616
@ ID_RECALC_SOURCE
Definition DNA_ID.h:1110
@ ID_RECALC_SYNC_TO_EVAL
Definition DNA_ID.h:1085
@ ID_RECALC_GEOMETRY
Definition DNA_ID.h:1041
@ ID_RECALC_ALL
Definition DNA_ID.h:1155
#define ID_IS_LINKED(_id)
Definition DNA_ID.h:654
#define MAX_ID_NAME
Definition DNA_ID.h:377
@ ID_FLAG_INDIRECT_WEAK_LINK
Definition DNA_ID.h:731
@ ID_TAG_UNDO_OLD_ID_REUSED_UNCHANGED
Definition DNA_ID.h:903
@ ID_TAG_NEW
Definition DNA_ID.h:865
@ ID_TAG_UNDO_OLD_ID_REUSED_NOUNDO
Definition DNA_ID.h:914
@ ID_TAG_NEED_EXPAND
Definition DNA_ID.h:879
@ ID_TAG_TEMP_MAIN
Definition DNA_ID.h:938
@ ID_TAG_INDIRECT
Definition DNA_ID.h:794
@ ID_TAG_EXTERN
Definition DNA_ID.h:788
@ ID_TAG_MISSING
Definition DNA_ID.h:813
@ ID_TAG_LOCAL
Definition DNA_ID.h:782
@ ID_TAG_UNDO_OLD_ID_REREAD_IN_PLACE
Definition DNA_ID.h:921
@ ID_TAG_NEED_LINK
Definition DNA_ID.h:894
@ ID_TAG_LIBOVERRIDE_NEED_RESYNC
Definition DNA_ID.h:852
@ ID_TAG_ID_LINK_PLACEHOLDER
Definition DNA_ID.h:886
#define INDEX_ID_MAX
Definition DNA_ID.h:1328
@ INDEX_ID_NULL
Definition DNA_ID.h:1325
@ LIBRARY_IS_ASSET_EDIT_FILE
Definition DNA_ID.h:556
#define ID_TAG_KEEP_ON_UNDO
Definition DNA_ID.h:1013
@ ID_WM
@ ID_LI
@ ID_SCE
@ ID_SCR
@ ID_OB
#define ID_SCRN
#define ID_LINK_PLACEHOLDER
Object groups, one object can be in many groups at once.
blenloader genfile private function prototypes
const char * DNA_struct_get_compareflags(const struct SDNA *oldsdna, const struct SDNA *newsdna)
void DNA_sdna_free(struct SDNA *sdna)
const struct SDNA * DNA_sdna_current_get(void)
int DNA_struct_find_with_alias(const struct SDNA *sdna, const char *str)
int DNA_struct_member_offset_by_name_with_alias(const struct SDNA *sdna, const char *stype, const char *vartype, const char *name)
int DNA_struct_size(const struct SDNA *sdna, int struct_index)
const char * DNA_struct_identifier(struct SDNA *sdna, int struct_index)
void * DNA_struct_reconstruct(const struct DNA_ReconstructInfo *reconstruct_info, int old_struct_index, int blocks, const void *old_blocks, const char *alloc_name)
struct DNA_ReconstructInfo * DNA_reconstruct_info_create(const struct SDNA *oldsdna, const struct SDNA *newsdna, const char *compare_flags)
struct SDNA * DNA_sdna_from_data(const void *data, int data_len, bool do_endian_swap, bool data_alloc, bool do_alias, const char **r_error_message)
void DNA_struct_switch_endian(const struct SDNA *sdna, int struct_index, char *data)
void DNA_reconstruct_info_free(struct DNA_ReconstructInfo *reconstruct_info)
int DNA_struct_alignment(const struct SDNA *sdna, int struct_index)
@ SDNA_CMP_REMOVED
Definition DNA_genfile.h:67
@ SDNA_CMP_NOT_EQUAL
Definition DNA_genfile.h:73
void DNA_sdna_alias_data_ensure_structs_map(struct SDNA *sdna)
@ SCE_READFILE_LIBLINK_NEED_SETSCENE_CHECK
#define SDNA_RAW_DATA_STRUCT_INDEX
@ FILE_RELPATH
@ USER_MENU_TYPE_OPERATOR
DrawDataList * DRW_drawdatalist_from_id(ID *id)
Read Guarded memory(de)allocation.
ATTR_WARN_UNUSED_RESULT const BMVert * v2
void clear()
Definition BLI_map.hh:989
const Value * lookup_ptr(const Key &key) const
Definition BLI_map.hh:484
bool add_overwrite(const Key &key, const Value &value)
Definition BLI_map.hh:301
bool add(const Key &key, const Value &value)
Definition BLI_map.hh:271
Value lookup_default(const Key &key, const Value &default_value) const
Definition BLI_map.hh:531
ValueIterator values() const
Definition BLI_map.hh:846
void clear_and_shrink()
Definition BLI_map.hh:1003
const char * insert(const keyT &key, std::string alloc_string)
#define printf
FILE * file
DEGForeachIDComponentCallback callback
#define offsetof(t, d)
int len
draw_view push_constant(Type::INT, "radiance_src") .push_constant(Type capture_info_buf storage_buf(1, Qualifier::READ, "ObjectBounds", "bounds_buf[]") .push_constant(Type draw_view int
#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.cc:202
format
void * MEM_mallocN_aligned(size_t len, size_t alignment, const char *str)
Definition mallocn.cc:110
void *(* MEM_mallocN)(size_t len, const char *str)
Definition mallocn.cc:44
void *(* MEM_malloc_arrayN)(size_t len, size_t size, const char *str)
Definition mallocn.cc:45
size_t(* MEM_allocN_len)(const void *vmemh)
Definition mallocn.cc:36
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
void *(* MEM_callocN)(size_t len, const char *str)
Definition mallocn.cc:42
#define G(x, y, z)
int main()
void node_tree_blend_read_data(BlendDataReader *reader, ID *owner_id, bNodeTree *ntree)
Definition node.cc:1042
void node_tree_update_all_new(Main *main)
Definition node.cc:4215
bNodeTree ** node_tree_ptr_from_id(ID *id)
Definition node.cc:3712
bNodeTree * node_tree_from_id(ID *id)
Definition node.cc:3732
AllocStringStorage< keyT, hashT > & alloc_string_storage_get(const std::string &storage_identifier)
void blo_do_versions_oldnewmap_insert(OldNewMap *onm, const void *oldaddr, void *newaddr, int nr)
Definition readfile.cc:278
static int lib_link_cb(LibraryIDLinkCallbackData *cb_data)
Definition readfile.cc:3226
void BLO_read_float3_array(BlendDataReader *reader, int array_size, float **ptr_p)
Definition readfile.cc:4977
static BHead * find_bhead(FileData *fd, void *old)
Definition readfile.cc:3917
static void * newdataadr_no_us(FileData *fd, const void *adr)
Definition readfile.cc:1473
static void read_libraries(FileData *basefd, ListBase *mainlist)
Definition readfile.cc:4743
void * blo_do_versions_newlibadr(FileData *fd, ID *self_id, const bool is_linked_only, const void *adr)
Definition readfile.cc:1489
static void lib_link_scenes_check_set(Main *bmain)
Definition readfile.cc:2261
void BLO_read_struct_list_with_size(BlendDataReader *reader, const size_t expected_elem_size, ListBase *list)
Definition readfile.cc:4908
static bool read_libblock_undo_restore_library(FileData *fd, Main *new_main, const ID *id, ID *id_old, BHead *bhead)
Definition readfile.cc:2591
FileData * blo_filedata_from_memory(const void *mem, int memsize, BlendFileReadReport *reports)
Definition readfile.cc:1312
static void link_glob_list(FileData *fd, ListBase *lb)
Definition readfile.cc:1892
static void bh8_from_bh4(BHead *bhead, BHead4 *bhead4)
Definition readfile.cc:681
static ID * create_placeholder(Main *mainvar, const short idcode, const char *idname, const int tag, const bool was_liboverride)
Definition readfile.cc:2381
static FileData * blo_filedata_from_file_descriptor(const char *filepath, BlendFileReadReport *reports, int filedes)
Definition readfile.cc:1201
static void lib_link_all(FileData *fd, Main *bmain)
Definition readfile.cc:3254
void blo_cache_storage_end(FileData *fd)
Definition readfile.cc:1692
static FileData * filedata_new(BlendFileReadReport *reports)
Definition readfile.cc:1098
BlendThumbnail * BLO_thumbnail_from_file(const char *filepath)
Definition readfile.cc:1422
static void direct_link_library(FileData *fd, Library *lib, Main *main)
Definition readfile.cc:2287
static void convert_pointer_array_64_to_32(BlendDataReader *reader, uint array_size, const uint64_t *src, uint32_t *dst)
Definition readfile.cc:5021
static void read_file_bhead_idname_map_create(FileData *fd)
Definition readfile.cc:496
static int direct_link_id_restore_recalc_exceptions(const ID *id_current)
Definition readfile.cc:2039
void BLO_read_uint8_array(BlendDataReader *reader, int array_size, uint8_t **ptr_p)
Definition readfile.cc:4935
void BLO_library_link_params_init(LibraryLink_Params *params, Main *bmain, const int flag, const int id_tag_extra)
Definition readfile.cc:4304
static void split_main_newid(Main *mainptr, Main *main_newid)
Definition readfile.cc:4340
static void link_global(FileData *fd, BlendFileData *bfd)
Definition readfile.cc:3085
static BHead * read_global(BlendFileData *bfd, FileData *fd, BHead *bhead)
Definition readfile.cc:3035
int BLO_read_fileversion_get(BlendDataReader *reader)
Definition readfile.cc:4898
BHead * blo_bhead_next(FileData *fd, BHead *thisblock)
Definition readfile.cc:867
blender::ImplicitSharingInfoAndData blo_read_shared_impl(BlendDataReader *reader, const void **ptr_p, const blender::FunctionRef< const blender::ImplicitSharingInfo *()> read_fn)
Definition readfile.cc:5092
static void read_undo_reuse_noundo_local_ids(FileData *fd)
Definition readfile.cc:2533
BlendFileReadReport * BLO_read_data_reports(BlendDataReader *reader)
Definition readfile.cc:5150
BHead * blo_bhead_first(FileData *fd)
Definition readfile.cc:839
static bool read_libblock_is_identical(FileData *fd, BHead *bhead)
Definition readfile.cc:2505
Main * BLO_read_lib_get_main(BlendLibReader *reader)
Definition readfile.cc:5160
static BHead * read_libblock(FileData *fd, Main *main, BHead *bhead, int id_tag, const bool placeholder_set_indirect_extern, ID **r_id)
Definition readfile.cc:2878
static void direct_link_id_common(BlendDataReader *reader, Library *current_library, ID *id, ID *id_old, const int id_tag)
Definition readfile.cc:2096
static int direct_link_id_restore_recalc(const FileData *fd, const ID *id_target, const ID *id_current, const bool is_identical)
Definition readfile.cc:2050
static bool blo_bhead_is_id(const BHead *bhead)
Definition readfile.cc:478
static void direct_link_id_override_property(BlendDataReader *reader, IDOverrideLibraryProperty *op)
Definition readfile.cc:1986
static const char * library_parent_filepath(Library *lib)
Definition readfile.cc:233
static void direct_link_id_embedded_id(BlendDataReader *reader, Library *current_library, ID *id, ID *id_old)
Definition readfile.cc:2006
void BLO_read_glob_list(BlendDataReader *reader, ListBase *list)
Definition readfile.cc:5145
static int has_linked_ids_to_read(Main *mainvar)
Definition readfile.cc:4524
static BHead * blo_bhead_read_full(FileData *fd, BHead *thisblock)
Definition readfile.cc:917
static bool direct_link_id(FileData *fd, Main *main, const int tag, ID *id, ID *id_old)
Definition readfile.cc:2432
static void library_link_end(Main *mainl, FileData **fd, const int flag)
Definition readfile.cc:4364
static void do_versions_userdef(FileData *, BlendFileData *bfd)
Definition readfile.cc:3108
static void split_libdata(ListBase *lb_src, Main **lib_main_array, const uint lib_main_array_len)
Definition readfile.cc:375
void BLO_read_double_array(BlendDataReader *reader, int array_size, double **ptr_p)
Definition readfile.cc:4982
static void add_main_to_main(Main *mainvar, Main *from)
Definition readfile.cc:334
static OldNewMap * oldnewmap_new()
Definition readfile.cc:255
static void after_liblink_id_process(BlendLibReader *reader, ID *id)
Definition readfile.cc:1973
bool BLO_read_data_is_undo(BlendDataReader *reader)
Definition readfile.cc:5135
static bool read_libblock_undo_restore_linked(FileData *fd, Main *libmain, const ID *id, ID **r_id_old, BHead *bhead)
Definition readfile.cc:2639
static void * newdataadr(FileData *fd, const void *adr)
Definition readfile.cc:1467
void * BLO_read_get_new_data_address_no_us(BlendDataReader *reader, const void *old_address, const size_t expected_size)
Definition readfile.cc:4857
void * BLO_read_struct_by_name_array(BlendDataReader *reader, const char *struct_name, const uint32_t items_num, const void *old_address)
Definition readfile.cc:4873
static void do_versions_after_linking(FileData *fd, Main *main)
Definition readfile.cc:3180
ID * BLO_read_get_new_id_address_from_session_uid(BlendLibReader *reader, uint session_uid)
Definition readfile.cc:4893
void BLO_read_float_array(BlendDataReader *reader, int array_size, float **ptr_p)
Definition readfile.cc:4967
void BLO_read_int32_array(BlendDataReader *reader, int array_size, int32_t **ptr_p)
Definition readfile.cc:4947
static bool oldnewmap_insert(OldNewMap *onm, const void *oldaddr, void *newaddr, int nr)
Definition readfile.cc:264
static BHead * read_data_into_datamap(FileData *fd, BHead *bhead, const char *allocname, const int id_type_index)
Definition readfile.cc:2479
ID * BLO_read_get_new_id_address(BlendLibReader *reader, ID *self_id, const bool is_linked_only, ID *id)
Definition readfile.cc:4885
static BHead * find_bhead_from_idname(FileData *fd, const char *idname)
Definition readfile.cc:3981
BlendFileReadReport * BLO_read_lib_reports(BlendLibReader *reader)
Definition readfile.cc:5165
static const char * get_alloc_name(FileData *fd, BHead *bh, const char *blockname, int id_type_index=INDEX_ID_NULL)
Definition readfile.cc:1731
AssetMetaData * blo_bhead_id_asset_data_address(const FileData *fd, const BHead *bhead)
Definition readfile.cc:939
BlendFileData * blo_read_file_internal(FileData *fd, const char *filepath)
Definition readfile.cc:3531
static void switch_endian_structs(const SDNA *filesdna, BHead *bhead)
Definition readfile.cc:1708
static void sort_bhead_old_map(FileData *fd)
Definition readfile.cc:3875
FileData * blo_filedata_from_memfile(MemFile *memfile, const BlendFileReadParams *params, BlendFileReadReport *reports)
Definition readfile.cc:1342
static void fix_relpaths_library(const char *basepath, Main *main)
Definition readfile.cc:2347
static void expand_doit_library(void *fdhandle, Main *mainvar, void *old)
Definition readfile.cc:4016
void BLO_read_pointer_array(BlendDataReader *reader, const int array_size, void **ptr_p)
Definition readfile.cc:5052
static void blo_cache_storage_entry_clear_in_old(ID *, const IDCacheKey *key, void **cache_p, uint, void *cache_storage_v)
Definition readfile.cc:1607
bool BLO_read_lib_is_undo(BlendLibReader *reader)
Definition readfile.cc:5155
void * BLO_read_struct_array_with_size(BlendDataReader *reader, const void *old_address, const size_t expected_size)
Definition readfile.cc:4865
static const void * peek_struct_undo(FileData *fd, BHead *bhead)
Definition readfile.cc:1885
static void * oldnewmap_liblookup(OldNewMap *onm, const void *addr, const bool is_linked_only)
Definition readfile.cc:296
static void oldnewmap_free(OldNewMap *onm)
Definition readfile.cc:323
void BLO_read_uint32_array(BlendDataReader *reader, int array_size, uint32_t **ptr_p)
Definition readfile.cc:4957
static BHeadN * get_bhead(FileData *fd)
Definition readfile.cc:695
static ID * link_named_part(Main *mainl, FileData *fd, const short idcode, const char *name, const int flag)
Definition readfile.cc:4199
static void after_liblink_merged_bmain_process(Main *bmain, BlendFileReadReport *reports)
Definition readfile.cc:3324
void BLO_read_string(BlendDataReader *reader, char **ptr_p)
Definition readfile.cc:4992
void BLO_read_data_globmap_add(BlendDataReader *reader, void *oldaddr, void *newaddr)
Definition readfile.cc:5140
static bool read_libblock_undo_restore(FileData *fd, Main *main, BHead *bhead, int id_tag, ID **r_id_old)
Definition readfile.cc:2777
static int expand_cb(LibraryIDLinkCallbackData *cb_data)
Definition readfile.cc:4129
const char * blo_bhead_id_name(const FileData *fd, const BHead *bhead)
Definition readfile.cc:934
static void read_undo_remap_noundo_data(FileData *fd)
Definition readfile.cc:3493
FileData * blo_filedata_from_file(const char *filepath, BlendFileReadReport *reports)
Definition readfile.cc:1282
static void read_library_linked_id(FileData *basefd, FileData *fd, Main *mainvar, ID *id, ID **r_id)
Definition readfile.cc:4540
static void read_library_linked_ids(FileData *basefd, FileData *fd, ListBase *mainlist, Main *mainvar)
Definition readfile.cc:4592
static void do_versions(FileData *fd, Library *lib, Main *main)
Definition readfile.cc:3119
#define BHEADN_FROM_BHEAD(bh)
Definition readfile.cc:201
static void change_link_placeholder_to_real_ID_pointer_fd(FileData *fd, const void *old, void *newp)
Definition readfile.cc:1498
void BLO_read_char_array(BlendDataReader *reader, int array_size, char **ptr_p)
Definition readfile.cc:4929
Main * BLO_library_link_begin(BlendHandle **bh, const char *filepath, const LibraryLink_Params *params)
Definition readfile.cc:4332
bool BLO_read_requires_endian_switch(BlendDataReader *reader)
Definition readfile.cc:4903
static ID * library_id_is_yet_read(FileData *fd, Main *mainvar, BHead *bhead)
Definition readfile.cc:3990
static void blo_cache_storage_entry_restore_in_new(ID *id, const IDCacheKey *key, void **cache_p, uint flags, void *cache_storage_v)
Definition readfile.cc:1572
static void direct_link_keymapitem(BlendDataReader *reader, wmKeyMapItem *kmi)
Definition readfile.cc:3358
static void blo_cache_storage_entry_register(ID *id, const IDCacheKey *key, void **cache_p, uint, void *cache_storage_v)
Definition readfile.cc:1552
static void * newlibadr(FileData *fd, ID *, const bool is_linked_only, const void *adr)
Definition readfile.cc:1484
void blo_split_main(ListBase *mainlist, Main *main)
Definition readfile.cc:397
static int verg_bheadsort(const void *v1, const void *v2)
Definition readfile.cc:3861
void BLO_library_link_params_init_with_context(LibraryLink_Params *params, Main *bmain, const int flag, const int id_tag_extra, Scene *scene, ViewLayer *view_layer, const View3D *v3d)
Definition readfile.cc:4315
static bool read_file_dna(FileData *fd, const char **r_error_message)
Definition readfile.cc:997
void blo_do_versions_key_uidgen(Key *key)
Definition readfile.cc:2211
static void placeholders_ensure_valid(Main *bmain)
Definition readfile.cc:2420
static BHead * find_bhead_from_code_name(FileData *fd, const short idcode, const char *name)
Definition readfile.cc:3951
void blo_cache_storage_init(FileData *fd, Main *bmain)
Definition readfile.cc:1628
void blo_make_old_idmap_from_main(FileData *fd, Main *bmain)
Definition readfile.cc:1533
short BLO_version_from_file(const char *filepath)
Definition readfile.cc:1449
BHead * blo_read_asset_data_block(FileData *fd, BHead *bhead, AssetMetaData **r_asset_data)
Definition readfile.cc:3012
static void read_libblock_undo_restore_identical(FileData *fd, Main *main, const ID *, ID *id_old, BHead *bhead, const int id_tag)
Definition readfile.cc:2688
static void change_link_placeholder_to_real_ID_pointer(ListBase *mainlist, FileData *basefd, void *old, void *newp)
Definition readfile.cc:1512
static FileData * blo_filedata_from_file_minimal(const char *filepath)
Definition readfile.cc:1298
static void oldnewmap_clear(OldNewMap *onm)
Definition readfile.cc:312
static void decode_blender_header(FileData *fd)
Definition readfile.cc:947
static void read_libblock_undo_restore_at_old_address(FileData *fd, Main *main, ID *id, ID *id_old)
Definition readfile.cc:2736
static void bh4_from_bh8(BHead *bhead, BHead8 *bhead8, bool do_endian_swap)
Definition readfile.cc:655
void BLO_reportf_wrap(BlendFileReadReport *reports, eReportType type, const char *format,...)
Definition readfile.cc:213
static void * oldnewmap_lookup_and_inc(OldNewMap *onm, const void *addr, bool increase_users)
Definition readfile.cc:283
static BHead * find_previous_lib(FileData *fd, BHead *bhead)
Definition readfile.cc:3901
#define BHEAD_USE_READ_ON_DEMAND(bhead)
Definition readfile.cc:207
static void read_library_clear_weak_links(FileData *basefd, ListBase *mainlist, Main *mainvar)
Definition readfile.cc:4641
void * BLO_library_read_struct(FileData *fd, BHead *bh, const char *blockname)
Definition readfile.cc:4513
static CLG_LogRef LOG
Definition readfile.cc:180
static bool is_minversion_older_than_blender(FileData *fd, ReportList *reports)
Definition readfile.cc:1120
void BLO_expand_main(void *fdhandle, Main *mainvar, BLOExpandDoitCallback callback)
Definition readfile.cc:4159
void * BLO_read_get_new_data_address(BlendDataReader *reader, const void *old_address)
Definition readfile.cc:4852
static void switch_endian_bh4(BHead4 *bhead)
Definition readfile.cc:627
static Main * library_link_begin(Main *mainvar, FileData *fd, const char *filepath, const int id_tag_extra)
Definition readfile.cc:4269
static void blo_read_file_checks(Main *bmain)
Definition readfile.cc:3515
static void switch_endian_bh8(BHead8 *bhead)
Definition readfile.cc:641
ID * BLO_library_link_named_part(Main *mainl, BlendHandle **bh, const short idcode, const char *name, const LibraryLink_Params *params)
Definition readfile.cc:4248
static bool blo_bhead_read_data(FileData *fd, BHead *thisblock, void *buf)
Definition readfile.cc:894
static Main * blo_find_main(FileData *fd, const char *filepath, const char *relabase)
Definition readfile.cc:537
static BHead * read_userdef(BlendFileData *bfd, FileData *fd, BHead *bhead)
Definition readfile.cc:3366
void blo_filedata_free(FileData *fd)
Definition readfile.cc:1359
static int * read_file_thumbnail(FileData *fd)
Definition readfile.cc:1052
static bool blo_bhead_is_id_valid_type(const BHead *bhead)
Definition readfile.cc:485
static void after_liblink_id_embedded_id_process(BlendLibReader *reader, ID *id)
Definition readfile.cc:1929
BHead * blo_bhead_prev(FileData *, BHead *thisblock)
Definition readfile.cc:859
static void read_undo_move_libmain_data(FileData *fd, Main *new_main, Main *old_main, Main *libmain, BHead *bhead)
Definition readfile.cc:2567
static void oldnewmap_lib_insert(FileData *fd, const void *oldaddr, ID *newaddr, int id_code)
Definition readfile.cc:273
void BLO_read_int8_array(BlendDataReader *reader, int array_size, int8_t **ptr_p)
Definition readfile.cc:4941
void blo_readfile_invalidate(FileData *fd, Main *bmain, const char *message)
Definition readfile.cc:590
void BLO_library_link_end(Main *mainl, BlendHandle **bh, const LibraryLink_Params *params)
Definition readfile.cc:4484
static void read_file_version(FileData *fd, Main *main)
Definition readfile.cc:450
void blo_cache_storage_old_bmain_clear(FileData *fd, Main *bmain_old)
Definition readfile.cc:1665
static CLG_LogRef LOG_UNDO
Definition readfile.cc:181
static FileData * blo_filedata_from_file_open(const char *filepath, BlendFileReadReport *reports)
Definition readfile.cc:1267
static int read_undo_remap_noundo_data_cb(LibraryIDLinkCallbackData *cb_data)
Definition readfile.cc:3471
static void * blo_verify_data_address(void *new_address, const void *, const size_t expected_size)
Definition readfile.cc:4837
static void * read_struct(FileData *fd, BHead *bh, const char *blockname, const int id_type_index)
Definition readfile.cc:1808
void blo_join_main(ListBase *mainlist)
Definition readfile.cc:350
static void convert_pointer_array_32_to_64(BlendDataReader *, uint array_size, const uint32_t *src, uint64_t *dst)
Definition readfile.cc:5041
static FileData * blo_decode_and_check(FileData *fd, ReportList *reports)
Definition readfile.cc:1166
void * blo_read_get_new_globaldata_address(FileData *fd, const void *adr)
Definition readfile.cc:1478
static FileData * read_library_file_data(FileData *basefd, ListBase *mainlist, Main *mainl, Main *mainptr)
Definition readfile.cc:4663
void blo_do_versions_400(FileData *fd, Library *lib, Main *bmain)
void blo_do_versions_300(FileData *fd, Library *lib, Main *bmain)
void do_versions_after_linking_300(FileData *fd, Main *bmain)
void blo_do_versions_dna(SDNA *sdna, int versionfile, int subversionfile)
void blo_do_versions_250(FileData *fd, Library *lib, Main *bmain)
void do_versions_after_linking_400(FileData *fd, Main *bmain)
void do_versions_after_linking_250(Main *bmain)
void do_versions_after_linking_290(FileData *fd, Main *bmain)
@ FD_FLAGS_FILE_POINTSIZE_IS_4
Definition readfile.hh:42
@ FD_FLAGS_POINTSIZE_DIFFERS
Definition readfile.hh:43
@ FD_FLAGS_IS_MEMFILE
Definition readfile.hh:45
@ FD_FLAGS_FILE_OK
Definition readfile.hh:44
@ FD_FLAGS_SWITCH_ENDIAN
Definition readfile.hh:41
@ FD_FLAGS_FILE_FUTURE
Definition readfile.hh:50
void blo_do_versions_userdef(UserDef *userdef)
void do_versions_after_linking_280(FileData *fd, Main *bmain)
void blo_do_versions_290(FileData *fd, Library *lib, Main *bmain)
void blo_do_versions_270(FileData *fd, Library *lib, Main *bmain)
void do_versions_after_linking_270(Main *bmain)
void do_versions_after_linking_260(Main *bmain)
void blo_do_versions_260(FileData *fd, Library *lib, Main *bmain)
#define SIZEOFBLENDERHEADER
Definition readfile.hh:155
void blo_do_versions_pre250(FileData *fd, Library *lib, Main *bmain)
void blo_do_versions_280(FileData *fd, Library *lib, 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 char uint8_t
Definition stdint.h:78
unsigned __int64 uint64_t
Definition stdint.h:90
signed char int8_t
Definition stdint.h:75
The meta-data of an asset. By creating and giving this for a data-block (ID.asset_data),...
uint64_t old
off64_t file_offset
Definition readfile.cc:193
bool has_data
Definition readfile.cc:195
BHeadN * prev
Definition readfile.cc:190
bool is_memchunk_identical
Definition readfile.cc:197
BHead bhead
Definition readfile.cc:198
BHeadN * next
Definition readfile.cc:190
const void * old
Definition readfile.cc:3858
BHead * bhead
Definition readfile.cc:3857
const void * old
MemArena * memarena
Definition readfile.cc:1543
GHash * cache_map
Definition readfile.cc:1542
blender::Map< const void *, blender::ImplicitSharingInfoAndData > shared_data_by_stored_address
Definition readfile.cc:619
FileData * fd
Definition readfile.cc:613
FileData * fd
Definition readfile.cc:4011
BLOExpandDoitCallback callback
Definition readfile.cc:4013
UserDef * user
ViewLayer * cur_view_layer
char filepath[1024]
eBlenFileType type
bScreen * curscreen
struct BlendFileReadReport::@127 duration
struct BlendFileReadReport::@128 count
FileData * fd
Definition readfile.cc:623
char rect[0]
Definition BKE_main.hh:46
eBLOReadSkip skip_flags
Definition readfile.hh:103
int undo_direction
Definition readfile.hh:75
int id_asset_data_offset
Definition readfile.hh:98
ListBase * old_mainlist
Definition readfile.hh:133
GHash * bhead_idname_hash
Definition readfile.hh:129
enum eFileDataFlag flags
Definition readfile.hh:68
ListBase bhead_list
Definition readfile.hh:67
int fileversion
Definition readfile.hh:93
void * storage_handle
Definition readfile.hh:152
int fileflags
Definition readfile.hh:100
DNA_ReconstructInfo * reconstruct_info
Definition readfile.hh:91
BHeadSort * bheadmap
Definition readfile.hh:125
ListBase * mainlist
Definition readfile.hh:131
IDNameLib_Map * new_idmap_uid
Definition readfile.hh:147
OldNewMap * globmap
Definition readfile.hh:114
OldNewMap * datamap
Definition readfile.hh:113
int id_tag_extra
Definition readfile.hh:111
FileReader * file
Definition readfile.hh:71
char relabase[FILE_MAX]
Definition readfile.hh:84
const char * compflags
Definition readfile.hh:90
BLOCacheStorage * cache_storage
Definition readfile.hh:123
int globalf
Definition readfile.hh:100
int id_name_offset
Definition readfile.hh:95
OldNewMap * libmap
Definition readfile.hh:121
BlendFileReadReport * reports
Definition readfile.hh:149
bool is_eof
Definition readfile.hh:69
int tot_bheadmap
Definition readfile.hh:126
const SDNA * memsdna
Definition readfile.hh:88
IDNameLib_Map * old_idmap_uid
Definition readfile.hh:137
SDNA * filesdna
Definition readfile.hh:87
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_uid
Definition BKE_idtype.hh:69
IDTypeBlendReadUndoPreserve blend_read_undo_preserve
short id_code
const char * name
IDTypeForeachCacheFunction foreach_cache
IDTypeBlendReadDataFunction blend_read_data
uint32_t flags
AssetTypeInfo * asset_type_info
IDTypeBlendReadAfterLiblinkFunction blend_read_after_liblink
Definition DNA_ID.h:413
unsigned int recalc_after_undo_push
Definition DNA_ID.h:448
unsigned int recalc
Definition DNA_ID.h:437
int tag
Definition DNA_ID.h:434
struct Library * lib
Definition DNA_ID.h:419
int us
Definition DNA_ID.h:435
int icon_id
Definition DNA_ID.h:436
struct ID * newid
Definition DNA_ID.h:417
struct ID * orig_id
Definition DNA_ID.h:466
char name[66]
Definition DNA_ID.h:425
unsigned int recalc_up_to_undo_push
Definition DNA_ID.h:447
int uidgen
ListBase block
struct Library * parent
Definition DNA_ID.h:512
short versionfile
Definition DNA_ID.h:522
short subversionfile
Definition DNA_ID.h:522
struct FileData * filedata
Definition DNA_ID.h:499
char filepath_abs[1024]
Definition DNA_ID.h:509
struct PackedFile * packedfile
Definition DNA_ID.h:533
char filepath[1024]
Definition DNA_ID.h:531
struct Library_Runtime runtime
Definition DNA_ID.h:535
ID id
Definition DNA_ID.h:529
void * last
void * first
ListBase scenes
Definition BKE_main.hh:210
ListBase wm
Definition BKE_main.hh:239
short subversionfile
Definition BKE_main.hh:137
bool is_asset_edit_file
Definition BKE_main.hh:151
bool has_forward_compatibility_issues
Definition BKE_main.hh:144
char filepath[1024]
Definition BKE_main.hh:136
BlendThumbnail * blen_thumb
Definition BKE_main.hh:207
Main * prev
Definition BKE_main.hh:123
short minversionfile
Definition BKE_main.hh:138
uint64_t build_commit_timestamp
Definition BKE_main.hh:154
ListBase libraries
Definition BKE_main.hh:211
IDNameLib_Map * id_map
Definition BKE_main.hh:263
char build_hash[16]
Definition BKE_main.hh:156
Main * next
Definition BKE_main.hh:123
short minsubversionfile
Definition BKE_main.hh:138
short versionfile
Definition BKE_main.hh:137
bool is_read_invalid
Definition BKE_main.hh:183
Library * curlib
Definition BKE_main.hh:209
ListBase objects
Definition BKE_main.hh:212
blender::Map< const void *, const blender::ImplicitSharingInfo * > map
MemFileSharedStorage * shared_storage
void * newp
Definition readfile.cc:245
blender::Map< const void *, NewAddress > map
Definition readfile.cc:252
int pointer_size
struct Scene * set
MemFile * memfile
struct ListBase addons
ListBase script_directories
struct ListBase uistyles
struct ListBase asset_shelves_settings
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 extension_repos
struct ListBase user_menus
struct ListBase asset_libraries
char app_template[64]
UserDef_Runtime runtime
char name[64]
struct IDProperty * prop
struct PointerRNA * ptr
static DynamicLibrary lib
PointerRNA * ptr
Definition wm_files.cc:4126
uint8_t flag
Definition wm_window.cc:138