Blender V4.5
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
8
9#include "fmt/core.h"
10
11#include <cerrno>
12#include <cstdarg> /* for va_start/end. */
13#include <cstddef> /* for offsetof. */
14#include <cstdlib> /* for atoi. */
15#include <cstring>
16#include <ctime> /* for gmtime. */
17#include <fcntl.h> /* for open flags (O_BINARY, O_RDONLY). */
18
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 <fmt/format.h>
28
29#include "CLG_log.h"
30
31/* allow readfile to use deprecated functionality */
32#define DNA_DEPRECATED_ALLOW
33
34#include "DNA_asset_types.h"
38#include "DNA_genfile.h"
39#include "DNA_key_types.h"
40#include "DNA_layer_types.h"
41#include "DNA_node_types.h"
43#include "DNA_sdna_types.h"
44#include "DNA_userdef_types.h"
45
47#include "MEM_guardedalloc.h"
48
49#include "BLI_endian_defines.h"
50#include "BLI_endian_switch.h"
51#include "BLI_fileops.h"
52#include "BLI_ghash.h"
53#include "BLI_map.hh"
54#include "BLI_memarena.h"
55#include "BLI_set.hh"
56#include "BLI_string.h"
57#include "BLI_string_ref.hh"
58#include "BLI_string_utf8.h"
59#include "BLI_string_utils.hh"
60#include "BLI_threads.h"
61#include "BLI_time.h"
62#include "BLI_utildefines.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_library.hh"
80#include "BKE_main.hh" /* for Main */
81#include "BKE_main_idmap.hh"
83#include "BKE_main_namemap.hh"
84#include "BKE_material.hh"
85#include "BKE_mesh.hh"
86#include "BKE_modifier.hh"
87#include "BKE_nla.hh"
88#include "BKE_node.hh" /* for tree type defines */
90#include "BKE_object.hh"
91#include "BKE_packedFile.hh"
92#include "BKE_preferences.h"
93#include "BKE_report.hh"
94#include "BKE_scene.hh"
95#include "BKE_screen.hh"
96#include "BKE_undo_system.hh"
97#include "BKE_workspace.hh"
98
99#include "DRW_engine.hh"
100
101#include "DEG_depsgraph.hh"
102
103#include "BLO_blend_validate.hh"
104#include "BLO_read_write.hh"
105#include "BLO_readfile.hh"
106#include "BLO_undofile.hh"
107
108#include "SEQ_iterator.hh"
109#include "SEQ_modifier.hh"
110#include "SEQ_sequencer.hh"
111#include "SEQ_utils.hh"
112
113#include "readfile.hh"
114#include "versioning_common.hh"
115
116/* Make preferences read-only. */
117#define U (*((const UserDef *)&U))
118
168
176#define USE_BHEAD_READ_ON_DEMAND
177
178static CLG_LogRef LOG = {"blo.readfile"};
179static CLG_LogRef LOG_UNDO = {"blo.readfile.undo"};
180
181#if ENDIAN_ORDER == B_ENDIAN
182# warning "Support for Big Endian endianness is deprecated and will be removed in Blender 5.0"
183#endif
184
185/* local prototypes */
186static void read_libraries(FileData *basefd, ListBase *mainlist);
187static void *read_struct(FileData *fd, BHead *bh, const char *blockname, const int id_type_index);
188static BHead *find_bhead_from_code_name(FileData *fd, const short idcode, const char *name);
189
190struct BHeadN {
192#ifdef USE_BHEAD_READ_ON_DEMAND
194 off64_t file_offset;
197#endif
200};
201
202#define BHEADN_FROM_BHEAD(bh) ((BHeadN *)POINTER_OFFSET(bh, -int(offsetof(BHeadN, bhead))))
203
208#define BHEAD_USE_READ_ON_DEMAND(bhead) ((bhead)->code == BLO_CODE_DATA)
209
210/* -------------------------------------------------------------------- */
213
215 const eReportType type,
216 const char *format,
217 ...)
218{
219 char fixed_buf[1024]; /* should be long enough */
220
221 va_list args;
222
223 va_start(args, format);
224 vsnprintf(fixed_buf, sizeof(fixed_buf), format, args);
225 va_end(args);
226
227 fixed_buf[sizeof(fixed_buf) - 1] = '\0';
228
229 BKE_report(reports->reports, type, fixed_buf);
230
231 if (G.background == 0) {
232 printf("%s: %s\n", BKE_report_type_str(type), fixed_buf);
233 }
234}
235
236/* for reporting linking messages */
238{
239 return lib->runtime->parent ? lib->runtime->parent->runtime->filepath_abs : "<direct>";
240}
241
243
244/* -------------------------------------------------------------------- */
247
249 void *newp;
250
252 int nr;
253};
254
258
260{
261 return MEM_new<OldNewMap>(__func__);
262}
263
268static bool oldnewmap_insert(OldNewMap *onm, const void *oldaddr, void *newaddr, const int nr)
269{
270 if (oldaddr == nullptr || newaddr == nullptr) {
271 return false;
272 }
273
274 return onm->map.add_overwrite(oldaddr, NewAddress{newaddr, nr});
275}
276
277static void oldnewmap_lib_insert(FileData *fd, const void *oldaddr, ID *newaddr, const int id_code)
278{
279 oldnewmap_insert(fd->libmap, oldaddr, newaddr, id_code);
280}
281
283 const void *oldaddr,
284 void *newaddr,
285 const int nr)
286{
287 oldnewmap_insert(onm, oldaddr, newaddr, nr);
288}
289
290static void *oldnewmap_lookup_and_inc(OldNewMap *onm, const void *addr, const bool increase_users)
291{
292 NewAddress *entry = onm->map.lookup_ptr(addr);
293 if (entry == nullptr) {
294 return nullptr;
295 }
296 if (increase_users) {
297 entry->nr++;
298 }
299 return entry->newp;
300}
301
302/* for libdata, NewAddress.nr has ID code, no increment */
303static void *oldnewmap_liblookup(OldNewMap *onm, const void *addr, const bool is_linked_only)
304{
305 if (addr == nullptr) {
306 return nullptr;
307 }
308
309 ID *id = static_cast<ID *>(oldnewmap_lookup_and_inc(onm, addr, false));
310 if (id == nullptr) {
311 return nullptr;
312 }
313 if (!is_linked_only || ID_IS_LINKED(id)) {
314 return id;
315 }
316 return nullptr;
317}
318
319static void oldnewmap_clear(OldNewMap *onm)
320{
321 /* Free unused data. */
322 for (NewAddress &new_addr : onm->map.values()) {
323 if (new_addr.nr == 0) {
324 MEM_freeN(new_addr.newp);
325 }
326 }
327 onm->map.clear();
328}
329
330static void oldnewmap_free(OldNewMap *onm)
331{
332 MEM_delete(onm);
333}
334
336
337/* -------------------------------------------------------------------- */
340
341static void add_main_to_main(Main *mainvar, Main *from)
342{
343 if (from->is_read_invalid) {
344 mainvar->is_read_invalid = true;
345 }
346
347 MainListsArray lbarray = BKE_main_lists_get(*mainvar);
348 MainListsArray fromarray = BKE_main_lists_get(*from);
349 int a = fromarray.size();
350 while (a--) {
351 BLI_movelisttolist(lbarray[a], fromarray[a]);
352 }
353}
354
355void blo_join_main(ListBase *mainlist)
356{
357 Main *tojoin, *mainl;
358
359 mainl = static_cast<Main *>(mainlist->first);
360
361 if (mainl->id_map != nullptr) {
362 /* Cannot keep this since we add some IDs from joined mains. */
364 mainl->id_map = nullptr;
365 }
366
367 /* Will no longer be valid after joining. */
369
370 while ((tojoin = mainl->next)) {
371 BLI_assert(((tojoin->curlib->runtime->tag & LIBRARY_IS_ASSET_EDIT_FILE) != 0) ==
372 tojoin->is_asset_edit_file);
373 add_main_to_main(mainl, tojoin);
374 BLI_remlink(mainlist, tojoin);
375 tojoin->next = tojoin->prev = nullptr;
376 BKE_main_free(tojoin);
377 }
378}
379
380static void split_libdata(ListBase *lb_src, Main **lib_main_array, const uint lib_main_array_len)
381{
382 for (ID *id = static_cast<ID *>(lb_src->first), *idnext; id; id = idnext) {
383 idnext = static_cast<ID *>(id->next);
384
385 if (id->lib) {
386 if ((uint(id->lib->runtime->temp_index) < lib_main_array_len) &&
387 /* this check should never fail, just in case 'id->lib' is a dangling pointer. */
388 (lib_main_array[id->lib->runtime->temp_index]->curlib == id->lib))
389 {
390 Main *mainvar = lib_main_array[id->lib->runtime->temp_index];
391 ListBase *lb_dst = which_libbase(mainvar, GS(id->name));
392 BLI_remlink(lb_src, id);
393 BLI_addtail(lb_dst, id);
394 }
395 else {
396 CLOG_ERROR(&LOG, "Invalid library for '%s'", id->name);
397 }
398 }
399 }
400}
401
403{
404 mainlist->first = mainlist->last = main;
405 main->next = nullptr;
406
407 if (BLI_listbase_is_empty(&main->libraries)) {
408 return;
409 }
410
411 if (main->id_map != nullptr) {
412 /* Cannot keep this since we remove some IDs from given main. */
414 main->id_map = nullptr;
415 }
416
417 /* Will no longer be valid after splitting. */
419
420 /* (Library.temp_index -> Main), lookup table */
421 const uint lib_main_array_len = BLI_listbase_count(&main->libraries);
422 Main **lib_main_array = MEM_malloc_arrayN<Main *>(lib_main_array_len, __func__);
423
424 int i = 0;
425 for (Library *lib = static_cast<Library *>(main->libraries.first); lib;
426 lib = static_cast<Library *>(lib->id.next), i++)
427 {
428 Main *libmain = BKE_main_new();
429 libmain->curlib = lib;
430 libmain->versionfile = lib->runtime->versionfile;
431 libmain->subversionfile = lib->runtime->subversionfile;
434 libmain->is_asset_edit_file = (lib->runtime->tag & LIBRARY_IS_ASSET_EDIT_FILE) != 0;
435 BLI_addtail(mainlist, libmain);
436 lib->runtime->temp_index = i;
437 lib_main_array[i] = libmain;
438 }
439
441 i = lbarray.size();
442 while (i--) {
443 ID *id = static_cast<ID *>(lbarray[i]->first);
444 if (id == nullptr || GS(id->name) == ID_LI) {
445 /* No ID_LI data-block should ever be linked anyway, but just in case, better be explicit. */
446 continue;
447 }
448 split_libdata(lbarray[i], lib_main_array, lib_main_array_len);
449 }
450
451 MEM_freeN(lib_main_array);
452}
453
455{
456 BHead *bhead;
457
458 for (bhead = blo_bhead_first(fd); bhead; bhead = blo_bhead_next(fd, bhead)) {
459 if (bhead->code == BLO_CODE_GLOB) {
460 FileGlobal *fg = static_cast<FileGlobal *>(
461 read_struct(fd, bhead, "Data from Global block", INDEX_ID_NULL));
462 if (fg) {
463 if (main->versionfile != fd->fileversion) {
464 /* `versionfile` remains unset when linking from a new library (`main` has then just be
465 * created by `blo_find_main`). */
466 BLI_assert(main->versionfile == 0);
467 main->versionfile = short(fd->fileversion);
468 }
469 main->subversionfile = fg->subversion;
470 main->minversionfile = fg->minversion;
471 main->minsubversionfile = fg->minsubversion;
472 main->has_forward_compatibility_issues = !MAIN_VERSION_FILE_OLDER_OR_EQUAL(
474 main->is_asset_edit_file = (fg->fileflags & G_FILE_ASSET_EDIT_FILE) != 0;
475 MEM_freeN(fg);
476 }
477 else if (bhead->code == BLO_CODE_ENDB) {
478 break;
479 }
480 }
481 }
482 if (main->curlib) {
483 main->curlib->runtime->versionfile = main->versionfile;
484 main->curlib->runtime->subversionfile = main->subversionfile;
486 main->curlib->runtime->tag, main->is_asset_edit_file, LIBRARY_IS_ASSET_EDIT_FILE);
487 }
488}
489
490static bool blo_bhead_is_id(const BHead *bhead)
491{
492 /* BHead codes are four bytes (like 'ENDB', 'TEST', etc.), but if the two most-significant bytes
493 * are zero, the values actually indicate an ID type. */
494 return bhead->code <= 0xFFFF;
495}
496
497static bool blo_bhead_is_id_valid_type(const BHead *bhead)
498{
499 if (!blo_bhead_is_id(bhead)) {
500 return false;
501 }
502
503 const short id_type_code = bhead->code & 0xFFFF;
504 return BKE_idtype_idcode_is_valid(id_type_code);
505}
506
508{
509 /* dummy values */
510 bool is_link = false;
511 int code_prev = BLO_CODE_ENDB;
512
513 fd->bhead_idname_map.emplace();
514 for (BHead *bhead = blo_bhead_first(fd); bhead; bhead = blo_bhead_next(fd, bhead)) {
515 if (code_prev != bhead->code) {
516 code_prev = bhead->code;
517 is_link = blo_bhead_is_id_valid_type(bhead) ?
518 BKE_idtype_idcode_is_linkable(short(code_prev)) :
519 false;
520 }
521
522 if (is_link) {
523 /* #idname may be null in case the ID name of the given BHead is detected as invalid (e.g.
524 * because it comes from a future version of Blender allowing for longer ID names). These
525 * 'invalid-named IDs' are skipped here, which will e.g. prevent them from being linked. */
526 const char *idname = blo_bhead_id_name(fd, bhead);
527 if (idname) {
528 fd->bhead_idname_map->add(idname, bhead);
529 }
530 }
531 }
532}
533
534static Main *blo_find_main(FileData *fd, const char *filepath, const char *relabase)
535{
536 ListBase *mainlist = fd->mainlist;
537 Main *m;
538 Library *lib;
539 char filepath_abs[FILE_MAX];
540
541 STRNCPY(filepath_abs, filepath);
542 BLI_path_abs(filepath_abs, relabase);
543 BLI_path_normalize(filepath_abs);
544
545 // printf("blo_find_main: relabase %s\n", relabase);
546 // printf("blo_find_main: original in %s\n", filepath);
547 // printf("blo_find_main: converted to %s\n", filepath_abs);
548
549 LISTBASE_FOREACH (Main *, m, mainlist) {
550 const char *libname = (m->curlib) ? m->curlib->runtime->filepath_abs : m->filepath;
551
552 if (BLI_path_cmp(filepath_abs, libname) == 0) {
553 if (G.debug & G_DEBUG) {
554 CLOG_INFO(&LOG, 3, "Found library %s", libname);
555 }
556 return m;
557 }
558 }
559
560 m = BKE_main_new();
561 BLI_addtail(mainlist, m);
562
563 /* Add library data-block itself to 'main' Main, since libraries are **never** linked data.
564 * Fixes bug where you could end with all ID_LI data-blocks having the same name... */
565 lib = BKE_id_new<Library>(static_cast<Main *>(mainlist->first), BLI_path_basename(filepath));
566
567 /* Important, consistency with main ID reading code from read_libblock(). */
568 lib->id.us = ID_FAKE_USERS(lib);
569
570 /* Matches direct_link_library(). */
572
573 STRNCPY(lib->filepath, filepath);
574 STRNCPY(lib->runtime->filepath_abs, filepath_abs);
575
576 m->curlib = lib;
577
578 read_file_version(fd, m);
579
580 if (G.debug & G_DEBUG) {
581 CLOG_INFO(&LOG, 3, "Added new lib %s", filepath);
582 }
583 return m;
584}
585
586void blo_readfile_invalidate(FileData *fd, Main *bmain, const char *message)
587{
588 /* Tag given `bmain`, and 'root 'local' main one (in case given one is a library one) as invalid.
589 */
590 bmain->is_read_invalid = true;
591 for (; bmain->prev != nullptr; bmain = bmain->prev) {
592 /* Pass. */
593 }
594 bmain->is_read_invalid = true;
595
597 RPT_ERROR,
598 "A critical error happened (the blend file is likely corrupted): %s",
599 message);
600}
601
603
604/* -------------------------------------------------------------------- */
607
617
622
624{
625 BHeadN *new_bhead = nullptr;
626 const bool do_endian_swap = fd->flags & FD_FLAGS_SWITCH_ENDIAN;
627
628 if (fd) {
629 if (!fd->is_eof) {
630 std::optional<BHead> bhead_opt = BLO_readfile_read_bhead(
631 fd->file, fd->blender_header.bhead_type(), do_endian_swap);
632 BHead *bhead = nullptr;
633 if (!bhead_opt.has_value()) {
634 fd->is_eof = true;
635 }
636 else if (bhead_opt->len < 0) {
637 /* Make sure people are not trying to parse bad blend files. */
638 fd->is_eof = true;
639 }
640 else {
641 bhead = &bhead_opt.value();
642 }
643
644 /* bhead now contains the (converted) bhead structure. Now read
645 * the associated data and put everything in a BHeadN (creative naming !)
646 */
647 if (fd->is_eof) {
648 /* pass */
649 }
650#ifdef USE_BHEAD_READ_ON_DEMAND
651 else if (fd->file->seek != nullptr && BHEAD_USE_READ_ON_DEMAND(bhead)) {
652 /* Delay reading bhead content. */
653 new_bhead = MEM_mallocN<BHeadN>("new_bhead");
654 if (new_bhead) {
655 new_bhead->next = new_bhead->prev = nullptr;
656 new_bhead->file_offset = fd->file->offset;
657 new_bhead->has_data = false;
658 new_bhead->is_memchunk_identical = false;
659 new_bhead->bhead = *bhead;
660 const off64_t seek_new = fd->file->seek(fd->file, bhead->len, SEEK_CUR);
661 if (UNLIKELY(seek_new == -1)) {
662 fd->is_eof = true;
663 MEM_freeN(new_bhead);
664 new_bhead = nullptr;
665 }
666 else {
667 BLI_assert(fd->file->offset == seek_new);
668 }
669 }
670 else {
671 fd->is_eof = true;
672 }
673 }
674#endif
675 else {
676 new_bhead = static_cast<BHeadN *>(
677 MEM_mallocN(sizeof(BHeadN) + size_t(bhead->len), "new_bhead"));
678 if (new_bhead) {
679 new_bhead->next = new_bhead->prev = nullptr;
680#ifdef USE_BHEAD_READ_ON_DEMAND
681 new_bhead->file_offset = 0; /* don't seek. */
682 new_bhead->has_data = true;
683#endif
684 new_bhead->is_memchunk_identical = false;
685 new_bhead->bhead = *bhead;
686
687 const int64_t readsize = fd->file->read(fd->file, new_bhead + 1, size_t(bhead->len));
688
689 if (UNLIKELY(readsize != bhead->len)) {
690 fd->is_eof = true;
691 MEM_freeN(new_bhead);
692 new_bhead = nullptr;
693 }
694 else {
695 if (fd->flags & FD_FLAGS_IS_MEMFILE) {
696 new_bhead->is_memchunk_identical = ((UndoReader *)fd->file)->memchunk_identical;
697 }
698 }
699 }
700 else {
701 fd->is_eof = true;
702 }
703 }
704 }
705 }
706
707 /* We've read a new block. Now add it to the list
708 * of blocks.
709 */
710 if (new_bhead) {
711 BLI_addtail(&fd->bhead_list, new_bhead);
712 }
713
714 return new_bhead;
715}
716
718{
719 BHeadN *new_bhead;
720 BHead *bhead = nullptr;
721
722 /* Rewind the file
723 * Read in a new block if necessary
724 */
725 new_bhead = static_cast<BHeadN *>(fd->bhead_list.first);
726 if (new_bhead == nullptr) {
727 new_bhead = get_bhead(fd);
728 }
729
730 if (new_bhead) {
731 bhead = &new_bhead->bhead;
732 }
733
734 return bhead;
735}
736
737BHead *blo_bhead_prev(FileData * /*fd*/, BHead *thisblock)
738{
739 BHeadN *bheadn = BHEADN_FROM_BHEAD(thisblock);
740 BHeadN *prev = bheadn->prev;
741
742 return (prev) ? &prev->bhead : nullptr;
743}
744
746{
747 BHeadN *new_bhead = nullptr;
748 BHead *bhead = nullptr;
749
750 if (thisblock) {
751 /* bhead is actually a sub part of BHeadN
752 * We calculate the BHeadN pointer from the BHead pointer below */
753 new_bhead = BHEADN_FROM_BHEAD(thisblock);
754
755 /* get the next BHeadN. If it doesn't exist we read in the next one */
756 new_bhead = new_bhead->next;
757 if (new_bhead == nullptr) {
758 new_bhead = get_bhead(fd);
759 }
760 }
761
762 if (new_bhead) {
763 /* here we do the reverse:
764 * go from the BHeadN pointer to the BHead pointer */
765 bhead = &new_bhead->bhead;
766 }
767
768 return bhead;
769}
770
771#ifdef USE_BHEAD_READ_ON_DEMAND
772static bool blo_bhead_read_data(FileData *fd, BHead *thisblock, void *buf)
773{
774 bool success = true;
775 BHeadN *new_bhead = BHEADN_FROM_BHEAD(thisblock);
776 BLI_assert(new_bhead->has_data == false && new_bhead->file_offset != 0);
777 off64_t offset_backup = fd->file->offset;
778 if (UNLIKELY(fd->file->seek(fd->file, new_bhead->file_offset, SEEK_SET) == -1)) {
779 success = false;
780 }
781 else {
782 if (UNLIKELY(fd->file->read(fd->file, buf, size_t(new_bhead->bhead.len)) !=
783 new_bhead->bhead.len))
784 {
785 success = false;
786 }
787 else {
788 if (fd->flags & FD_FLAGS_IS_MEMFILE) {
789 new_bhead->is_memchunk_identical = ((UndoReader *)fd->file)->memchunk_identical;
790 }
791 }
792 }
793 if (fd->file->seek(fd->file, offset_backup, SEEK_SET) == -1) {
794 success = false;
795 }
796 return success;
797}
798
799static BHead *blo_bhead_read_full(FileData *fd, BHead *thisblock)
800{
801 BHeadN *new_bhead = BHEADN_FROM_BHEAD(thisblock);
802 BHeadN *new_bhead_data = static_cast<BHeadN *>(
803 MEM_mallocN(sizeof(BHeadN) + new_bhead->bhead.len, "new_bhead"));
804 new_bhead_data->bhead = new_bhead->bhead;
805 new_bhead_data->file_offset = new_bhead->file_offset;
806 new_bhead_data->has_data = true;
807 new_bhead_data->is_memchunk_identical = false;
808 if (!blo_bhead_read_data(fd, thisblock, new_bhead_data + 1)) {
809 MEM_freeN(new_bhead_data);
810 return nullptr;
811 }
812 return &new_bhead_data->bhead;
813}
814#endif /* USE_BHEAD_READ_ON_DEMAND */
815
816const char *blo_bhead_id_name(FileData *fd, const BHead *bhead)
817{
818 const char *id_name = reinterpret_cast<const char *>(
819 POINTER_OFFSET(bhead, sizeof(*bhead) + fd->id_name_offset));
820 if (std::memchr(id_name, '\0', MAX_ID_NAME)) {
821 return id_name;
822 }
823
824 /* ID name longer than MAX_ID_NAME - 1, or otherwise corrupted. */
826 return nullptr;
827}
828
830{
832 return (fd->id_asset_data_offset >= 0) ?
833 *(AssetMetaData **)POINTER_OFFSET(bhead, sizeof(*bhead) + fd->id_asset_data_offset) :
834 nullptr;
835}
836
838{
840 if (std::holds_alternative<BlenderHeaderInvalid>(header_variant)) {
841 return;
842 }
843 if (std::holds_alternative<BlenderHeaderUnknown>(header_variant)) {
845 return;
846 }
847 const BlenderHeader &header = std::get<BlenderHeader>(header_variant);
848 fd->flags |= FD_FLAGS_FILE_OK;
849 if (header.pointer_size == 4) {
851 }
852 if (header.pointer_size != sizeof(void *)) {
854 }
855 if (header.endian != ENDIAN_ORDER) {
857 }
858 fd->fileversion = header.file_version;
859 fd->blender_header = header;
860}
861
865static bool read_file_dna(FileData *fd, const char **r_error_message)
866{
867 BHead *bhead;
868 int subversion = 0;
869
870 for (bhead = blo_bhead_first(fd); bhead; bhead = blo_bhead_next(fd, bhead)) {
871 if (bhead->code == BLO_CODE_GLOB) {
872 /* Before this, the subversion didn't exist in 'FileGlobal' so the subversion
873 * value isn't accessible for the purpose of DNA versioning in this case. */
874 if (fd->fileversion <= 242) {
875 continue;
876 }
877 /* We can't use read_global because this needs 'DNA1' to be decoded,
878 * however the first 4 chars are _always_ the subversion. */
879 const FileGlobal *fg = reinterpret_cast<const FileGlobal *>(&bhead[1]);
880 BLI_STATIC_ASSERT(offsetof(FileGlobal, subvstr) == 0, "Must be first: subvstr")
881 char num[5];
882 memcpy(num, fg->subvstr, 4);
883 num[4] = 0;
884 subversion = atoi(num);
885 }
886 else if (bhead->code == BLO_CODE_DNA1) {
887 const bool do_endian_swap = (fd->flags & FD_FLAGS_SWITCH_ENDIAN) != 0;
888 const bool do_alias = false; /* Postpone until after #blo_do_versions_dna runs. */
890 &bhead[1], bhead->len, do_endian_swap, true, do_alias, r_error_message);
891 if (fd->filesdna) {
892 blo_do_versions_dna(fd->filesdna, fd->fileversion, subversion);
893 /* Allow aliased lookups (must be after version patching DNA). */
895
898 fd->filesdna, fd->memsdna, fd->compflags);
899 /* used to retrieve ID names from (bhead+1) */
901 fd->filesdna, "ID", "char", "name[]");
902 BLI_assert(fd->id_name_offset != -1);
904 fd->filesdna, "ID", "AssetMetaData", "*asset_data");
905
906 return true;
907 }
908
909 return false;
910 }
911 else if (bhead->code == BLO_CODE_ENDB) {
912 break;
913 }
914 }
915
916 *r_error_message = "Missing DNA block";
917 return false;
918}
919
921{
922 BHead *bhead;
923 int *blend_thumb = nullptr;
924
925 for (bhead = blo_bhead_first(fd); bhead; bhead = blo_bhead_next(fd, bhead)) {
926 if (bhead->code == BLO_CODE_TEST) {
927 const bool do_endian_swap = (fd->flags & FD_FLAGS_SWITCH_ENDIAN) != 0;
928 int *data = (int *)(bhead + 1);
929
930 if (bhead->len < sizeof(int[2])) {
931 break;
932 }
933
934 if (do_endian_swap) {
937 }
938
939 const int width = data[0];
940 const int height = data[1];
941 if (!BLEN_THUMB_MEMSIZE_IS_VALID(width, height)) {
942 break;
943 }
944 if (bhead->len < BLEN_THUMB_MEMSIZE_FILE(width, height)) {
945 break;
946 }
947
948 blend_thumb = data;
949 break;
950 }
951 if (bhead->code != BLO_CODE_REND) {
952 /* Thumbnail is stored in TEST immediately after first REND... */
953 break;
954 }
955 }
956
957 return blend_thumb;
958}
959
972{
973 ListBase *lb_iter;
974 /* Using a set is needed, to avoid renaming names when there is no collision, and deal with IDs
975 * being moved around in their list when renamed. A simple set is enough, since here only local
976 * IDs are processed. */
978 blender::Set<ID *> processed_ids;
979
980 FOREACH_MAIN_LISTBASE_BEGIN (bmain, lb_iter) {
981 LISTBASE_FOREACH_MUTABLE (ID *, id_iter, lb_iter) {
982 if (processed_ids.contains(id_iter)) {
983 continue;
984 }
985 processed_ids.add_new(id_iter);
986 /* Linked IDs can be fully ignored here, 'long names' IDs cannot be linked in any way. */
987 if (ID_IS_LINKED(id_iter)) {
988 continue;
989 }
990 if (!used_names.contains(id_iter->name)) {
991 used_names.add_new(id_iter->name);
992 continue;
993 }
994
996 *bmain, *lb_iter, *id_iter, nullptr, IDNewNameMode::RenameExistingNever, false);
997 BLI_assert(!used_names.contains(id_iter->name));
998 used_names.add_new(id_iter->name);
999 CLOG_INFO(&LOG, 3, "ID name has been de-duplicated to '%s'", id_iter->name);
1000 }
1001 }
1003}
1004
1014{
1015 /* NOTE: A large part of this code follows a similar logic to
1016 * #foreach_action_slot_use_with_references.
1017 *
1018 * However, no slot identifier should ever be skipped here, even if it is not in use in any way,
1019 * since it is critical to remove all non-null terminated strings.
1020 */
1021
1022 ID *id_iter;
1023 FOREACH_MAIN_ID_BEGIN (bmain, id_iter) {
1024 switch (GS(id_iter->name)) {
1025 case ID_AC: {
1026 bool has_truncated_slot_identifer = false;
1027 bAction *act = reinterpret_cast<bAction *>(id_iter);
1028 for (int i = 0; i < act->slot_array_num; i++) {
1030 CLOG_INFO(&LOG,
1031 4,
1032 "Truncated too long action slot name to '%s'",
1033 act->slot_array[i]->identifier);
1034 has_truncated_slot_identifer = true;
1035 }
1036 }
1037 if (!has_truncated_slot_identifer) {
1038 continue;
1039 }
1040
1041 /* If there are truncated slots identifiers, ensuring their uniqueness must happen in a
1042 * second loop, to avoid e.g. an attempt to read a slot identifier that has not yet been
1043 * truncated. */
1044 for (int i = 0; i < act->slot_array_num; i++) {
1046 [&](const blender::StringRef name) -> bool {
1047 for (int j = 0; j < act->slot_array_num; j++) {
1048 if (i == j) {
1049 continue;
1050 }
1051 if (act->slot_array[j]->identifier == name) {
1052 return true;
1053 }
1054 }
1055 return false;
1056 },
1057 "",
1058 '.',
1059 act->slot_array[i]->identifier,
1060 sizeof(act->slot_array[i]->identifier));
1061 }
1062 break;
1063 }
1064 case ID_OB: {
1065 auto visit_constraint = [](const bConstraint &constraint) -> bool {
1066 if (constraint.type != CONSTRAINT_TYPE_ACTION) {
1067 return true;
1068 }
1069 bActionConstraint *constraint_data = static_cast<bActionConstraint *>(constraint.data);
1071 CLOG_INFO(&LOG,
1072 4,
1073 "Truncated too long bActionConstraint.last_slot_identifier to '%s'",
1074 constraint_data->last_slot_identifier);
1075 }
1076 return true;
1077 };
1078
1079 Object *object = reinterpret_cast<Object *>(id_iter);
1080 LISTBASE_FOREACH (bConstraint *, con, &object->constraints) {
1081 visit_constraint(*con);
1082 }
1083 if (object->pose) {
1084 LISTBASE_FOREACH (bPoseChannel *, pchan, &object->pose->chanbase) {
1085 LISTBASE_FOREACH (bConstraint *, con, &pchan->constraints) {
1086 visit_constraint(*con);
1087 }
1088 }
1089 }
1090 }
1092 default: {
1093 AnimData *anim_data = BKE_animdata_from_id(id_iter);
1094 if (anim_data) {
1096 CLOG_INFO(&LOG,
1097 4,
1098 "Truncated too long AnimData.last_slot_identifier to '%s'",
1099 anim_data->last_slot_identifier);
1100 }
1102 CLOG_INFO(&LOG,
1103 4,
1104 "Truncated too long AnimData.tmp_last_slot_identifier to '%s'",
1105 anim_data->tmp_last_slot_identifier);
1106 }
1107
1108 blender::bke::nla::foreach_strip_adt(*anim_data, [&](NlaStrip *strip) -> bool {
1110 CLOG_INFO(&LOG,
1111 4,
1112 "Truncated too long NlaStrip.last_slot_identifier to '%s'",
1113 strip->last_slot_identifier);
1114 }
1115
1116 return true;
1117 });
1118 }
1119 }
1120 }
1122 }
1123}
1124
1126
1127/* -------------------------------------------------------------------- */
1130
1132{
1133 BLI_assert(reports != nullptr);
1134
1135 FileData *fd = MEM_new<FileData>(__func__);
1136
1138
1139 fd->datamap = oldnewmap_new();
1140 fd->globmap = oldnewmap_new();
1141 fd->libmap = oldnewmap_new();
1142
1143 fd->reports = reports;
1144
1145 return fd;
1146}
1147
1154{
1155 BLI_assert(fd->filesdna != nullptr);
1156 for (BHead *bhead = blo_bhead_first(fd); bhead; bhead = blo_bhead_next(fd, bhead)) {
1157 if (bhead->code != BLO_CODE_GLOB) {
1158 continue;
1159 }
1160
1161 FileGlobal *fg = static_cast<FileGlobal *>(
1162 read_struct(fd, bhead, "Data from Global block", INDEX_ID_NULL));
1163 if ((fg->minversion > BLENDER_FILE_VERSION) ||
1165 {
1166 char writer_ver_str[16];
1167 char min_reader_ver_str[16];
1168 if (fd->fileversion == fg->minversion) {
1170 writer_ver_str, sizeof(writer_ver_str), short(fd->fileversion), fg->subversion);
1172 min_reader_ver_str, sizeof(min_reader_ver_str), fg->minversion, fg->minsubversion);
1173 }
1174 else {
1176 writer_ver_str, sizeof(writer_ver_str), short(fd->fileversion), -1);
1178 min_reader_ver_str, sizeof(min_reader_ver_str), fg->minversion, -1);
1179 }
1181 RPT_ERROR,
1182 "The file was saved by a newer version, open it with Blender %s or later",
1183 min_reader_ver_str);
1184 CLOG_WARN(&LOG,
1185 "%s: File saved by a newer version of Blender (%s), Blender %s or later is "
1186 "needed to open it.",
1187 fd->relabase,
1188 writer_ver_str,
1189 min_reader_ver_str);
1190 MEM_freeN(fg);
1191 return true;
1192 }
1193 MEM_freeN(fg);
1194 return false;
1195 }
1196 return false;
1197}
1198
1200{
1202
1203 if (fd->flags & FD_FLAGS_FILE_OK) {
1204 const char *error_message = nullptr;
1205 if (read_file_dna(fd, &error_message) == false) {
1207 reports, RPT_ERROR, "Failed to read blend file '%s': %s", fd->relabase, error_message);
1209 fd = nullptr;
1210 }
1213 fd = nullptr;
1214 }
1215 else if (fd->flags & FD_FLAGS_SWITCH_ENDIAN) {
1216 if (ENDIAN_ORDER == L_ENDIAN) {
1218 CLOG_WARN(
1219 &LOG,
1220 "Blend file '%s' created by a Big Endian version of Blender, support for these "
1221 "files will be removed in Blender 5.0",
1222 fd->relabase);
1223 }
1226 "Blend file '%s' created by a Big Endian version of Blender, support for "
1227 "these files will be removed in Blender 5.0",
1228 fd->relabase);
1229 }
1230 }
1231 }
1232 else if (fd->flags & FD_FLAGS_FILE_FUTURE) {
1234 reports,
1235 RPT_ERROR,
1236 "Cannot read blend file '%s', incomplete header, may be from a newer version of Blender",
1237 fd->relabase);
1239 fd = nullptr;
1240 }
1241 else {
1242 BKE_reportf(reports, RPT_ERROR, "Failed to read file '%s', not a blend file", fd->relabase);
1244 fd = nullptr;
1245 }
1246
1247 return fd;
1248}
1249
1250static FileData *blo_filedata_from_file_descriptor(const char *filepath,
1252 const int filedes)
1253{
1254 char header[7];
1255 FileReader *rawfile = BLI_filereader_new_file(filedes);
1256 FileReader *file = nullptr;
1257
1258 errno = 0;
1259 /* If opening the file failed or we can't read the header, give up. */
1260 if (rawfile == nullptr || rawfile->read(rawfile, header, sizeof(header)) != sizeof(header)) {
1261 BKE_reportf(reports->reports,
1263 "Unable to read '%s': %s",
1264 filepath,
1265 errno ? strerror(errno) : RPT_("insufficient content"));
1266 if (rawfile) {
1267 rawfile->close(rawfile);
1268 }
1269 else {
1270 close(filedes);
1271 }
1272 return nullptr;
1273 }
1274
1275 /* Rewind the file after reading the header. */
1276 rawfile->seek(rawfile, 0, SEEK_SET);
1277
1278 /* Check if we have a regular file. */
1279 if (memcmp(header, "BLENDER", sizeof(header)) == 0) {
1280 /* Try opening the file with memory-mapped IO. */
1281 file = BLI_filereader_new_mmap(filedes);
1282 if (file == nullptr) {
1283 /* `mmap` failed, so just keep using `rawfile`. */
1284 file = rawfile;
1285 rawfile = nullptr;
1286 }
1287 }
1288 else if (BLI_file_magic_is_gzip(header)) {
1289 file = BLI_filereader_new_gzip(rawfile);
1290 if (file != nullptr) {
1291 rawfile = nullptr; /* The `Gzip` #FileReader takes ownership of `rawfile`. */
1292 }
1293 }
1294 else if (BLI_file_magic_is_zstd(header)) {
1295 file = BLI_filereader_new_zstd(rawfile);
1296 if (file != nullptr) {
1297 rawfile = nullptr; /* The `Zstd` #FileReader takes ownership of `rawfile`. */
1298 }
1299 }
1300
1301 /* Clean up `rawfile` if it wasn't taken over. */
1302 if (rawfile != nullptr) {
1303 rawfile->close(rawfile);
1304 }
1305 if (file == nullptr) {
1306 BKE_reportf(reports->reports, RPT_WARNING, "Unrecognized file format '%s'", filepath);
1307 return nullptr;
1308 }
1309
1311 fd->file = file;
1312
1313 return fd;
1314}
1315
1317{
1318 errno = 0;
1319 const int file = BLI_open(filepath, O_BINARY | O_RDONLY, 0);
1320 if (file == -1) {
1321 BKE_reportf(reports->reports,
1323 "Unable to open '%s': %s",
1324 filepath,
1325 errno ? strerror(errno) : RPT_("unknown error reading file"));
1326 return nullptr;
1327 }
1328 return blo_filedata_from_file_descriptor(filepath, reports, file);
1329}
1330
1332{
1334 if (fd != nullptr) {
1335 /* needed for library_append and read_libraries */
1336 STRNCPY(fd->relabase, filepath);
1337
1338 return blo_decode_and_check(fd, reports->reports);
1339 }
1340 return nullptr;
1341}
1342
1347static FileData *blo_filedata_from_file_minimal(const char *filepath)
1348{
1349 BlendFileReadReport read_report{};
1350 FileData *fd = blo_filedata_from_file_open(filepath, &read_report);
1351 if (fd != nullptr) {
1353 if (fd->flags & FD_FLAGS_FILE_OK) {
1354 return fd;
1355 }
1357 }
1358 return nullptr;
1359}
1360
1362 const int memsize,
1364{
1365 if (!mem || memsize < MIN_SIZEOFBLENDERHEADER) {
1366 BKE_report(
1367 reports->reports, RPT_WARNING, (mem) ? RPT_("Unable to read") : RPT_("Unable to open"));
1368 return nullptr;
1369 }
1370
1371 FileReader *mem_file = BLI_filereader_new_memory(mem, memsize);
1372 FileReader *file = mem_file;
1373
1374 if (BLI_file_magic_is_gzip(static_cast<const char *>(mem))) {
1375 file = BLI_filereader_new_gzip(mem_file);
1376 }
1377 else if (BLI_file_magic_is_zstd(static_cast<const char *>(mem))) {
1378 file = BLI_filereader_new_zstd(mem_file);
1379 }
1380
1381 if (file == nullptr) {
1382 /* Compression initialization failed. */
1383 mem_file->close(mem_file);
1384 return nullptr;
1385 }
1386
1388 fd->file = file;
1389
1390 return blo_decode_and_check(fd, reports->reports);
1391}
1392
1396{
1397 if (!memfile) {
1398 BKE_report(reports->reports, RPT_WARNING, "Unable to open blend <memory>");
1399 return nullptr;
1400 }
1401
1403 fd->file = BLO_memfile_new_filereader(memfile, params->undo_direction);
1404 fd->undo_direction = params->undo_direction;
1406
1407 return blo_decode_and_check(fd, reports->reports);
1408}
1409
1411{
1412 /* Free all BHeadN data blocks */
1413#ifdef NDEBUG
1415#else
1416 /* Sanity check we're not keeping memory we don't need. */
1417 LISTBASE_FOREACH_MUTABLE (BHeadN *, new_bhead, &fd->bhead_list) {
1418# ifdef USE_BHEAD_READ_ON_DEMAND
1419 if (fd->file->seek != nullptr && BHEAD_USE_READ_ON_DEMAND(&new_bhead->bhead)) {
1420 BLI_assert(new_bhead->has_data == 0);
1421 }
1422# endif
1423 MEM_freeN(new_bhead);
1424 }
1425#endif
1426 fd->file->close(fd->file);
1427
1428 if (fd->filesdna) {
1430 }
1431 if (fd->compflags) {
1432 MEM_freeN(fd->compflags);
1433 }
1434 if (fd->reconstruct_info) {
1436 }
1437
1438 if (fd->datamap) {
1440 }
1441 if (fd->globmap) {
1443 }
1444 if (fd->libmap) {
1446 }
1447 if (fd->old_idmap_uid != nullptr) {
1449 }
1450 if (fd->new_idmap_uid != nullptr) {
1452 }
1454 if (fd->bheadmap) {
1455 MEM_freeN(fd->bheadmap);
1456 }
1457
1458 MEM_delete(fd);
1459}
1460
1462
1463/* -------------------------------------------------------------------- */
1466
1468{
1469 BlendThumbnail *data = nullptr;
1470
1472 if (fd) {
1473 if (const int *fd_data = read_file_thumbnail(fd)) {
1474 const int width = fd_data[0];
1475 const int height = fd_data[1];
1476 if (BLEN_THUMB_MEMSIZE_IS_VALID(width, height)) {
1477 const size_t data_size = BLEN_THUMB_MEMSIZE(width, height);
1478 data = static_cast<BlendThumbnail *>(MEM_mallocN(data_size, __func__));
1479 if (data) {
1480 BLI_assert((data_size - sizeof(*data)) ==
1481 (BLEN_THUMB_MEMSIZE_FILE(width, height) - (sizeof(*fd_data) * 2)));
1482 data->width = width;
1483 data->height = height;
1484 memcpy(data->rect, &fd_data[2], data_size - sizeof(*data));
1485 }
1486 }
1487 }
1489 }
1490
1491 return data;
1492}
1493
1494short BLO_version_from_file(const char *filepath)
1495{
1496 short version = 0;
1498 if (fd) {
1499 version = fd->fileversion;
1501 }
1502 return version;
1503}
1504
1506
1507/* -------------------------------------------------------------------- */
1510
1511/* Only direct data-blocks. */
1512static void *newdataadr(FileData *fd, const void *adr)
1513{
1514 return oldnewmap_lookup_and_inc(fd->datamap, adr, true);
1515}
1516
1517/* Only direct data-blocks. */
1518static void *newdataadr_no_us(FileData *fd, const void *adr)
1519{
1520 return oldnewmap_lookup_and_inc(fd->datamap, adr, false);
1521}
1522
1524{
1525 return oldnewmap_lookup_and_inc(fd->globmap, adr, true);
1526}
1527
1528/* only lib data */
1529static void *newlibadr(FileData *fd, ID * /*self_id*/, const bool is_linked_only, const void *adr)
1530{
1531 return oldnewmap_liblookup(fd->libmap, adr, is_linked_only);
1532}
1533
1535 ID *self_id,
1536 const bool is_linked_only,
1537 const void *adr)
1538{
1539 return newlibadr(fd, self_id, is_linked_only, adr);
1540}
1541
1542/* increases user number */
1544 const void *old,
1545 void *newp)
1546{
1547 for (NewAddress &entry : fd->libmap->map.values()) {
1548 if (old == entry.newp && entry.nr == ID_LINK_PLACEHOLDER) {
1549 entry.newp = newp;
1550 if (newp) {
1551 entry.nr = GS(((ID *)newp)->name);
1552 }
1553 }
1554 }
1555}
1556
1557/* Very rarely needed, allows some form of ID remapping as part of readfile process.
1558 *
1559 * Currently only used to remap duplicate library pointers.
1560 */
1561static void change_ID_pointer_to_real_ID_pointer_fd(FileData *fd, const void *old, void *newp)
1562{
1563 for (NewAddress &entry : fd->libmap->map.values()) {
1564 if (old == entry.newp) {
1565 BLI_assert(BKE_idtype_idcode_is_valid(short(entry.nr)));
1566 entry.newp = newp;
1567 if (newp) {
1568 entry.nr = GS(((ID *)newp)->name);
1569 }
1570 }
1571 }
1572}
1573
1575{
1576 if (bmain->curlib) {
1577 return bmain->curlib->runtime->filedata;
1578 }
1579 else {
1580 return basefd;
1581 }
1582}
1583
1585 FileData *basefd,
1586 void *old,
1587 void *newp)
1588{
1589 LISTBASE_FOREACH (Main *, mainptr, mainlist) {
1590 FileData *fd = change_ID_link_filedata_get(mainptr, basefd);
1591 if (fd) {
1593 }
1594 }
1595}
1596
1598 FileData *basefd,
1599 void *old,
1600 void *newp)
1601{
1602 LISTBASE_FOREACH (Main *, mainptr, mainlist) {
1603 FileData *fd = change_ID_link_filedata_get(mainptr, basefd);
1604 if (fd) {
1606 }
1607 }
1608}
1609
1611{
1612 if (fd->old_idmap_uid != nullptr) {
1614 }
1615 fd->old_idmap_uid = BKE_main_idmap_create(bmain, false, nullptr, MAIN_IDMAP_TYPE_UID);
1616}
1617
1622
1627
1630 ID *id, const IDCacheKey *key, void **cache_p, uint /*flags*/, void *cache_storage_v)
1631{
1634
1635 BLOCacheStorage *cache_storage = static_cast<BLOCacheStorage *>(cache_storage_v);
1636 BLI_assert(!BLI_ghash_haskey(cache_storage->cache_map, key));
1637
1638 IDCacheKey *storage_key = static_cast<IDCacheKey *>(
1639 BLI_memarena_alloc(cache_storage->memarena, sizeof(*storage_key)));
1640 *storage_key = *key;
1641 BLOCacheStorageValue *storage_value = static_cast<BLOCacheStorageValue *>(
1642 BLI_memarena_alloc(cache_storage->memarena, sizeof(*storage_value)));
1643 storage_value->cache_v = *cache_p;
1644 storage_value->new_usage_count = 0;
1645 BLI_ghash_insert(cache_storage->cache_map, storage_key, storage_value);
1646}
1647
1650 ID *id, const IDCacheKey *key, void **cache_p, const uint flags, void *cache_storage_v)
1651{
1652 BLOCacheStorage *cache_storage = static_cast<BLOCacheStorage *>(cache_storage_v);
1653
1654 if (cache_storage == nullptr) {
1655 /* In non-undo case, only clear the pointer if it is a purely runtime one.
1656 * If it may be stored in a persistent way in the .blend file, direct_link code is responsible
1657 * to properly deal with it. */
1658 if ((flags & IDTYPE_CACHE_CB_FLAGS_PERSISTENT) == 0) {
1659 *cache_p = nullptr;
1660 }
1661 return;
1662 }
1663
1664 /* Assume that when ID source is tagged as changed, its caches need to be cleared.
1665 * NOTE: This is mainly a work-around for some IDs, like Image, which use a non-depsgraph-handled
1666 * process for part of their updates.
1667 */
1668 if (id->recalc & ID_RECALC_SOURCE) {
1669 *cache_p = nullptr;
1670 return;
1671 }
1672
1673 BLOCacheStorageValue *storage_value = static_cast<BLOCacheStorageValue *>(
1674 BLI_ghash_lookup(cache_storage->cache_map, key));
1675 if (storage_value == nullptr) {
1676 *cache_p = nullptr;
1677 return;
1678 }
1679 storage_value->new_usage_count++;
1680 *cache_p = storage_value->cache_v;
1681}
1682
1685 const IDCacheKey *key,
1686 void **cache_p,
1687 const uint /*flags*/,
1688 void *cache_storage_v)
1689{
1690 BLOCacheStorage *cache_storage = static_cast<BLOCacheStorage *>(cache_storage_v);
1691
1692 BLOCacheStorageValue *storage_value = static_cast<BLOCacheStorageValue *>(
1693 BLI_ghash_lookup(cache_storage->cache_map, key));
1694 if (storage_value == nullptr) {
1695 *cache_p = nullptr;
1696 return;
1697 }
1698 /* If that cache has been restored into some new ID, we want to remove it from old one, otherwise
1699 * keep it there so that it gets properly freed together with its ID. */
1700 if (storage_value->new_usage_count != 0) {
1701 *cache_p = nullptr;
1702 }
1703 else {
1704 BLI_assert(*cache_p == storage_value->cache_v);
1705 }
1706}
1707
1709{
1710 if (fd->flags & FD_FLAGS_IS_MEMFILE) {
1711 BLI_assert(fd->cache_storage == nullptr);
1716
1717 ListBase *lb;
1718 FOREACH_MAIN_LISTBASE_BEGIN (bmain, lb) {
1719 ID *id = static_cast<ID *>(lb->first);
1720 if (id == nullptr) {
1721 continue;
1722 }
1723
1724 const IDTypeInfo *type_info = BKE_idtype_get_info_from_id(id);
1725 if (type_info->foreach_cache == nullptr) {
1726 continue;
1727 }
1728
1730 if (ID_IS_LINKED(id)) {
1731 continue;
1732 }
1734 }
1736 }
1738 }
1739 else {
1740 fd->cache_storage = nullptr;
1741 }
1742}
1743
1745{
1746 if (fd->cache_storage != nullptr) {
1747 ListBase *lb;
1748 FOREACH_MAIN_LISTBASE_BEGIN (bmain_old, lb) {
1749 ID *id = static_cast<ID *>(lb->first);
1750 if (id == nullptr) {
1751 continue;
1752 }
1753
1754 const IDTypeInfo *type_info = BKE_idtype_get_info_from_id(id);
1755 if (type_info->foreach_cache == nullptr) {
1756 continue;
1757 }
1758
1760 if (ID_IS_LINKED(id)) {
1761 continue;
1762 }
1764 }
1766 }
1768 }
1769}
1770
1772{
1773 if (fd->cache_storage != nullptr) {
1774 BLI_ghash_free(fd->cache_storage->cache_map, nullptr, nullptr);
1777 fd->cache_storage = nullptr;
1778 }
1779}
1780
1782
1783/* -------------------------------------------------------------------- */
1786
1787static void switch_endian_structs(const SDNA *filesdna, BHead *bhead)
1788{
1789 int blocksize, nblocks;
1790 char *data;
1791
1792 data = (char *)(bhead + 1);
1793
1794 blocksize = DNA_struct_size(filesdna, bhead->SDNAnr);
1795
1796 nblocks = bhead->nr;
1797 while (nblocks--) {
1798 DNA_struct_switch_endian(filesdna, bhead->SDNAnr, data);
1799
1800 data += blocksize;
1801 }
1802}
1803
1810static const char *get_alloc_name(FileData *fd,
1811 BHead *bh,
1812 const char *blockname,
1813 const int id_type_index = INDEX_ID_NULL)
1814{
1815#ifndef NDEBUG
1816 /* Storage key is a pair of (string , int), where the first is the concatenation of the 'owner
1817 * block' string and DNA struct type name, and the second the length of the array, as defined by
1818 * the #BHead.nr value. */
1819 using keyT = const std::pair<const std::string, const int>;
1820#else
1821 /* Storage key is simple int, which is the ID type index. */
1822 using keyT = int;
1823#endif
1824 constexpr std::string_view STORAGE_ID = "readfile";
1825
1826 /* NOTE: This is thread_local storage, so as long as the handling of a same FileData is not
1827 * spread across threads (which is not supported at all currently), this is thread-safe. */
1828 if (!fd->storage_handle) {
1830 std::string(STORAGE_ID));
1831 }
1834 fd->storage_handle);
1835
1836 const bool is_id_data = !blockname && (id_type_index >= 0 && id_type_index < INDEX_ID_MAX);
1837
1838#ifndef NDEBUG
1839 /* Local storage of id type names, for fast access to this info. */
1840 static const std::array<std::string, INDEX_ID_MAX> id_alloc_names = [] {
1841 auto n = decltype(id_alloc_names)();
1842 for (int idtype_index = 0; idtype_index < INDEX_ID_MAX; idtype_index++) {
1843 const IDTypeInfo *idtype_info = BKE_idtype_get_info_from_idtype_index(idtype_index);
1844 BLI_assert(idtype_info);
1845 if (idtype_index == INDEX_ID_NULL) {
1846 /* #INDEX_ID_NULL returns the #IDType_ID_LINK_PLACEHOLDER type info, here we will rather
1847 * use it for unknown/invalid ID types. */
1848 n[size_t(idtype_index)] = "UNKNWOWN";
1849 }
1850 else {
1851 n[size_t(idtype_index)] = idtype_info->name;
1852 }
1853 }
1854 return n;
1855 }();
1856
1857 const std::string block_alloc_name = is_id_data ? id_alloc_names[id_type_index] : blockname;
1858 const std::string struct_name = DNA_struct_identifier(fd->filesdna, bh->SDNAnr);
1859 keyT key{block_alloc_name + struct_name, bh->nr};
1860 if (!storage.contains(key)) {
1861 const std::string alloc_string = fmt::format(
1862 fmt::runtime((is_id_data ? "{}{} (for ID type '{}')" : "{}{} (for block '{}')")),
1863 struct_name,
1864 bh->nr > 1 ? fmt::format("[{}]", bh->nr) : "",
1865 block_alloc_name);
1866 return storage.insert(key, alloc_string);
1867 }
1868 return storage.find(key);
1869#else
1870 /* Simple storage for pure release builds, using integer as key, one entry for each ID type. */
1872 if (is_id_data) {
1873 if (UNLIKELY(!storage.contains(id_type_index))) {
1874 if (id_type_index == INDEX_ID_NULL) {
1875 return storage.insert(id_type_index, "Data from UNKNOWN");
1876 }
1877 const IDTypeInfo *id_type = BKE_idtype_get_info_from_idtype_index(id_type_index);
1878 const std::string alloc_string = fmt::format("Data from '{}' ID type", id_type->name);
1879 return storage.insert(id_type_index, alloc_string);
1880 }
1881 return storage.find(id_type_index);
1882 }
1883 return blockname;
1884#endif
1885}
1886
1887static void *read_struct(FileData *fd, BHead *bh, const char *blockname, const int id_type_index)
1888{
1889 void *temp = nullptr;
1890
1891 if (bh->len) {
1892#ifdef USE_BHEAD_READ_ON_DEMAND
1893 BHead *bh_orig = bh;
1894#endif
1895
1896 /* Endianness switch is based on file DNA.
1897 *
1898 * NOTE: raw data (aka #SDNA_RAW_DATA_STRUCT_INDEX #SDNAnr) is not handled here, it's up to
1899 * the calling code to manage this. */
1900 BLI_STATIC_ASSERT(SDNA_RAW_DATA_STRUCT_INDEX == 0, "'raw data' SDNA struct index should be 0")
1902#ifdef USE_BHEAD_READ_ON_DEMAND
1903 if (BHEADN_FROM_BHEAD(bh)->has_data == false) {
1904 bh = blo_bhead_read_full(fd, bh);
1905 if (UNLIKELY(bh == nullptr)) {
1906 fd->flags &= ~FD_FLAGS_FILE_OK;
1907 return nullptr;
1908 }
1909 }
1910#endif
1912 }
1913
1914 if (fd->compflags[bh->SDNAnr] != SDNA_CMP_REMOVED) {
1915 const char *alloc_name = get_alloc_name(fd, bh, blockname, id_type_index);
1916 if (fd->compflags[bh->SDNAnr] == SDNA_CMP_NOT_EQUAL) {
1917#ifdef USE_BHEAD_READ_ON_DEMAND
1918 if (BHEADN_FROM_BHEAD(bh)->has_data == false) {
1919 bh = blo_bhead_read_full(fd, bh);
1920 if (UNLIKELY(bh == nullptr)) {
1921 fd->flags &= ~FD_FLAGS_FILE_OK;
1922 return nullptr;
1923 }
1924 }
1925#endif
1927 fd->reconstruct_info, bh->SDNAnr, bh->nr, (bh + 1), alloc_name);
1928 }
1929 else {
1930 /* SDNA_CMP_EQUAL */
1931 const int alignment = DNA_struct_alignment(fd->filesdna, bh->SDNAnr);
1932 temp = MEM_mallocN_aligned(bh->len, alignment, alloc_name);
1933#ifdef USE_BHEAD_READ_ON_DEMAND
1934 if (BHEADN_FROM_BHEAD(bh)->has_data) {
1935 memcpy(temp, (bh + 1), bh->len);
1936 }
1937 else {
1938 /* Instead of allocating the bhead, then copying it,
1939 * read the data from the file directly into the memory. */
1940 if (UNLIKELY(!blo_bhead_read_data(fd, bh, temp))) {
1941 fd->flags &= ~FD_FLAGS_FILE_OK;
1942 MEM_freeN(temp);
1943 temp = nullptr;
1944 }
1945 }
1946#else
1947 memcpy(temp, (bh + 1), bh->len);
1948#endif
1949 }
1950 }
1951
1952#ifdef USE_BHEAD_READ_ON_DEMAND
1953 if (bh_orig != bh) {
1955 }
1956#endif
1957 }
1958
1959 return temp;
1960}
1961
1962static ID *read_id_struct(FileData *fd, BHead *bh, const char *blockname, const int id_type_index)
1963{
1964 ID *id = static_cast<ID *>(read_struct(fd, bh, blockname, id_type_index));
1965 if (!id) {
1966 return id;
1967 }
1968
1969 /* Invalid ID name (probably from 'too long' ID name from a future Blender version).
1970 *
1971 * They can only be truncated here, ensuring that all ID names remain unique happens later, after
1972 * reading all local IDs, but before linking them, see the call to
1973 * #long_id_names_ensure_unique_id_names in #blo_read_file_internal. */
1976 CLOG_INFO(&LOG, 3, "Truncated too long ID name to '%s'", id->name);
1977 }
1978
1979 return id;
1980}
1981
1982/* Like read_struct, but gets a pointer without allocating. Only works for
1983 * undo since DNA must match. */
1984static const void *peek_struct_undo(FileData *fd, BHead *bhead)
1985{
1988 return (bhead->len) ? (const void *)(bhead + 1) : nullptr;
1989}
1990
1991static void link_glob_list(FileData *fd, ListBase *lb) /* for glob data */
1992{
1993 Link *ln, *prev;
1994 void *poin;
1995
1996 if (BLI_listbase_is_empty(lb)) {
1997 return;
1998 }
1999 poin = newdataadr(fd, lb->first);
2000 if (lb->first) {
2001 oldnewmap_insert(fd->globmap, lb->first, poin, 0);
2002 }
2003 lb->first = poin;
2004
2005 ln = static_cast<Link *>(lb->first);
2006 prev = nullptr;
2007 while (ln) {
2008 poin = newdataadr(fd, ln->next);
2009 if (ln->next) {
2010 oldnewmap_insert(fd->globmap, ln->next, poin, 0);
2011 }
2012 ln->next = static_cast<Link *>(poin);
2013 ln->prev = prev;
2014 prev = ln;
2015 ln = ln->next;
2016 }
2017 lb->last = prev;
2018}
2019
2021
2022/* -------------------------------------------------------------------- */
2025
2026static void after_liblink_id_process(BlendLibReader *reader, ID *id);
2027
2029{
2030
2031 /* Handle 'private IDs'. */
2033 if (nodetree != nullptr) {
2034 after_liblink_id_process(reader, &nodetree->id);
2035
2036 if (nodetree->owner_id == nullptr) {
2037 CLOG_WARN(&LOG,
2038 "NULL owner_id pointer for embedded NodeTree of %s, should never happen",
2039 id->name);
2040 nodetree->owner_id = id;
2041 }
2042 else if (nodetree->owner_id != id) {
2043 CLOG_WARN(&LOG,
2044 "Inconsistent owner_id pointer for embedded NodeTree of %s, should never happen",
2045 id->name);
2046 nodetree->owner_id = id;
2047 }
2048 }
2049
2050 if (GS(id->name) == ID_SCE) {
2051 Scene *scene = (Scene *)id;
2052 if (scene->master_collection != nullptr) {
2054
2055 if (scene->master_collection->owner_id == nullptr) {
2056 CLOG_WARN(&LOG,
2057 "NULL owner_id pointer for embedded Scene Collection of %s, should never happen",
2058 id->name);
2059 scene->master_collection->owner_id = id;
2060 }
2061 else if (scene->master_collection->owner_id != id) {
2062 CLOG_WARN(&LOG,
2063 "Inconsistent owner_id pointer for embedded Scene Collection of %s, should "
2064 "never happen",
2065 id->name);
2066 scene->master_collection->owner_id = id;
2067 }
2068 }
2069 }
2070}
2071
2073{
2074 /* NOTE: WM IDProperties are never written to file, hence they should always be nullptr here. */
2075 BLI_assert((GS(id->name) != ID_WM) || id->properties == nullptr);
2076
2078
2079 const IDTypeInfo *id_type = BKE_idtype_get_info_from_id(id);
2080 if (id_type->blend_read_after_liblink != nullptr) {
2081 id_type->blend_read_after_liblink(reader, id);
2082 }
2083}
2084
2087{
2088 BLO_read_string(reader, &op->rna_path);
2089
2090 op->tag = 0; /* Runtime only. */
2091
2093
2095 BLO_read_string(reader, &opop->subitem_reference_name);
2096 BLO_read_string(reader, &opop->subitem_local_name);
2097
2098 opop->tag = 0; /* Runtime only. */
2099 }
2100}
2101
2102static void direct_link_id_common(BlendDataReader *reader,
2103 Library *current_library,
2104 ID *id,
2105 ID *id_old,
2106 int id_tag,
2107 ID_Readfile_Data::Tags id_read_tags);
2108
2110 Library *current_library,
2111 ID *id,
2112 ID *id_old)
2113{
2114 /* Handle 'private IDs'. */
2116 if (nodetree != nullptr && *nodetree != nullptr) {
2117 BLO_read_struct(reader, bNodeTree, nodetree);
2118 if (!*nodetree || !BKE_idtype_idcode_is_valid(GS((*nodetree)->id.name))) {
2120 reader->fd->reports,
2121 RPT_ERROR,
2122 RPT_("Data-block '%s' had an invalid embedded node group, which has not been read"),
2123 id->name);
2124 MEM_SAFE_FREE(*nodetree);
2125 }
2126 else {
2127 direct_link_id_common(reader,
2128 current_library,
2129 (ID *)*nodetree,
2130 id_old != nullptr ? (ID *)blender::bke::node_tree_from_id(id_old) :
2131 nullptr,
2132 0,
2134 blender::bke::node_tree_blend_read_data(reader, id, *nodetree);
2135 }
2136 }
2137
2138 if (GS(id->name) == ID_SCE) {
2139 Scene *scene = (Scene *)id;
2140 if (scene->master_collection != nullptr) {
2142 if (!scene->master_collection ||
2144 {
2146 reader->fd->reports,
2147 RPT_ERROR,
2148 RPT_("Scene '%s' had an invalid root collection, which has not been read"),
2149 BKE_id_name(*id));
2151 }
2152 else {
2153 direct_link_id_common(reader,
2154 current_library,
2155 &scene->master_collection->id,
2156 id_old != nullptr ? &((Scene *)id_old)->master_collection->id :
2157 nullptr,
2158 0,
2160 BKE_collection_blend_read_data(reader, scene->master_collection, &scene->id);
2161 }
2162 }
2163 }
2164}
2165
2167{
2168 /* Exception for armature objects, where the pose has direct points to the
2169 * armature data-block. */
2170 if (GS(id_current->name) == ID_OB && ((Object *)id_current)->pose) {
2171 return ID_RECALC_GEOMETRY;
2172 }
2173
2174 return 0;
2175}
2176
2178 const ID *id_target,
2179 const ID *id_current,
2180 const bool is_identical)
2181{
2182 /* These are the evaluations that had not been performed yet at the time the
2183 * target undo state was written. These need to be done again, since they may
2184 * flush back changes to the original datablock. */
2185 int recalc = id_target->recalc;
2186
2187 if (id_current == nullptr) {
2188 /* ID does not currently exist in the database, so also will not exist in
2189 * the dependency graphs. That means it will be newly created and as a
2190 * result also fully re-evaluated regardless of the recalc flag set here. */
2191 recalc |= ID_RECALC_ALL;
2192 }
2193 else {
2194 /* If the contents datablock changed, the depsgraph needs to copy the
2195 * datablock again to ensure it matches the original datablock. */
2196 if (!is_identical) {
2197 recalc |= ID_RECALC_SYNC_TO_EVAL;
2198 }
2199
2200 /* Special exceptions. */
2201 recalc |= direct_link_id_restore_recalc_exceptions(id_current);
2202
2203 /* Evaluations for the current state that have not been performed yet
2204 * by the time we are performing this undo step. */
2205 recalc |= id_current->recalc;
2206
2207 /* Tags that were set between the target state and the current state,
2208 * that we need to perform again. */
2209 if (fd->undo_direction == STEP_UNDO) {
2210 /* Undo: tags from target to the current state. */
2211 recalc |= id_current->recalc_up_to_undo_push;
2212 }
2213 else {
2215 /* Redo: tags from current to the target state. */
2216 recalc |= id_target->recalc_up_to_undo_push;
2217 }
2218 }
2219
2220 return recalc;
2221}
2222
2224{
2225 if (id.runtime.readfile_data) {
2226 return;
2227 }
2228 id.runtime.readfile_data = MEM_callocN<ID_Readfile_Data>(__func__);
2229}
2230
2232{
2233 if (!id.runtime.readfile_data) {
2234 return ID_Readfile_Data::Tags{};
2235 }
2236 return id.runtime.readfile_data->tags;
2237}
2238
2240{
2242 return id.runtime.readfile_data->tags;
2243}
2244
2246{
2247 MEM_SAFE_FREE(id.runtime.readfile_data);
2248}
2249
2251{
2252 ID *id;
2253 FOREACH_MAIN_ID_BEGIN (&bmain, id) {
2254 /* Handle the ID itself. */
2256
2257 /* Handle its embedded IDs, because they do not get referenced by bmain. */
2258 if (GS(id->name) == ID_SCE) {
2259 Collection *collection = reinterpret_cast<Scene *>(id)->master_collection;
2260 if (collection) {
2262 }
2263 }
2264
2266 if (node_tree) {
2268 }
2269 }
2271}
2272
2274 Library *current_library,
2275 ID *id,
2276 ID *id_old,
2277 const int id_tag,
2278 const ID_Readfile_Data::Tags id_read_tags)
2279{
2280 /* This should have been caught already, either by a call to `#blo_bhead_is_id_valid_type` for
2281 * regular IDs, or in `#direct_link_id_embedded_id` for embedded ones. */
2283 "Unknown or invalid ID type, this should never happen");
2284
2285 if (!BLO_read_data_is_undo(reader)) {
2286 /* When actually reading a file, we do want to reset/re-generate session UIDS.
2287 * In undo case, we want to re-use existing ones. */
2288 id->session_uid = MAIN_ID_SESSION_UID_UNSET;
2289 }
2290
2291 id->lib = current_library;
2292 if (id->lib) {
2293 /* Always fully clear fake user flag for linked data. */
2294 id->flag &= ~ID_FLAG_FAKEUSER;
2295 }
2296 id->us = ID_FAKE_USERS(id);
2297 id->icon_id = 0;
2298 id->newid = nullptr; /* Needed because .blend may have been saved with crap value here... */
2299 id->orig_id = nullptr;
2300 id->py_instance = nullptr;
2301
2302 /* Initialize with provided tag. */
2303 if (BLO_read_data_is_undo(reader)) {
2304 id->tag = (id_tag & ~ID_TAG_KEEP_ON_UNDO) | (id->tag & ID_TAG_KEEP_ON_UNDO);
2305 }
2306 else {
2307 id->tag = id_tag;
2308 }
2309
2310 if (!BLO_read_data_is_undo(reader)) {
2311 /* Reset the runtime data, as there were versions of Blender that did not do
2312 * this before writing to disk. */
2313 id->runtime = ID_Runtime{};
2314 }
2316 id->runtime.readfile_data->tags = id_read_tags;
2317
2318 if ((id_tag & ID_TAG_TEMP_MAIN) == 0) {
2320 }
2321
2322 if (ID_IS_LINKED(id)) {
2323 id->library_weak_reference = nullptr;
2324 }
2325 else {
2327 }
2328
2330 /* For placeholder we only need to set the tag and properly initialize generic ID fields above,
2331 * no further data to read. */
2332 return;
2333 }
2334
2335 BKE_animdata_blend_read_data(reader, id);
2336
2337 if (id->asset_data) {
2340 /* Restore runtime asset type info. */
2341 const IDTypeInfo *id_type = BKE_idtype_get_info_from_id(id);
2342 id->asset_data->local_type_info = id_type->asset_type_info;
2343 }
2344
2345 /* Link direct data of ID properties. */
2346 if (id->properties) {
2347 BLO_read_struct(reader, IDProperty, &id->properties);
2348 /* this case means the data was written incorrectly, it should not happen */
2349 IDP_BlendDataRead(reader, &id->properties);
2350 }
2351
2352 if (id->system_properties) {
2355 }
2356
2357 id->flag &= ~ID_FLAG_INDIRECT_WEAK_LINK;
2358
2359 /* NOTE: It is important to not clear the recalc flags for undo/redo.
2360 * Preserving recalc flags on redo/undo is the only way to make dependency graph detect
2361 * that animation is to be evaluated on undo/redo. If this is not enforced by the recalc
2362 * flags dependency graph does not do animation update to avoid loss of unkeyed changes.,
2363 * which conflicts with undo/redo of changes to animation data itself.
2364 *
2365 * But for regular file load we clear the flag, since the flags might have been changed since
2366 * the version the file has been saved with. */
2367 if (!BLO_read_data_is_undo(reader)) {
2368 id->recalc = 0;
2369 id->recalc_after_undo_push = 0;
2370 }
2371 else if ((reader->fd->skip_flags & BLO_READ_SKIP_UNDO_OLD_MAIN) == 0) {
2372 id->recalc = direct_link_id_restore_recalc(reader->fd, id, id_old, false);
2373 id->recalc_after_undo_push = 0;
2374 }
2375
2376 /* Link direct data of overrides. */
2377 if (id->override_library) {
2379 /* Work around file corruption on writing, see #86853. */
2380 if (id->override_library != nullptr) {
2384 }
2385 id->override_library->runtime = nullptr;
2386 }
2387 }
2388
2389 /* Handle 'private IDs'. */
2390 direct_link_id_embedded_id(reader, current_library, id, id_old);
2391}
2392
2394
2395/* -------------------------------------------------------------------- */
2398
2400
2401/* -------------------------------------------------------------------- */
2404
2406{
2407 key->uidgen = 1;
2408 LISTBASE_FOREACH (KeyBlock *, block, &key->block) {
2409 block->uid = key->uidgen++;
2410 }
2411}
2412
2414
2415/* -------------------------------------------------------------------- */
2418
2419#ifdef USE_SETSCENE_CHECK
2423static bool scene_validate_setscene__liblink(Scene *sce, const int totscene)
2424{
2425 Scene *sce_iter;
2426 int a;
2427
2428 if (sce->set == nullptr) {
2429 return true;
2430 }
2431
2432 for (a = 0, sce_iter = sce; sce_iter->set; sce_iter = sce_iter->set, a++) {
2433 /* This runs per library (before each libraries #Main has been joined),
2434 * so we can't step into other libraries since `totscene` is only for this library.
2435 *
2436 * Also, other libraries may not have been linked yet, while we could check for
2437 * #ID_Readfile_Data::Tags.needs_linking the library pointer check is sufficient. */
2438 if (sce->id.lib != sce_iter->id.lib) {
2439 return true;
2440 }
2442 return true;
2443 }
2444
2445 if (a > totscene) {
2446 sce->set = nullptr;
2447 return false;
2448 }
2449 }
2450
2451 return true;
2452}
2453#endif
2454
2456{
2457#ifdef USE_SETSCENE_CHECK
2458 const int totscene = BLI_listbase_count(&bmain->scenes);
2459 LISTBASE_FOREACH (Scene *, sce, &bmain->scenes) {
2462 if (!scene_validate_setscene__liblink(sce, totscene)) {
2463 CLOG_WARN(&LOG, "Found cyclic background scene when linking %s", sce->id.name + 2);
2464 }
2465 }
2466 }
2467#else
2468 UNUSED_VARS(bmain, totscene);
2469#endif
2470}
2471
2472#undef USE_SETSCENE_CHECK
2473
2475
2476/* -------------------------------------------------------------------- */
2477
2480
2482{
2483 /* Make sure we have full path in lib->runtime->filepath_abs */
2484 /* NOTE: Since existing libraries are searched by their absolute path, this has to be generated
2485 * before the lookup below. Otherwise, in case the stored absolute filepath is not 'correct' (may
2486 * be empty, or have been stored in a different 'relative path context'), the comparison below
2487 * will always fail, leading to creating duplicates IDs of a same library. */
2488 /* TODO: May be worth checking whether comparison below could use `lib->filepath` instead? */
2489 STRNCPY(lib->runtime->filepath_abs, lib->filepath);
2490 BLI_path_abs(lib->runtime->filepath_abs, fd->relabase);
2491 BLI_path_normalize(lib->runtime->filepath_abs);
2492
2493 /* check if the library was already read */
2494 LISTBASE_FOREACH (Main *, newmain, fd->mainlist) {
2495 if (newmain->curlib) {
2496 if (BLI_path_cmp(newmain->curlib->runtime->filepath_abs, lib->runtime->filepath_abs) == 0) {
2499 RPT_("Library '%s', '%s' had multiple instances, save and reload!"),
2500 lib->filepath,
2501 lib->runtime->filepath_abs);
2502
2503 change_ID_pointer_to_real_ID_pointer(fd->mainlist, fd, lib, newmain->curlib);
2504 // change_link_placeholder_to_real_ID_pointer_fd(fd, lib, newmain->curlib);
2505
2506 BLI_remlink(&main->libraries, lib);
2507 MEM_freeN(lib);
2508
2509 /* Now, since Blender always expect **latest** Main pointer from fd->mainlist
2510 * to be the active library Main pointer,
2511 * where to add all non-library data-blocks found in file next, we have to switch that
2512 * 'dupli' found Main to latest position in the list!
2513 * Otherwise, you get weird disappearing linked data on a rather inconsistent basis.
2514 * See also #53977 for reproducible case. */
2515 BLI_remlink(fd->mainlist, newmain);
2516 BLI_addtail(fd->mainlist, newmain);
2517
2518 return;
2519 }
2520 }
2521 }
2522
2523 // printf("direct_link_library: filepath %s\n", lib->filepath);
2524 // printf("direct_link_library: filepath_abs %s\n", lib->runtime->filepath_abs);
2525
2526 BlendDataReader reader = {fd};
2527 BKE_packedfile_blend_read(&reader, &lib->packedfile, lib->filepath);
2528
2529 /* new main */
2530 Main *newmain = BKE_main_new();
2531 BLI_addtail(fd->mainlist, newmain);
2532 newmain->curlib = lib;
2533
2534 lib->runtime->parent = nullptr;
2535
2536 id_us_ensure_real(&lib->id);
2537}
2538
2539/* Always call this once you have loaded new library data to set the relative paths correctly
2540 * in relation to the blend file. */
2541static void fix_relpaths_library(const char *basepath, Main *main)
2542{
2543 /* #BLO_read_from_memory uses a blank file-path. */
2544 if (basepath == nullptr || basepath[0] == '\0') {
2545 LISTBASE_FOREACH (Library *, lib, &main->libraries) {
2546 /* when loading a linked lib into a file which has not been saved,
2547 * there is nothing we can be relative to, so instead we need to make
2548 * it absolute. This can happen when appending an object with a relative
2549 * link into an unsaved blend file. See #27405.
2550 * The remap relative option will make it relative again on save - campbell */
2551 if (BLI_path_is_rel(lib->filepath)) {
2552 STRNCPY(lib->filepath, lib->runtime->filepath_abs);
2553 }
2554 }
2555 }
2556 else {
2557 LISTBASE_FOREACH (Library *, lib, &main->libraries) {
2558 /* Libraries store both relative and abs paths, recreate relative paths,
2559 * relative to the blend file since indirectly linked libraries will be
2560 * relative to their direct linked library. */
2561 if (BLI_path_is_rel(lib->filepath)) { /* if this is relative to begin with? */
2562 STRNCPY(lib->filepath, lib->runtime->filepath_abs);
2563 BLI_path_rel(lib->filepath, basepath);
2564 }
2565 }
2566 }
2567}
2568
2570
2571/* -------------------------------------------------------------------- */
2574
2575static ID *create_placeholder(Main *mainvar,
2576 const short idcode,
2577 const char *idname,
2578 const int tag,
2579 const bool was_liboverride)
2580{
2581 ListBase *lb = which_libbase(mainvar, idcode);
2582 ID *ph_id = BKE_libblock_alloc_notest(idcode);
2583
2584 *((short *)ph_id->name) = idcode;
2585 BLI_strncpy(ph_id->name + 2, idname, sizeof(ph_id->name) - 2);
2587 ph_id->lib = mainvar->curlib;
2588 ph_id->tag = tag | ID_TAG_MISSING;
2589 ph_id->us = ID_FAKE_USERS(ph_id);
2590 ph_id->icon_id = 0;
2591
2592 if (was_liboverride) {
2593 /* 'Abuse' `ID_TAG_LIBOVERRIDE_NEED_RESYNC` to mark that placeholder missing linked ID as
2594 * being a liboverride.
2595 *
2596 * This will be used by the liboverride resync process, see #lib_override_library_resync. */
2598 }
2599
2600 BLI_addtail(lb, ph_id);
2601 id_sort_by_name(lb, ph_id, nullptr);
2602
2603 if (mainvar->id_map != nullptr) {
2604 BKE_main_idmap_insert_id(mainvar->id_map, ph_id);
2605 }
2606
2607 if ((tag & ID_TAG_TEMP_MAIN) == 0) {
2609 }
2610
2611 return ph_id;
2612}
2613
2615{
2616 /* Placeholder ObData IDs won't have any material, we have to update their objects for that,
2617 * otherwise the inconsistency between both will lead to crashes (especially in Eevee?). */
2618 LISTBASE_FOREACH (Object *, ob, &bmain->objects) {
2619 ID *obdata = static_cast<ID *>(ob->data);
2620 if (obdata != nullptr && obdata->tag & ID_TAG_MISSING) {
2621 BKE_object_materials_sync_length(bmain, ob, obdata);
2622 }
2623 }
2624}
2625
2626static bool direct_link_id(FileData *fd,
2627 Main *main,
2628 const int tag,
2629 const ID_Readfile_Data::Tags id_read_tags,
2630 ID *id,
2631 ID *id_old)
2632{
2633 BlendDataReader reader = {fd};
2634 /* Sharing is only allowed within individual data-blocks currently. The clearing is done
2635 * explicitly here, in case the `reader` is used by multiple IDs in the future. */
2637
2638 /* Read part of datablock that is common between real and embedded datablocks. */
2639 direct_link_id_common(&reader, main->curlib, id, id_old, tag, id_read_tags);
2640
2642 /* For placeholder we only need to set the tag, no further data to read. */
2643 id->tag = tag;
2644 return true;
2645 }
2646
2647 const IDTypeInfo *id_type = BKE_idtype_get_info_from_id(id);
2648 if (id_type->blend_read_data != nullptr) {
2649 id_type->blend_read_data(&reader, id);
2650 }
2651
2652 /* XXX Very weakly handled currently, see comment in read_libblock() before trying to
2653 * use it for anything new. */
2654 bool success = true;
2655
2656 switch (GS(id->name)) {
2657 case ID_SCR:
2658 success = BKE_screen_blend_read_data(&reader, (bScreen *)id);
2659 break;
2660 case ID_LI:
2661 direct_link_library(fd, (Library *)id, main);
2662 break;
2663 default:
2664 /* Do nothing. Handled by IDTypeInfo callback. */
2665 break;
2666 }
2667
2668 /* try to restore (when undoing) or clear ID's cache pointers. */
2669 if (id_type->foreach_cache != nullptr) {
2672 }
2673
2674 return success;
2675}
2676
2677/* Read all data associated with a datablock into datamap. */
2679 BHead *bhead,
2680 const char *allocname,
2681 const int id_type_index)
2682{
2683 bhead = blo_bhead_next(fd, bhead);
2684
2685 while (bhead && bhead->code == BLO_CODE_DATA) {
2686 void *data = read_struct(fd, bhead, allocname, id_type_index);
2687 if (data) {
2688 const bool is_new = oldnewmap_insert(fd->datamap, bhead->old, data, 0);
2689 if (!is_new) {
2690 CLOG_ERROR(&LOG,
2691 "Blendfile corruption: Invalid, or multiple `bhead` with same old address "
2692 "value (%p) for a given ID.",
2693 bhead->old);
2694 }
2695 }
2696
2697 bhead = blo_bhead_next(fd, bhead);
2698 }
2699
2700 return bhead;
2701}
2702
2703/* Verify if the datablock and all associated data is identical. */
2705{
2706 /* Test ID itself. */
2707 if (bhead->len && !BHEADN_FROM_BHEAD(bhead)->is_memchunk_identical) {
2708 return false;
2709 }
2710
2711 /* Test any other data that is part of ID (logic must match read_data_into_datamap). */
2712 bhead = blo_bhead_next(fd, bhead);
2713
2714 while (bhead && bhead->code == BLO_CODE_DATA) {
2715 if (bhead->len && !BHEADN_FROM_BHEAD(bhead)->is_memchunk_identical) {
2716 return false;
2717 }
2718
2719 bhead = blo_bhead_next(fd, bhead);
2720 }
2721
2722 return true;
2723}
2724
2725/* Re-use the whole 'noundo' local IDs by moving them from old to new main. Linked ones are handled
2726 * separately together with their libraries.
2727 *
2728 * NOTE: While in theory Library IDs (and their related linked IDs) are also 'noundo' data, in
2729 * practice they need to be handled separately, to ensure that their order in the new bmain list
2730 * matches the one from the read blend-file. Reading linked 'placeholder' entries in a memfile
2731 * relies on current library being the last item in the new main list. */
2733{
2734 Main *old_bmain = static_cast<Main *>(fd->old_mainlist->first);
2735
2736 BLI_assert(old_bmain->curlib == nullptr);
2738
2740 int i = lbarray.size();
2741 while (i--) {
2742 if (BLI_listbase_is_empty(lbarray[i])) {
2743 continue;
2744 }
2745
2746 /* Only move 'noundo' local IDs. */
2747 ID *id = static_cast<ID *>(lbarray[i]->first);
2748 const IDTypeInfo *id_type = BKE_idtype_get_info_from_id(id);
2749 if ((id_type->flags & IDTYPE_FLAGS_NO_MEMFILE_UNDO) == 0) {
2750 continue;
2751 }
2752
2753 Main *new_bmain = static_cast<Main *>(fd->mainlist->first);
2756 BLI_movelisttolist(new_lb, lbarray[i]);
2757
2758 /* Update mappings accordingly. */
2759 LISTBASE_FOREACH (ID *, id_iter, new_lb) {
2761 id_iter->tag |= ID_TAG_UNDO_OLD_ID_REUSED_NOUNDO;
2762 }
2763 }
2764}
2765
2767 FileData *fd, Main *new_main, Main *old_main, Main *libmain, BHead *bhead)
2768{
2769 Library *curlib = libmain->curlib;
2770
2771 BLI_remlink(fd->old_mainlist, libmain);
2772 BLI_remlink_safe(&old_main->libraries, libmain->curlib);
2773 BLI_addtail(fd->mainlist, libmain);
2774 BLI_addtail(&new_main->libraries, libmain->curlib);
2775
2778 if (bhead != nullptr) {
2779 oldnewmap_lib_insert(fd, bhead->old, &curlib->id, GS(curlib->id.name));
2780 }
2781
2782 ID *id_iter;
2783 FOREACH_MAIN_ID_BEGIN (libmain, id_iter) {
2785 }
2787}
2788
2789/* For undo, restore matching library datablock from the old main. */
2791 FileData *fd, Main *new_main, const ID *id, ID *id_old, BHead *bhead)
2792{
2793 /* In undo case, most libraries and linked data should be kept as is from previous state
2794 * (see BLO_read_from_memfile).
2795 * However, some needed by the snapshot being read may have been removed in previous one,
2796 * and would go missing.
2797 * This leads e.g. to disappearing objects in some undo/redo case, see #34446.
2798 * That means we have to carefully check whether current lib or
2799 * libdata already exits in old main, if it does we merely copy it over into new main area,
2800 * otherwise we have to do a full read of that bhead... */
2801 CLOG_INFO(&LOG_UNDO, 2, "UNDO: restore library %s", id->name);
2802
2803 if (id_old == nullptr) {
2804 CLOG_INFO(&LOG_UNDO, 2, " -> NO match");
2805 return false;
2806 }
2807
2808 Main *libmain = static_cast<Main *>(fd->old_mainlist->first);
2809 /* Skip `oldmain` itself. */
2810 for (libmain = libmain->next; libmain; libmain = libmain->next) {
2811 if (&libmain->curlib->id == id_old) {
2812 Main *old_main = static_cast<Main *>(fd->old_mainlist->first);
2814 2,
2815 " compare with %s -> match (existing libpath: %s)",
2816 libmain->curlib ? libmain->curlib->id.name : "<none>",
2817 libmain->curlib ? libmain->curlib->runtime->filepath_abs : "<none>");
2818 /* In case of a library, we need to re-add its main to fd->mainlist,
2819 * because if we have later a missing ID_LINK_PLACEHOLDER,
2820 * we need to get the correct lib it is linked to!
2821 * Order is crucial, we cannot bulk-add it in BLO_read_from_memfile()
2822 * like it used to be. */
2823 read_undo_move_libmain_data(fd, new_main, old_main, libmain, bhead);
2824 return true;
2825 }
2826 }
2827
2828 return false;
2829}
2830
2831static ID *library_id_is_yet_read(FileData *fd, Main *mainvar, BHead *bhead);
2832
2833/* For undo, restore existing linked datablock from the old main.
2834 *
2835 * Note that IDs from existing libs have already been moved into the new main when their (local)
2836 * ID_LI library ID was handled by #read_libblock_undo_restore_library, so this function has very
2837 * little to do. */
2839 FileData *fd, Main *libmain, const ID *id, ID **r_id_old, BHead *bhead)
2840{
2841 CLOG_INFO(&LOG_UNDO, 2, "UNDO: restore linked datablock %s", id->name);
2842
2843 if (*r_id_old == nullptr) {
2844 /* If the linked ID had to be re-read at some point, its session_uid may not be the same as
2845 * its reference stored in the memfile anymore. Do a search by name then. */
2846 *r_id_old = library_id_is_yet_read(fd, libmain, bhead);
2847
2848 if (*r_id_old == nullptr) {
2850 2,
2851 " from %s (%s): NOT found",
2852 libmain->curlib ? libmain->curlib->id.name : "<nullptr>",
2853 libmain->curlib ? libmain->curlib->filepath : "<nullptr>");
2854 return false;
2855 }
2856
2858 2,
2859 " from %s (%s): found by name",
2860 libmain->curlib ? libmain->curlib->id.name : "<nullptr>",
2861 libmain->curlib ? libmain->curlib->filepath : "<nullptr>");
2862 /* The Library ID 'owning' this linked ID should already have been moved to new main by a call
2863 * to #read_libblock_undo_restore_library. */
2864 BLI_assert(*r_id_old == static_cast<ID *>(BKE_main_idmap_lookup_uid(
2865 fd->new_idmap_uid, (*r_id_old)->session_uid)));
2866 }
2867 else {
2869 2,
2870 " from %s (%s): found by session_uid",
2871 libmain->curlib ? libmain->curlib->id.name : "<nullptr>",
2872 libmain->curlib ? libmain->curlib->filepath : "<nullptr>");
2873 /* The Library ID 'owning' this linked ID should already have been moved to new main by a call
2874 * to #read_libblock_undo_restore_library. */
2875 BLI_assert(*r_id_old ==
2876 static_cast<ID *>(BKE_main_idmap_lookup_uid(fd->new_idmap_uid, id->session_uid)));
2877 }
2878
2879 oldnewmap_lib_insert(fd, bhead->old, *r_id_old, GS((*r_id_old)->name));
2880
2881 /* No need to do anything else for ID_LINK_PLACEHOLDER, it's assumed
2882 * already present in its lib's main. */
2883 return true;
2884}
2885
2886/* For undo, restore unchanged local datablock from old main. */
2888 FileData *fd, Main *main, const ID * /*id*/, ID *id_old, BHead *bhead, const int id_tag)
2889{
2891 BLI_assert(id_old != nullptr);
2892
2893 /* Do not add ID_TAG_NEW here, this should not be needed/used in undo case anyway (as
2894 * this is only for do_version-like code), but for sake of consistency, and also because
2895 * it will tell us which ID is re-used from old Main, and which one is actually newly read. */
2896 /* Also do not set #ID_Readfile_Data::Tags.needs_linking, this ID will never be re-liblinked,
2897 * hence that tag will never be cleared, leading to critical issue in link/append code. */
2898 /* Some tags need to be preserved here. */
2900 (id_old->tag & ID_TAG_KEEP_ON_UNDO);
2901 id_old->lib = main->curlib;
2902 id_old->us = ID_FAKE_USERS(id_old);
2903 /* Do not reset id->icon_id here, memory allocated for it remains valid. */
2904 /* Needed because .blend may have been saved with crap value here... */
2905 id_old->newid = nullptr;
2906 id_old->orig_id = nullptr;
2907
2908 const short idcode = GS(id_old->name);
2909 Main *old_bmain = static_cast<Main *>(fd->old_mainlist->first);
2910 ListBase *old_lb = which_libbase(old_bmain, idcode);
2911 ListBase *new_lb = which_libbase(main, idcode);
2912 BLI_remlink(old_lb, id_old);
2913 BLI_addtail(new_lb, id_old);
2914
2915 /* Recalc flags, mostly these just remain as they are. */
2917 id_old->recalc_after_undo_push = 0;
2918
2919 /* Insert into library map for lookup by newly read datablocks (with pointer value bhead->old).
2920 * Note that existing datablocks in memory (which pointer value would be id_old) are not
2921 * remapped, so no need to store this info here. */
2922 oldnewmap_lib_insert(fd, bhead->old, id_old, bhead->code);
2923
2925
2926 if (GS(id_old->name) == ID_OB) {
2927 Object *ob = (Object *)id_old;
2928 /* For undo we stay in object mode during undo presses, so keep editmode disabled for re-used
2929 * data-blocks too. */
2930 ob->mode &= ~OB_MODE_EDIT;
2931 }
2932}
2933
2934/* For undo, store changed datablock at old address. */
2936{
2937 /* During memfile undo, if an ID changed and we cannot directly re-use existing one from old
2938 * bmain, we do a full read of the new id from the memfile, and then fully swap its content
2939 * with the old id. This allows us to keep the same pointer even for modified data, which
2940 * helps reducing further detected changes by the depsgraph (since unchanged IDs remain fully
2941 * unchanged, even if they are using/pointing to a changed one). */
2943 BLI_assert(id_old != nullptr);
2944
2945 const short idcode = GS(id->name);
2946
2947 Main *old_bmain = static_cast<Main *>(fd->old_mainlist->first);
2948 ListBase *old_lb = which_libbase(old_bmain, idcode);
2949 ListBase *new_lb = which_libbase(main, idcode);
2950 BLI_remlink(old_lb, id_old);
2951 BLI_remlink(new_lb, id);
2952
2953 /* We do need remapping of internal pointers to the ID itself here.
2954 *
2955 * Passing a null #Main means that not all potential runtime data (like collections' parent
2956 * pointers etc.) will be up-to-date. However, this should not be a problem here, since these
2957 * data are re-generated later in file-read process anyway. */
2958 BKE_lib_id_swap_full(nullptr,
2959 id,
2960 id_old,
2961 true,
2965
2966 /* Special temporary usage of this pointer, necessary for the `undo_preserve` call after
2967 * lib-linking to restore some data that should never be affected by undo, e.g. the 3D cursor of
2968 * #Scene. */
2969 id_old->orig_id = id;
2972
2973 BLI_addtail(new_lb, id_old);
2974 BLI_addtail(old_lb, id);
2975}
2976
2978 FileData *fd, Main *main, BHead *bhead, const int id_tag, ID **r_id_old)
2979{
2980 BLI_assert(fd->old_idmap_uid != nullptr);
2981
2982 /* Get pointer to memory of new ID that we will be reading. */
2983 const ID *id = static_cast<const ID *>(peek_struct_undo(fd, bhead));
2984 const IDTypeInfo *id_type = BKE_idtype_get_info_from_id(id);
2985
2986 const bool do_partial_undo = (fd->skip_flags & BLO_READ_SKIP_UNDO_OLD_MAIN) == 0;
2987#ifndef NDEBUG
2988 if (do_partial_undo && (bhead->code != ID_LINK_PLACEHOLDER)) {
2989 /* This code should only ever be reached for local data-blocks. */
2990 BLI_assert(main->curlib == nullptr);
2991 }
2992#endif
2993
2994 /* Find the 'current' existing ID we want to reuse instead of the one we
2995 * would read from the undo memfile. */
2996 ID *id_old = (fd->old_idmap_uid != nullptr) ?
2998 nullptr;
2999
3000 if (bhead->code == ID_LI) {
3001 /* Restore library datablock, if possible. */
3002 if (read_libblock_undo_restore_library(fd, main, id, id_old, bhead)) {
3003 return true;
3004 }
3005 }
3006 else if (bhead->code == ID_LINK_PLACEHOLDER) {
3007 /* Restore linked datablock. */
3008 if (read_libblock_undo_restore_linked(fd, main, id, &id_old, bhead)) {
3009 return true;
3010 }
3011 }
3012 else if (id_type->flags & IDTYPE_FLAGS_NO_MEMFILE_UNDO) {
3013 CLOG_INFO(
3014 &LOG_UNDO, 2, "UNDO: skip restore datablock %s, 'NO_MEMFILE_UNDO' type of ID", id->name);
3015
3016 /* If that local noundo ID still exists currently, the call to
3017 * #read_undo_reuse_noundo_local_ids at the beginning of #blo_read_file_internal will already
3018 * have moved it into the new main, and populated accordingly the new_idmap_uid.
3019 *
3020 * If this is the case, it can also be remapped for newly read data. Otherwise, this is 'lost'
3021 * data that cannot be restored on undo, so no remapping should exist for it in the ID
3022 * oldnewmap. */
3023 if (id_old) {
3024 BLI_assert(id_old ==
3025 static_cast<ID *>(BKE_main_idmap_lookup_uid(fd->new_idmap_uid, id->session_uid)));
3026 oldnewmap_lib_insert(fd, bhead->old, id_old, bhead->code);
3027 }
3028 return true;
3029 }
3030
3031 if (!do_partial_undo) {
3033 2,
3034 "UNDO: read %s (uid %u) -> no partial undo, always read at new address",
3035 id->name,
3036 id->session_uid);
3037 return false;
3038 }
3039
3040 /* Restore local datablocks. */
3041 if (id_old != nullptr && read_libblock_is_identical(fd, bhead)) {
3042 /* Local datablock was unchanged, restore from the old main. */
3044 2,
3045 "UNDO: read %s (uid %u) -> keep identical datablock",
3046 id->name,
3047 id->session_uid);
3048
3049 read_libblock_undo_restore_identical(fd, main, id, id_old, bhead, id_tag);
3050
3051 *r_id_old = id_old;
3052 return true;
3053 }
3054 if (id_old != nullptr) {
3055 /* Local datablock was changed. Restore at the address of the old datablock. */
3057 2,
3058 "UNDO: read %s (uid %u) -> read to old existing address",
3059 id->name,
3060 id->session_uid);
3061 *r_id_old = id_old;
3062 return false;
3063 }
3064
3065 /* Local datablock does not exist in the undo step, so read from scratch. */
3066 CLOG_INFO(
3067 &LOG_UNDO, 2, "UNDO: read %s (uid %u) -> read at new address", id->name, id->session_uid);
3068 return false;
3069}
3070
3071/* This routine reads a datablock and its direct data, and advances bhead to
3072 * the next datablock. For library linked datablocks, only a placeholder will
3073 * be generated, to be replaced in read_library_linked_ids.
3074 *
3075 * When reading for undo, libraries, linked datablocks and unchanged datablocks
3076 * will be restored from the old database. Only new or changed datablocks will
3077 * actually be read. */
3079 Main *main,
3080 BHead *bhead,
3081 int id_tag,
3082 ID_Readfile_Data::Tags id_read_tags,
3083 const bool placeholder_set_indirect_extern,
3084 ID **r_id)
3085{
3086 const bool do_partial_undo = (fd->skip_flags & BLO_READ_SKIP_UNDO_OLD_MAIN) == 0;
3087
3088 /* First attempt to restore existing datablocks for undo.
3089 * When datablocks are changed but still exist, we restore them at the old
3090 * address and inherit recalc flags for the dependency graph. */
3091 ID *id_old = nullptr;
3092 if (fd->flags & FD_FLAGS_IS_MEMFILE) {
3093 if (read_libblock_undo_restore(fd, main, bhead, id_tag, &id_old)) {
3094 if (r_id) {
3095 *r_id = id_old;
3096 }
3097 if (main->id_map != nullptr && id_old != nullptr) {
3098 BKE_main_idmap_insert_id(main->id_map, id_old);
3099 }
3100
3101 return blo_bhead_next(fd, bhead);
3102 }
3103 }
3104
3105 /* Read libblock struct. */
3106 const int id_type_index = BKE_idtype_idcode_to_index(bhead->code);
3107#ifndef NDEBUG
3108 const char *blockname = nullptr;
3109#else
3110 /* Avoid looking up in the mapping for all read BHead, since this only contains the ID type name
3111 * in release builds. */
3112 const char *blockname = get_alloc_name(fd, bhead, nullptr, id_type_index);
3113#endif
3114 ID *id = read_id_struct(fd, bhead, blockname, id_type_index);
3115 if (id == nullptr) {
3116 if (r_id) {
3117 *r_id = nullptr;
3118 }
3119 return blo_bhead_next(fd, bhead);
3120 }
3121
3122 /* Determine ID type and add to main database list. */
3123 const short idcode = GS(id->name);
3124 ListBase *lb = which_libbase(main, idcode);
3125 if (lb == nullptr) {
3126 /* Unknown ID type. */
3127 CLOG_WARN(&LOG, "Unknown id code '%c%c'", (idcode & 0xff), (idcode >> 8));
3128 MEM_freeN(id);
3129 if (r_id) {
3130 *r_id = nullptr;
3131 }
3132 return blo_bhead_next(fd, bhead);
3133 }
3134
3135 /* NOTE: id must be added to the list before direct_link_id(), since
3136 * direct_link_library() may remove it from there in case of duplicates. */
3137 BLI_addtail(lb, id);
3138
3139 /* Insert into library map for lookup by newly read datablocks (with pointer value bhead->old).
3140 * Note that existing datablocks in memory (which pointer value would be id_old) are not remapped
3141 * remapped anymore, so no need to store this info here. */
3142 ID *id_target = (do_partial_undo && id_old != nullptr) ? id_old : id;
3143 oldnewmap_lib_insert(fd, bhead->old, id_target, bhead->code);
3144
3145 if (r_id) {
3146 *r_id = id_target;
3147 }
3148
3149 /* Set tag for new datablock to indicate lib linking and versioning needs
3150 * to be done still. */
3151 id_tag |= ID_TAG_NEW;
3152 id_read_tags.needs_linking = true;
3153
3154 if (bhead->code == ID_LINK_PLACEHOLDER) {
3155 /* Read placeholder for linked datablock. */
3156 id_read_tags.is_link_placeholder = true;
3157
3158 if (placeholder_set_indirect_extern) {
3159 if (id->flag & ID_FLAG_INDIRECT_WEAK_LINK) {
3160 id_tag |= ID_TAG_INDIRECT;
3161 }
3162 else {
3163 id_tag |= ID_TAG_EXTERN;
3164 }
3165 }
3166
3167 direct_link_id(fd, main, id_tag, id_read_tags, id, id_old);
3168
3169 if (main->id_map != nullptr) {
3170 BKE_main_idmap_insert_id(main->id_map, id);
3171 }
3172
3173 return blo_bhead_next(fd, bhead);
3174 }
3175
3176 /* Read datablock contents.
3177 * Use convenient malloc name for debugging and better memory link prints. */
3178 bhead = read_data_into_datamap(fd, bhead, blockname, id_type_index);
3179 const bool success = direct_link_id(fd, main, id_tag, id_read_tags, id, id_old);
3181
3182 if (!success) {
3183 /* XXX This is probably working OK currently given the very limited scope of that flag.
3184 * However, it is absolutely **not** handled correctly: it is freeing an ID pointer that has
3185 * been added to the fd->libmap mapping, which in theory could lead to nice crashes...
3186 * This should be properly solved at some point. */
3187 BKE_id_free(main, id);
3188 if (r_id != nullptr) {
3189 *r_id = nullptr;
3190 }
3191 }
3192 else {
3193 if (do_partial_undo && id_old != nullptr) {
3194 /* For undo, store contents read into id at id_old. */
3196 }
3197 if (fd->new_idmap_uid != nullptr) {
3199 }
3200 if (main->id_map != nullptr) {
3201 BKE_main_idmap_insert_id(main->id_map, id_target);
3202 }
3203 }
3204
3205 return bhead;
3206}
3207
3209
3210/* -------------------------------------------------------------------- */
3213
3215{
3217
3218 bhead = read_data_into_datamap(fd, bhead, "Data for Asset meta-data", INDEX_ID_NULL);
3219
3220 BlendDataReader reader = {fd};
3221 BLO_read_struct(&reader, AssetMetaData, r_asset_data);
3222 BKE_asset_metadata_read(&reader, *r_asset_data);
3223
3225
3226 return bhead;
3227}
3228
3230
3231/* -------------------------------------------------------------------- */
3234
3235/* NOTE: this has to be kept for reading older files... */
3236/* also version info is written here */
3238{
3239 FileGlobal *fg = static_cast<FileGlobal *>(
3240 read_struct(fd, bhead, "Data from Global block", INDEX_ID_NULL));
3241
3242 /* NOTE: `bfd->main->versionfile` is supposed to have already been set from `fd->fileversion`
3243 * beforehand by calling code. */
3244 bfd->main->subversionfile = fg->subversion;
3247
3248 bfd->main->minversionfile = fg->minversion;
3250
3252 STRNCPY(bfd->main->build_hash, fg->build_hash);
3254
3255 bfd->fileflags = fg->fileflags;
3256 bfd->globalf = fg->globalf;
3257
3258 /* NOTE: since 88b24bc6bb, `fg->filepath` is only written for crash recovery and autosave files,
3259 * so only overwrite `fd->relabase` if it is not empty, in case a regular blendfile is opened
3260 * through one of the 'recover' operators.
3261 *
3262 * In all other cases, the path is just set to the current path of the blendfile being read, so
3263 * there is no need to handle anymore older files (pre-2.65) that did not store (correctly) their
3264 * path. */
3265 if (G.fileflags & G_FILE_RECOVER_READ) {
3266 if (fg->filepath[0] != '\0') {
3267 STRNCPY(fd->relabase, fg->filepath);
3268 /* Used to set expected original filepath in read Main, instead of the path of the recovery
3269 * file itself. */
3270 STRNCPY(bfd->filepath, fg->filepath);
3271 }
3272 }
3273
3274 bfd->curscreen = fg->curscreen;
3275 bfd->curscene = fg->curscene;
3276 bfd->cur_view_layer = fg->cur_view_layer;
3277
3278 MEM_freeN(fg);
3279
3280 fd->globalf = bfd->globalf;
3281 fd->fileflags = bfd->fileflags;
3282
3283 return blo_bhead_next(fd, bhead);
3284}
3285
3286/* NOTE: this has to be kept for reading older files... */
3287static void link_global(FileData *fd, BlendFileData *bfd)
3288{
3289 bfd->cur_view_layer = static_cast<ViewLayer *>(
3291 bfd->curscreen = static_cast<bScreen *>(newlibadr(fd, nullptr, false, bfd->curscreen));
3292 bfd->curscene = static_cast<Scene *>(newlibadr(fd, nullptr, false, bfd->curscene));
3293 /* this happens in files older than 2.35 */
3294 if (bfd->curscene == nullptr) {
3295 if (bfd->curscreen) {
3296 bfd->curscene = bfd->curscreen->scene;
3297 }
3298 }
3299 if (bfd->curscene == nullptr) {
3300 bfd->curscene = static_cast<Scene *>(bfd->main->scenes.first);
3301 }
3302}
3303
3305
3306/* -------------------------------------------------------------------- */
3309
3310static void do_versions_userdef(FileData * /*fd*/, BlendFileData *bfd)
3311{
3312 UserDef *user = bfd->user;
3313
3314 if (user == nullptr) {
3315 return;
3316 }
3317
3319}
3320
3322{
3323 /* WATCH IT!!!: pointers from libdata have not been converted */
3324
3325 /* Don't allow versioning to create new data-blocks. */
3326 main->is_locked_for_linking = true;
3327
3328 /* Code ensuring conversion from new 'system IDProperties' in 5.0. This needs to run before any
3329 * other data versioning. Otherwise, things like Cycles versioning code cannot work as expected.
3330 *
3331 * Merge (with overwrite) future system properties storage into current IDProperties. */
3333
3334 if (G.debug & G_DEBUG) {
3335 char build_commit_datetime[32];
3336 time_t temp_time = main->build_commit_timestamp;
3337 tm *tm = (temp_time) ? gmtime(&temp_time) : nullptr;
3338 if (LIKELY(tm)) {
3339 strftime(build_commit_datetime, sizeof(build_commit_datetime), "%Y-%m-%d %H:%M", tm);
3340 }
3341 else {
3342 STRNCPY(build_commit_datetime, "unknown");
3343 }
3344
3345 CLOG_INFO(&LOG, 0, "Read file %s", fd->relabase);
3346 CLOG_INFO(&LOG,
3347 0,
3348 " Version %d sub %d date %s hash %s",
3349 main->versionfile,
3350 main->subversionfile,
3351 build_commit_datetime,
3352 main->build_hash);
3353 }
3354
3355 if (!main->is_read_invalid) {
3357 }
3358 if (!main->is_read_invalid) {
3360 }
3361 if (!main->is_read_invalid) {
3363 }
3364 if (!main->is_read_invalid) {
3366 }
3367 if (!main->is_read_invalid) {
3369 }
3370 if (!main->is_read_invalid) {
3372 }
3373 if (!main->is_read_invalid) {
3375 }
3376 if (!main->is_read_invalid) {
3378 }
3379 if (!main->is_read_invalid) {
3381 }
3382 if (!main->is_read_invalid) {
3384 }
3385 if (!main->is_read_invalid) {
3387 }
3388 if (!main->is_read_invalid) {
3390 }
3391 if (!main->is_read_invalid) {
3393 }
3394
3395 /* WATCH IT!!!: pointers from libdata have not been converted yet here! */
3396 /* WATCH IT 2!: #UserDef struct init see #do_versions_userdef() above! */
3397
3398 /* don't forget to set version number in BKE_blender_version.h! */
3399
3400 main->is_locked_for_linking = false;
3401}
3402
3404{
3405 BLI_assert(fd != nullptr);
3406
3407 CLOG_INFO(&LOG,
3408 2,
3409 "Processing %s (%s), %d.%d",
3410 main->curlib ? main->curlib->filepath : main->filepath,
3411 main->curlib ? "LIB" : "MAIN",
3412 main->versionfile,
3413 main->subversionfile);
3414
3415 /* Don't allow versioning to create new data-blocks. */
3416 main->is_locked_for_linking = true;
3417
3418 if (!main->is_read_invalid) {
3420 }
3421 if (!main->is_read_invalid) {
3423 }
3424 if (!main->is_read_invalid) {
3426 }
3427 if (!main->is_read_invalid) {
3429 }
3430 if (!main->is_read_invalid) {
3432 }
3433 if (!main->is_read_invalid) {
3435 }
3436 if (!main->is_read_invalid) {
3438 }
3439 if (!main->is_read_invalid) {
3441 }
3442 if (!main->is_read_invalid) {
3444 }
3445 if (!main->is_read_invalid) {
3447 }
3448 if (!main->is_read_invalid) {
3450 }
3451 if (!main->is_read_invalid) {
3453 }
3454
3455 main->is_locked_for_linking = false;
3456}
3457
3459
3460/* -------------------------------------------------------------------- */
3463
3465{
3466 /* Embedded IDs are not known by lib_link code, so they would be remapped to `nullptr`. But there
3467 * is no need to process them anyway, as they are already handled during the 'read_data' phase.
3468 *
3469 * NOTE: Some external non-owning pointers to embedded IDs (like the node-tree pointers of the
3470 * Node editor) will not be detected as embedded ones though at 'lib_link' stage (because their
3471 * source data cannot be accessed). This is handled on a case-by-case basis in 'after_lib_link'
3472 * validation code. */
3474 return IDWALK_RET_NOP;
3475 }
3476
3477 /* Explicitly requested to be ignored during readfile processing. Means the read_data code
3478 * already handled this pointer. Typically, the 'owner_id' pointer of an embedded ID. */
3479 if (cb_data->cb_flag & IDWALK_CB_READFILE_IGNORE) {
3480 return IDWALK_RET_NOP;
3481 }
3482
3483 BlendLibReader *reader = static_cast<BlendLibReader *>(cb_data->user_data);
3484 ID **id_ptr = cb_data->id_pointer;
3485 ID *owner_id = cb_data->owner_id;
3486
3487 *id_ptr = BLO_read_get_new_id_address(reader, owner_id, ID_IS_LINKED(owner_id), *id_ptr);
3488
3489 return IDWALK_RET_NOP;
3490}
3491
3492static void lib_link_all(FileData *fd, Main *bmain)
3493{
3494 BlendLibReader reader = {fd, bmain};
3495
3496 ID *id;
3497 FOREACH_MAIN_ID_BEGIN (bmain, id) {
3498 const IDTypeInfo *id_type = BKE_idtype_get_info_from_id(id);
3499
3501 {
3503 /* This ID has been re-used from 'old' bmain. Since it was therefore unchanged across
3504 * current undo step, and old IDs re-use their old memory address, we do not need to liblink
3505 * it at all. */
3507
3508 /* Some data that should be persistent, like the 3DCursor or the tool settings, are
3509 * stored in IDs affected by undo, like Scene. So this requires some specific handling. */
3510 /* NOTE: even though the ID may have been detected as unchanged, the 'undo_preserve' may have
3511 * to actually change some of its ID pointers, it's e.g. the case with Scene's tool-settings
3512 * Brush/Palette pointers. This is the case where both new and old ID may be the same. */
3513 if (id_type->blend_read_undo_preserve != nullptr) {
3515 id_type->blend_read_undo_preserve(&reader, id, id->orig_id ? id->orig_id : id);
3516 }
3517 continue;
3518 }
3519
3521 /* Not all original pointer values can be considered as valid.
3522 * Handling of DNA deprecated data should never be needed in undo case. */
3524 ((fd->flags & FD_FLAGS_IS_MEMFILE) ?
3525 IDWALK_NOP :
3527 BKE_library_foreach_ID_link(bmain, id, lib_link_cb, &reader, flag);
3528
3529 after_liblink_id_process(&reader, id);
3530
3532 }
3533
3534 /* Some data that should be persistent, like the 3DCursor or the tool settings, are
3535 * stored in IDs affected by undo, like Scene. So this requires some specific handling. */
3536 if (id_type->blend_read_undo_preserve != nullptr && id->orig_id != nullptr) {
3538 id_type->blend_read_undo_preserve(&reader, id, id->orig_id);
3539 }
3540 }
3542
3543 /* Cleanup `ID.orig_id`, this is now reserved for depsgraph/copy-on-eval usage only. */
3544 FOREACH_MAIN_ID_BEGIN (bmain, id) {
3545 id->orig_id = nullptr;
3546 }
3548
3549#ifndef NDEBUG
3550 /* Double check we do not have any 'need link' tag remaining, this should never be the case once
3551 * this function has run. */
3552 FOREACH_MAIN_ID_BEGIN (bmain, id) {
3554 }
3556#endif
3557}
3558
3565{
3566 /* We only expect a merged Main here, not a split one. */
3567 BLI_assert((bmain->prev == nullptr) && (bmain->next == nullptr));
3568
3569 if (!BKE_main_namemap_validate_and_fix(*bmain)) {
3570 BKE_report(
3571 reports ? reports->reports : nullptr,
3572 RPT_ERROR,
3573 "Critical blend-file corruption: Conflicts and/or otherwise invalid data-blocks names "
3574 "(see console for details)");
3575 }
3576
3577 /* Check for possible cycles in scenes' 'set' background property. */
3579
3580 /* We could integrate that to mesh/curve/lattice lib_link, but this is really cheap process,
3581 * so simpler to just use it directly in this single call. */
3582 BLO_main_validate_shapekeys(bmain, reports ? reports->reports : nullptr);
3583
3584 BLO_main_validate_embedded_flag(bmain, reports ? reports->reports : nullptr);
3585 BLO_main_validate_embedded_liboverrides(bmain, reports ? reports->reports : nullptr);
3586
3587 /* We have to rebuild that runtime information *after* all data-blocks have been properly linked.
3588 */
3590}
3591
3593
3594/* -------------------------------------------------------------------- */
3597
3599{
3600 BLO_read_struct(reader, IDProperty, &kmi->properties);
3601 IDP_BlendDataRead(reader, &kmi->properties);
3602 kmi->ptr = nullptr;
3603 kmi->flag &= ~KMI_UPDATE;
3604}
3605
3607{
3608 UserDef *user;
3609 bfd->user = user = static_cast<UserDef *>(
3610 read_struct(fd, bhead, "Data for User Def", INDEX_ID_NULL));
3611
3612 /* User struct has separate do-version handling */
3613 user->versionfile = bfd->main->versionfile;
3614 user->subversionfile = bfd->main->subversionfile;
3615
3616 /* read all data into fd->datamap */
3617 bhead = read_data_into_datamap(fd, bhead, "Data for User Def", INDEX_ID_NULL);
3618
3619 BlendDataReader reader_ = {fd};
3620 BlendDataReader *reader = &reader_;
3621
3622 BLO_read_struct_list(reader, bTheme, &user->themes);
3625 BLO_read_struct_list(reader, bUserMenu, &user->user_menus);
3626 BLO_read_struct_list(reader, bAddon, &user->addons);
3632
3633 LISTBASE_FOREACH (wmKeyMap *, keymap, &user->user_keymaps) {
3634 keymap->modal_items = nullptr;
3635 keymap->poll = nullptr;
3636 keymap->flag &= ~KEYMAP_UPDATE;
3637
3638 BLO_read_struct_list(reader, wmKeyMapDiffItem, &keymap->diff_items);
3639 BLO_read_struct_list(reader, wmKeyMapItem, &keymap->items);
3640
3641 LISTBASE_FOREACH (wmKeyMapDiffItem *, kmdi, &keymap->diff_items) {
3642 BLO_read_struct(reader, wmKeyMapItem, &kmdi->remove_item);
3643 BLO_read_struct(reader, wmKeyMapItem, &kmdi->add_item);
3644
3645 if (kmdi->remove_item) {
3646 direct_link_keymapitem(reader, kmdi->remove_item);
3647 }
3648 if (kmdi->add_item) {
3649 direct_link_keymapitem(reader, kmdi->add_item);
3650 }
3651 }
3652
3653 LISTBASE_FOREACH (wmKeyMapItem *, kmi, &keymap->items) {
3654 direct_link_keymapitem(reader, kmi);
3655 }
3656 }
3657
3659 BLO_read_struct(reader, IDProperty, &kpt->prop);
3660 IDP_BlendDataRead(reader, &kpt->prop);
3661 }
3662
3663 LISTBASE_FOREACH (bUserMenu *, um, &user->user_menus) {
3664 BLO_read_struct_list(reader, bUserMenuItem, &um->items);
3665 LISTBASE_FOREACH (bUserMenuItem *, umi, &um->items) {
3666 if (umi->type == USER_MENU_TYPE_OPERATOR) {
3667 bUserMenuItem_Op *umi_op = (bUserMenuItem_Op *)umi;
3668 BLO_read_struct(reader, IDProperty, &umi_op->prop);
3669 IDP_BlendDataRead(reader, &umi_op->prop);
3670 }
3671 }
3672 }
3673
3674 LISTBASE_FOREACH (bAddon *, addon, &user->addons) {
3675 BLO_read_struct(reader, IDProperty, &addon->prop);
3676 IDP_BlendDataRead(reader, &addon->prop);
3677 }
3678
3681 }
3682
3684 BKE_asset_catalog_path_list_blend_read_data(reader, shelf_settings->enabled_catalog_paths);
3685 }
3686
3687 /* XXX */
3688 user->uifonts.first = user->uifonts.last = nullptr;
3689
3690 BLO_read_struct_list(reader, uiStyle, &user->uistyles);
3691
3692 /* Don't read the active app template, use the default one. */
3693 user->app_template[0] = '\0';
3694
3695 /* Clear runtime data. */
3696 user->runtime.is_dirty = false;
3697 user->edit_studio_light = 0;
3698
3699 /* free fd->datamap again */
3701
3702 return bhead;
3703}
3704
3706
3707/* -------------------------------------------------------------------- */
3710
3712{
3714 return IDWALK_RET_NOP;
3715 }
3716
3717 IDNameLib_Map *new_idmap_uid = static_cast<IDNameLib_Map *>(cb_data->user_data);
3718 ID **id_pointer = cb_data->id_pointer;
3719 if (*id_pointer != nullptr) {
3720 *id_pointer = BKE_main_idmap_lookup_uid(new_idmap_uid, (*id_pointer)->session_uid);
3721 }
3722
3723 return IDWALK_RET_NOP;
3724}
3725
3726/* Remap 'no undo' ID usages to matching IDs in new main.
3727 *
3728 * 'no undo' IDs have simply be moved from old to new main so far. However, unlike the other
3729 * re-used IDs (the 'unchanged' ones), there is no guarantee that all the ID pointers they use are
3730 * still valid.
3731 *
3732 * This code performs a remapping based on the session_uid. */
3734{
3735 Main *new_bmain = static_cast<Main *>(fd->mainlist->first);
3736 ID *id_iter;
3737 FOREACH_MAIN_ID_BEGIN (new_bmain, id_iter) {
3738 if (ID_IS_LINKED(id_iter)) {
3739 continue;
3740 }
3741 if ((id_iter->tag & ID_TAG_UNDO_OLD_ID_REUSED_NOUNDO) == 0) {
3742 continue;
3743 }
3744
3747 }
3749}
3750
3755static void blo_read_file_checks(Main *bmain)
3756{
3757#ifndef NDEBUG
3758 BLI_assert(bmain->next == nullptr);
3759 BLI_assert(!bmain->is_read_invalid);
3760
3761 LISTBASE_FOREACH (wmWindowManager *, wm, &bmain->wm) {
3762 LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
3763 /* This pointer is deprecated and should always be nullptr. */
3764 BLI_assert(win->screen == nullptr);
3765 }
3766 }
3767#endif
3768 UNUSED_VARS_NDEBUG(bmain);
3769}
3770
3772{
3773 BHead *bhead = blo_bhead_first(fd);
3774 BlendFileData *bfd;
3775 ListBase mainlist = {nullptr, nullptr};
3776
3777 const bool is_undo = (fd->flags & FD_FLAGS_IS_MEMFILE) != 0;
3778 if (is_undo) {
3779 CLOG_INFO(&LOG_UNDO, 2, "UNDO: read step");
3780 }
3781
3782 /* Prevent any run of layer collections rebuild during readfile process, and the do_versions
3783 * calls.
3784 *
3785 * NOTE: Typically readfile code should not trigger such updates anyway. But some calls to
3786 * non-BLO functions (e.g. ID deletion) can indirectly trigger it. */
3788
3789 bfd = MEM_new<BlendFileData>(__func__);
3790
3791 bfd->main = BKE_main_new();
3792 bfd->main->versionfile = fd->fileversion;
3793 STRNCPY(bfd->filepath, filepath);
3794
3795 bfd->type = BLENFILETYPE_BLEND;
3796
3797 if ((fd->skip_flags & BLO_READ_SKIP_DATA) == 0) {
3798 BLI_addtail(&mainlist, bfd->main);
3799 fd->mainlist = &mainlist;
3800 STRNCPY(bfd->main->filepath, filepath);
3801 }
3802
3803 if (G.background) {
3804 /* We only read & store .blend thumbnail in background mode
3805 * (because we cannot re-generate it, no OpenGL available).
3806 */
3807 const int *data = read_file_thumbnail(fd);
3808
3809 if (data) {
3810 const int width = data[0];
3811 const int height = data[1];
3812 if (BLEN_THUMB_MEMSIZE_IS_VALID(width, height)) {
3813 const size_t data_size = BLEN_THUMB_MEMSIZE(width, height);
3814 bfd->main->blen_thumb = static_cast<BlendThumbnail *>(MEM_mallocN(data_size, __func__));
3815
3816 BLI_assert((data_size - sizeof(*bfd->main->blen_thumb)) ==
3817 (BLEN_THUMB_MEMSIZE_FILE(width, height) - (sizeof(*data) * 2)));
3818 bfd->main->blen_thumb->width = width;
3819 bfd->main->blen_thumb->height = height;
3820 memcpy(bfd->main->blen_thumb->rect, &data[2], data_size - sizeof(*bfd->main->blen_thumb));
3821 }
3822 }
3823 }
3824
3825 if (is_undo) {
3826 /* This idmap will store UIDs of all IDs ending up in the new main, whether they are newly
3827 * read, or re-used from the old main. */
3829 static_cast<Main *>(fd->mainlist->first), false, nullptr, MAIN_IDMAP_TYPE_UID);
3830
3831 /* Copy all 'no undo' local data from old to new bmain. */
3833 }
3834
3835 while (bhead) {
3836 switch (bhead->code) {
3837 case BLO_CODE_DATA:
3838 case BLO_CODE_DNA1:
3839 case BLO_CODE_TEST: /* used as preview since 2.5x */
3840 case BLO_CODE_REND:
3841 bhead = blo_bhead_next(fd, bhead);
3842 break;
3843 case BLO_CODE_GLOB:
3844 bhead = read_global(bfd, fd, bhead);
3845 break;
3846 case BLO_CODE_USER:
3848 bhead = blo_bhead_next(fd, bhead);
3849 }
3850 else {
3851 bhead = read_userdef(bfd, fd, bhead);
3852 }
3853 break;
3854 case BLO_CODE_ENDB:
3855 bhead = nullptr;
3856 break;
3857
3859 if (fd->skip_flags & BLO_READ_SKIP_DATA) {
3860 bhead = blo_bhead_next(fd, bhead);
3861 }
3862 else {
3863 /* Add link placeholder to the main of the library it belongs to.
3864 * The library is the most recently loaded ID_LI block, according
3865 * to the file format definition. So we can use the entry at the
3866 * end of mainlist, added in direct_link_library. */
3867 Main *libmain = static_cast<Main *>(mainlist.last);
3868 bhead = read_libblock(fd, libmain, bhead, 0, {}, true, nullptr);
3869 }
3870 break;
3871 /* in 2.50+ files, the file identifier for screens is patched, forward compatibility */
3872 case ID_SCRN:
3873 bhead->code = ID_SCR;
3874 /* pass on to default */
3876 default: {
3877 if (blo_bhead_is_id_valid_type(bhead)) {
3878 /* BHead is a valid known ID type one, read the whole ID and its sub-data, unless reading
3879 * actual data is skipped. */
3880 if (fd->skip_flags & BLO_READ_SKIP_DATA) {
3881 bhead = blo_bhead_next(fd, bhead);
3882 }
3883 else {
3884 bhead = read_libblock(fd, bfd->main, bhead, ID_TAG_LOCAL, {}, false, nullptr);
3885 }
3886 }
3887 else {
3888 /* Unknown BHead type (or ID type), ignore it and skip to next BHead. */
3889 bhead = blo_bhead_next(fd, bhead);
3890 }
3891 }
3892 }
3893
3894 if (bfd->main->is_read_invalid) {
3895 return bfd;
3896 }
3897 }
3898
3899 if (is_undo) {
3900 /* Move the remaining Library IDs and their linked data to the new main.
3901 *
3902 * NOTE: These linked IDs have not been detected as used in newly read main. However, they
3903 * could be dependencies from some 'no undo' IDs that were unconditionally moved from the old
3904 * to the new main.
3905 *
3906 * While there could be some more refined check here to detect such cases and only move these
3907 * into the new bmain, in practice it is simpler to systematically move all linked data. The
3908 * handling of libraries already moves all their linked IDs too, regardless of whether they are
3909 * effectively used or not. */
3910
3911 Main *new_main = bfd->main;
3912 Main *old_main = static_cast<Main *>(fd->old_mainlist->first);
3913 BLI_assert(old_main != nullptr);
3914 BLI_assert(old_main->curlib == nullptr);
3915 Main *libmain, *libmain_next;
3916 for (libmain = old_main->next; libmain != nullptr; libmain = libmain_next) {
3917 libmain_next = libmain->next;
3918 read_undo_move_libmain_data(fd, new_main, old_main, libmain, nullptr);
3919 }
3920 }
3921
3922 /* Ensure fully valid and unique ID names before calling first stage of versioning. */
3923 if (!is_undo && (fd->flags & FD_FLAGS_HAS_INVALID_ID_NAMES) != 0) {
3925
3929 "Blendfile '%s' was created by a future version of Blender and contains ID "
3930 "names longer than currently supported. These have been truncated.",
3931 bfd->filepath);
3932 }
3933 else {
3935 RPT_ERROR,
3936 "Blendfile '%s' appears corrupted, it contains invalid ID names. These have "
3937 "been truncated.",
3938 bfd->filepath);
3939 }
3940
3941 /* This part is only to ensure forward compatibility with 5.0+ blend-files in 4.5.
3942 * It will be removed in 5.0. */
3944 }
3945 else {
3946 /* Getting invalid ID names from memfile undo data would be a critical error. */
3948 if ((fd->flags & FD_FLAGS_HAS_INVALID_ID_NAMES) != 0) {
3949 bfd->main->is_read_invalid = true;
3950 }
3951 }
3952
3953 if (bfd->main->is_read_invalid) {
3954 return bfd;
3955 }
3956
3957 /* Do versioning before read_libraries, but skip in undo case. */
3958 if (!is_undo) {
3959 if ((fd->skip_flags & BLO_READ_SKIP_DATA) == 0) {
3960 do_versions(fd, nullptr, bfd->main);
3961 }
3962
3963 if ((fd->skip_flags & BLO_READ_SKIP_USERDEF) == 0) {
3964 do_versions_userdef(fd, bfd);
3965 }
3966 }
3967
3968 if (bfd->main->is_read_invalid) {
3969 return bfd;
3970 }
3971
3972 if ((fd->skip_flags & BLO_READ_SKIP_DATA) == 0) {
3974 read_libraries(fd, &mainlist);
3975
3976 blo_join_main(&mainlist);
3977
3978 lib_link_all(fd, bfd->main);
3980
3981 if (is_undo) {
3982 /* Ensure ID usages of reused 'no undo' IDs remain valid. */
3983 /* Although noundo data was reused as-is from the old main, it may have ID pointers to data
3984 * that has been removed, or that have a new address. */
3986 }
3987
3989
3990 /* Skip in undo case. */
3991 if (!is_undo) {
3992 /* Note that we can't recompute user-counts at this point in undo case, we play too much with
3993 * IDs from different memory realms, and Main database is not in a fully valid state yet.
3994 */
3995 /* Some versioning code does expect some proper user-reference-counting, e.g. in conversion
3996 * from groups to collections... We could optimize out that first call when we are reading a
3997 * current version file, but again this is really not a bottle neck currently.
3998 * So not worth it. */
4000
4001 /* Necessary to allow 2.80 layer collections conversion code to work. */
4003
4004 /* Yep, second splitting... but this is a very cheap operation, so no big deal. */
4005 blo_split_main(&mainlist, bfd->main);
4006 LISTBASE_FOREACH (Main *, mainvar, &mainlist) {
4007 /* Do versioning for newly added linked data-blocks. If no data-blocks were read from a
4008 * library versionfile will still be zero and we can skip it. */
4009 if (mainvar->versionfile == 0) {
4010 continue;
4011 }
4012 do_versions_after_linking((mainvar->curlib && mainvar->curlib->runtime->filedata) ?
4013 mainvar->curlib->runtime->filedata :
4014 fd,
4015 mainvar);
4016 }
4017 blo_join_main(&mainlist);
4018
4020
4021 /* And we have to compute those user-reference-counts again, as `do_versions_after_linking()`
4022 * does not always properly handle user counts, and/or that function does not take into
4023 * account old, deprecated data. */
4025 }
4026
4028 /* Now we can clear this runtime library filedata, it is not needed anymore. */
4029 if (lib->runtime->filedata) {
4030 BLI_assert(lib->runtime->versionfile != 0);
4031 blo_filedata_free(lib->runtime->filedata);
4032 lib->runtime->filedata = nullptr;
4033 }
4034 /* If no data-blocks were read from a library (should only happen when all references to a
4035 * library's data are `ID_FLAG_INDIRECT_WEAK_LINK`), its versionfile will still be zero and
4036 * it can be deleted.
4037 *
4038 * NOTES:
4039 * - In case the library blendfile exists but is missing all the referenced linked IDs, the
4040 * placeholders IDs created will reference the library ID, and the library ID will have a
4041 * valid version number as the file was read to search for the linked IDs.
4042 * - In case the library blendfile does not exist, its local Library ID will get the version
4043 * of the current local Main (i.e. the loaded blendfile). */
4044 else if (lib->runtime->versionfile == 0) {
4045#ifndef NDEBUG
4046 ID *id_iter;
4047 FOREACH_MAIN_ID_BEGIN (bfd->main, id_iter) {
4048 BLI_assert(id_iter->lib != lib);
4049 }
4051#endif
4052 BKE_id_delete(bfd->main, lib);
4053 }
4054 }
4055
4056 if (bfd->main->is_read_invalid) {
4057 return bfd;
4058 }
4059
4060 /* After all data has been read and versioned, uses ID_TAG_NEW. Theoretically this should
4061 * not be calculated in the undo case, but it is currently needed even on undo to recalculate
4062 * a cache. */
4064
4066
4067 BKE_main_id_tag_all(bfd->main, ID_TAG_NEW, false);
4068
4069 /* Must happen before applying liboverrides, as this process may fully invalidate e.g. view
4070 * layer pointers in case a Scene is a liboverride. */
4071 link_global(fd, bfd);
4072
4073 /* Now that all our data-blocks are loaded,
4074 * we can re-generate overrides from their references. */
4075 if (!is_undo) {
4076 /* Do not apply in undo case! */
4078
4079 std::string cur_view_layer_name = bfd->cur_view_layer != nullptr ?
4080 bfd->cur_view_layer->name :
4081 "";
4082
4085
4086 /* In case the current scene is a liboverride, while the ID pointer itself remains valid,
4087 * above update of liboverrides will have completely invalidated its old content, so the
4088 * current view-layer needs to be searched for again. */
4089 if (bfd->cur_view_layer != nullptr) {
4090 bfd->cur_view_layer = BKE_view_layer_find(bfd->curscene, cur_view_layer_name.c_str());
4091 }
4092
4093 /* FIXME Temporary 'fix' to a problem in how temp ID are copied in
4094 * `BKE_lib_override_library_main_update`, see #103062.
4095 * Proper fix involves first addressing #90610. */
4097
4098 /* Update invariants after re-generating overrides. */
4100
4103 }
4104
4106
4108
4109 /* Make all relative paths, relative to the open blend file. */
4111 }
4112 else {
4114 }
4115
4116 fd->mainlist = nullptr; /* Safety, this is local variable, shall not be used afterward. */
4117
4118 BLI_assert(bfd->main->id_map == nullptr);
4119
4120 /* Sanity checks. */
4122
4123 return bfd;
4124}
4125
4127
4128/* -------------------------------------------------------------------- */
4133
4136 const void *old;
4137};
4138
4139static int verg_bheadsort(const void *v1, const void *v2)
4140{
4141 const BHeadSort *x1 = static_cast<const BHeadSort *>(v1),
4142 *x2 = static_cast<const BHeadSort *>(v2);
4143
4144 if (x1->old > x2->old) {
4145 return 1;
4146 }
4147 if (x1->old < x2->old) {
4148 return -1;
4149 }
4150 return 0;
4151}
4152
4154{
4155 BHead *bhead;
4156 BHeadSort *bhs;
4157 int tot = 0;
4158
4159 for (bhead = blo_bhead_first(fd); bhead; bhead = blo_bhead_next(fd, bhead)) {
4160 tot++;
4161 }
4162
4163 fd->tot_bheadmap = tot;
4164 if (tot == 0) {
4165 return;
4166 }
4167
4168 bhs = fd->bheadmap = MEM_malloc_arrayN<BHeadSort>(tot, "BHeadSort");
4169
4170 for (bhead = blo_bhead_first(fd); bhead; bhead = blo_bhead_next(fd, bhead), bhs++) {
4171 bhs->bhead = bhead;
4172 bhs->old = bhead->old;
4173 }
4174
4175 qsort(fd->bheadmap, tot, sizeof(BHeadSort), verg_bheadsort);
4176}
4177
4179{
4180 /* Skip library data-blocks in undo, see comment in read_libblock. */
4181 if (fd->flags & FD_FLAGS_IS_MEMFILE) {
4182 return nullptr;
4183 }
4184
4185 for (; bhead; bhead = blo_bhead_prev(fd, bhead)) {
4186 if (bhead->code == ID_LI) {
4187 break;
4188 }
4189 }
4190
4191 return bhead;
4192}
4193
4194static BHead *find_bhead(FileData *fd, void *old)
4195{
4196#if 0
4197 BHead *bhead;
4198#endif
4199 BHeadSort *bhs, bhs_s;
4200
4201 if (!old) {
4202 return nullptr;
4203 }
4204
4205 if (fd->bheadmap == nullptr) {
4207 }
4208
4209 bhs_s.old = old;
4210 bhs = static_cast<BHeadSort *>(
4211 bsearch(&bhs_s, fd->bheadmap, fd->tot_bheadmap, sizeof(BHeadSort), verg_bheadsort));
4212
4213 if (bhs) {
4214 return bhs->bhead;
4215 }
4216
4217#if 0
4218 for (bhead = blo_bhead_first(fd); bhead; bhead = blo_bhead_next(fd, bhead)) {
4219 if (bhead->old == old) {
4220 return bhead;
4221 }
4222 }
4223#endif
4224
4225 return nullptr;
4226}
4227
4228static BHead *find_bhead_from_code_name(FileData *fd, const short idcode, const char *name)
4229{
4230 char idname_full[MAX_ID_NAME];
4231 *((short *)idname_full) = idcode;
4232 BLI_strncpy(idname_full + 2, name, sizeof(idname_full) - 2);
4233
4234 return fd->bhead_idname_map->lookup_default(idname_full, nullptr);
4235}
4236
4237static BHead *find_bhead_from_idname(FileData *fd, const char *idname)
4238{
4239 BHead *bhead = fd->bhead_idname_map->lookup_default(idname, nullptr);
4240 if (LIKELY(bhead)) {
4241 return bhead;
4242 }
4243
4244 /* Expected ID was not found, attempt to load the same name, but for an older, deprecated and
4245 * converted ID type. */
4246 const short id_code_old = do_versions_new_to_old_idcode_get(GS(idname));
4247 if (id_code_old == ID_LINK_PLACEHOLDER) {
4248 return bhead;
4249 }
4250 return find_bhead_from_code_name(fd, id_code_old, idname + 2);
4251}
4252
4253static ID *library_id_is_yet_read(FileData *fd, Main *mainvar, BHead *bhead)
4254{
4255 if (mainvar->id_map == nullptr) {
4256 mainvar->id_map = BKE_main_idmap_create(mainvar, false, nullptr, MAIN_IDMAP_TYPE_NAME);
4257 }
4258 BLI_assert(BKE_main_idmap_main_get(mainvar->id_map) == mainvar);
4259
4260 const char *idname = blo_bhead_id_name(fd, bhead);
4261 if (!idname) {
4262 return nullptr;
4263 }
4264
4265 ID *id = BKE_main_idmap_lookup_name(mainvar->id_map, GS(idname), idname + 2, mainvar->curlib);
4266 BLI_assert(id == BLI_findstring(which_libbase(mainvar, GS(idname)), idname, offsetof(ID, name)));
4267 return id;
4268}
4269
4272 const bool has_forward_compatibility_issues,
4273 const char *filepath)
4274{
4275 if (!fd || (fd->flags & FD_FLAGS_HAS_INVALID_ID_NAMES) == 0) {
4276 return;
4277 }
4278 if (has_forward_compatibility_issues) {
4281 "Library '%s' was created by a future version of Blender and contains ID names "
4282 "longer than currently supported. This may cause missing linked data, consider "
4283 "opening and re-saving that library with the current Blender version.",
4284 filepath);
4285 }
4286 else {
4288 RPT_ERROR,
4289 "Library '%s' appears corrupted, it contains invalid ID names. This may cause "
4290 "missing linked data.",
4291 filepath);
4292 }
4293}
4294
4296
4297/* -------------------------------------------------------------------- */
4300
4306
4307static void expand_doit_library(void *fdhandle, Main *mainvar, void *old)
4308{
4309 FileData *fd = static_cast<FileData *>(fdhandle);
4310
4311 if (mainvar->is_read_invalid) {
4312 return;
4313 }
4314
4315 BHead *bhead = find_bhead(fd, old);
4316 if (bhead == nullptr) {
4317 return;
4318 }
4319 /* In 2.50+ file identifier for screens is patched, forward compatibility. */
4320 if (bhead->code == ID_SCRN) {
4321 bhead->code = ID_SCR;
4322 }
4323 if (!blo_bhead_is_id_valid_type(bhead)) {
4324 return;
4325 }
4326 if (!blo_bhead_id_name(fd, bhead)) {
4327 /* Do not allow linking ID which names are invalid (likely coming from a future version of
4328 * Blender allowing longer names). */
4329 return;
4330 }
4331
4332 if (bhead->code == ID_LINK_PLACEHOLDER) {
4333 /* Placeholder link to data-block in another library. */
4334 BHead *bheadlib = find_previous_lib(fd, bhead);
4335 if (bheadlib == nullptr) {
4336 return;
4337 }
4338
4339 Library *lib = reinterpret_cast<Library *>(
4340 read_id_struct(fd, bheadlib, "Data for Library ID type", INDEX_ID_NULL));
4341 Main *libmain = blo_find_main(fd, lib->filepath, fd->relabase);
4342
4343 if (libmain->curlib == nullptr) {
4344 const char *idname = blo_bhead_id_name(fd, bhead);
4345
4348 RPT_("LIB: Data refers to main .blend file: '%s' from %s"),
4349 idname ? idname : "<InvalidIDName>",
4350 mainvar->curlib->runtime->filepath_abs);
4351 return;
4352 }
4353
4354 ID *id = library_id_is_yet_read(fd, libmain, bhead);
4355
4356 if (id == nullptr) {
4357 /* ID has not been read yet, add placeholder to the main of the
4358 * library it belongs to, so that it will be read later. */
4359 read_libblock(fd, libmain, bhead, fd->id_tag_extra | ID_TAG_INDIRECT, {}, false, &id);
4360 BLI_assert(id != nullptr);
4361 id_sort_by_name(which_libbase(libmain, GS(id->name)), id, static_cast<ID *>(id->prev));
4362
4363 /* commented because this can print way too much */
4364 // if (G.debug & G_DEBUG) printf("expand_doit: other lib %s\n", lib->filepath);
4365
4366 /* for outliner dependency only */
4367 libmain->curlib->runtime->parent = mainvar->curlib;
4368 }
4369 else {
4370 /* Convert any previously read weak link to regular link
4371 * to signal that we want to read this data-block. */
4373 id->flag &= ~ID_FLAG_INDIRECT_WEAK_LINK;
4374 }
4375
4376 /* "id" is either a placeholder or real ID that is already in the
4377 * main of the library (A) it belongs to. However it might have been
4378 * put there by another library (C) which only updated its own
4379 * fd->libmap. In that case we also need to update the fd->libmap
4380 * of the current library (B) so we can find it for lookups.
4381 *
4382 * An example of such a setup is:
4383 * (A) tree.blend: contains Tree object.
4384 * (B) forest.blend: contains Forest collection linking in Tree from tree.blend.
4385 * (C) shot.blend: links in both Tree from tree.blend and Forest from forest.blend.
4386 */
4387 oldnewmap_lib_insert(fd, bhead->old, id, bhead->code);
4388
4389 /* Commented because this can print way too much. */
4390#if 0
4391 if (G.debug & G_DEBUG) {
4392 printf("expand_doit: already linked: %s lib: %s\n", id->name, lib->filepath);
4393 }
4394#endif
4395 }
4396
4397 MEM_freeN(lib);
4398 }
4399 else {
4400 /* Data-block in same library. */
4401 ID *id = library_id_is_yet_read(fd, mainvar, bhead);
4402 if (id == nullptr) {
4403 ID_Readfile_Data::Tags id_read_tags{};
4404 id_read_tags.needs_expanding = true;
4406 fd, mainvar, bhead, fd->id_tag_extra | ID_TAG_INDIRECT, id_read_tags, false, &id);
4407 BLI_assert(id != nullptr);
4408 id_sort_by_name(which_libbase(mainvar, GS(id->name)), id, static_cast<ID *>(id->prev));
4409 }
4410 else {
4411 /* Convert any previously read weak link to regular link to signal that we want to read this
4412 * data-block. Note that this function also visits already-loaded data-blocks, and thus their
4413 * `readfile_data` field might already have been freed. */
4415 id->flag &= ~ID_FLAG_INDIRECT_WEAK_LINK;
4416 }
4417
4418 /* this is actually only needed on UI call? when ID was already read before,
4419 * and another append happens which invokes same ID...
4420 * in that case the lookup table needs this entry */
4421 oldnewmap_lib_insert(fd, bhead->old, id, bhead->code);
4422 /* commented because this can print way too much */
4423 // if (G.debug & G_DEBUG) printf("expand: already read %s\n", id->name);
4424 }
4425 }
4426}
4427
4429{
4430 /* Embedded IDs are not known by lib_link code, so they would be remapped to `nullptr`. But there
4431 * is no need to process them anyway, as they are already handled during the 'read_data' phase.
4432 */
4434 return IDWALK_RET_NOP;
4435 }
4436
4437 /* Explicitly requested to be ignored during readfile processing. Means the read_data code
4438 * already handled this pointer. Typically, the 'owner_id' pointer of an embedded ID. */
4439 if (cb_data->cb_flag & IDWALK_CB_READFILE_IGNORE) {
4440 return IDWALK_RET_NOP;
4441 }
4442
4443 /* Expand process can be re-entrant or have other complex interactions that will not work well
4444 * with loop-back pointers. Further more, processing such data should not be needed here anyway.
4445 */
4446 if (cb_data->cb_flag & (IDWALK_CB_LOOPBACK)) {
4447 return IDWALK_RET_NOP;
4448 }
4449
4450 BlendExpander *expander = static_cast<BlendExpander *>(cb_data->user_data);
4451 ID *id = *(cb_data->id_pointer);
4452
4453 expander->callback(expander->fd, expander->main, id);
4454
4455 return IDWALK_RET_NOP;
4456}
4457
4458void BLO_expand_main(void *fdhandle, Main *mainvar, BLOExpandDoitCallback callback)
4459{
4460 FileData *fd = static_cast<FileData *>(fdhandle);
4461 BlendExpander expander = {fd, mainvar, callback};
4462
4463 for (bool do_it = true; do_it;) {
4464 do_it = false;
4465 ID *id_iter;
4466
4467 FOREACH_MAIN_ID_BEGIN (mainvar, id_iter) {
4469 continue;
4470 }
4471
4472 /* Original (current) ID pointer can be considered as valid, but _not_ its own pointers to
4473 * other IDs - the already loaded ones will be valid, but the yet-to-be-read ones will not.
4474 * Expanding should _not_ require processing of UI ID pointers.
4475 * Expanding should never modify ID pointers themselves.
4476 * Handling of DNA deprecated data should never be needed in undo case. */
4478 ((!fd || (fd->flags & FD_FLAGS_IS_MEMFILE)) ?
4479 IDWALK_NOP :
4481 BKE_library_foreach_ID_link(nullptr, id_iter, expand_cb, &expander, flag);
4482
4483 do_it = true;
4485 }
4487 }
4488}
4489
4491
4492/* -------------------------------------------------------------------- */
4495
4496/* returns true if the item was found
4497 * but it may already have already been appended/linked */
4499 Main *mainl, FileData *fd, const short idcode, const char *name, const int flag)
4500{
4501 BHead *bhead = find_bhead_from_code_name(fd, idcode, name);
4502 ID *id;
4503
4504 const bool use_placeholders = (flag & BLO_LIBLINK_USE_PLACEHOLDERS) != 0;
4505 const bool force_indirect = (flag & BLO_LIBLINK_FORCE_INDIRECT) != 0;
4506
4508
4509 if (bhead && blo_bhead_is_id_valid_type(bhead)) {
4510 id = library_id_is_yet_read(fd, mainl, bhead);
4511 if (id == nullptr) {
4512 /* not read yet */
4513 const int tag = ((force_indirect ? ID_TAG_INDIRECT : ID_TAG_EXTERN) | fd->id_tag_extra);
4514 ID_Readfile_Data::Tags id_read_tags{};
4515 id_read_tags.needs_expanding = true;
4516 read_libblock(fd, mainl, bhead, tag, id_read_tags, false, &id);
4517
4518 if (id) {
4519 /* sort by name in list */
4520 ListBase *lb = which_libbase(mainl, idcode);
4521 id_sort_by_name(lb, id, nullptr);
4522 }
4523 }
4524 else {
4525 /* already linked */
4526 CLOG_WARN(&LOG, "Append: ID '%s' is already linked", id->name);
4527 oldnewmap_lib_insert(fd, bhead->old, id, bhead->code);
4528 if (!force_indirect && (id->tag & ID_TAG_INDIRECT)) {
4529 id->tag &= ~ID_TAG_INDIRECT;
4530 id->flag &= ~ID_FLAG_INDIRECT_WEAK_LINK;
4531 id->tag |= ID_TAG_EXTERN;
4532 }
4533 }
4534 }
4535 else if (use_placeholders) {
4536 /* XXX flag part is weak! */
4537 id = create_placeholder(
4538 mainl, idcode, name, force_indirect ? ID_TAG_INDIRECT : ID_TAG_EXTERN, false);
4539 }
4540 else {
4541 id = nullptr;
4542 }
4543
4544 /* NOTE: `id` may be `nullptr` even if a BHead was found, in case e.g. it is an invalid BHead. */
4545
4546 return id;
4547}
4548
4550 BlendHandle **bh,
4551 const short idcode,
4552 const char *name,
4554{
4555 FileData *fd = (FileData *)(*bh);
4556
4557 ID *ret_id = nullptr;
4558 if (!mainl->is_read_invalid) {
4559 ret_id = link_named_part(mainl, fd, idcode, name, params->flag);
4560 }
4561
4562 if (mainl->is_read_invalid) {
4563 return nullptr;
4564 }
4565 return ret_id;
4566}
4567
4568/* common routine to append/link something from a library */
4569
4571 FileData *fd,
4572 const char *filepath,
4573 const int id_tag_extra)
4574{
4575 Main *mainl;
4576
4577 /* Only allow specific tags to be set as extra,
4578 * otherwise this could conflict with library loading logic.
4579 * Other flags can be added here, as long as they are safe. */
4580 BLI_assert((id_tag_extra & ~ID_TAG_TEMP_MAIN) == 0);
4581
4582 fd->id_tag_extra = id_tag_extra;
4583
4584 fd->mainlist = MEM_callocN<ListBase>("FileData.mainlist");
4585
4586 /* make mains */
4587 blo_split_main(fd->mainlist, mainvar);
4588
4589 /* which one do we need? */
4590 mainl = blo_find_main(fd, filepath, BKE_main_blendfile_path(mainvar));
4591 if (mainl->curlib) {
4592 mainl->curlib->runtime->filedata = fd;
4593 }
4594
4595 /* needed for do_version */
4596 mainl->versionfile = short(fd->fileversion);
4597 read_file_version(fd, mainl);
4599
4600 return mainl;
4601}
4602
4604 Main *bmain,
4605 const int flag,
4606 const int id_tag_extra)
4607{
4608 memset(params, 0, sizeof(*params));
4609 params->bmain = bmain;
4610 params->flag = flag;
4611 params->id_tag_extra = id_tag_extra;
4612}
4613
4615 Main *bmain,
4616 const int flag,
4617 const int id_tag_extra,
4618 /* Context arguments. */
4619 Scene *scene,
4620 ViewLayer *view_layer,
4621 const View3D *v3d)
4622{
4623 BLO_library_link_params_init(params, bmain, flag, id_tag_extra);
4624 if (scene != nullptr) {
4625 params->context.scene = scene;
4626 params->context.view_layer = view_layer;
4627 params->context.v3d = v3d;
4628 }
4629}
4630
4632 const char *filepath,
4634{
4635 FileData *fd = reinterpret_cast<FileData *>(*bh);
4636 return library_link_begin(params->bmain, fd, filepath, params->id_tag_extra);
4637}
4638
4639static void split_main_newid(Main *mainptr, Main *main_newid)
4640{
4641 /* We only copy the necessary subset of data in this temp main. */
4642 main_newid->versionfile = mainptr->versionfile;
4643 main_newid->subversionfile = mainptr->subversionfile;
4644 STRNCPY(main_newid->filepath, mainptr->filepath);
4645 main_newid->curlib = mainptr->curlib;
4646
4647 MainListsArray lbarray = BKE_main_lists_get(*mainptr);
4648 MainListsArray lbarray_newid = BKE_main_lists_get(*main_newid);
4649 int i = lbarray.size();
4650 while (i--) {
4651 BLI_listbase_clear(lbarray_newid[i]);
4652
4653 LISTBASE_FOREACH_MUTABLE (ID *, id, lbarray[i]) {
4654 if (id->tag & ID_TAG_NEW) {
4655 BLI_remlink(lbarray[i], id);
4656 BLI_addtail(lbarray_newid[i], id);
4657 }
4658 }
4659 }
4660}
4661
4662static void library_link_end(Main *mainl, FileData **fd, const int flag, ReportList *reports)
4663{
4664 Main *mainvar;
4665 Library *curlib;
4666
4667 if (mainl->id_map == nullptr) {
4668 mainl->id_map = BKE_main_idmap_create(mainl, false, nullptr, MAIN_IDMAP_TYPE_NAME);
4669 }
4670
4671 /* make main consistent */
4673
4675 *fd, reports, mainl->has_forward_compatibility_issues, mainl->curlib->runtime->filepath_abs);
4676
4677 /* Do this when expand found other libraries. */
4678 read_libraries(*fd, (*fd)->mainlist);
4679
4680 curlib = mainl->curlib;
4681
4682 /* make the lib path relative if required */
4683 if (flag & FILE_RELPATH) {
4684 /* use the full path, this could have been read by other library even */
4685 STRNCPY(curlib->filepath, curlib->runtime->filepath_abs);
4686
4687 /* uses current .blend file as reference */
4689 }
4690
4691 blo_join_main((*fd)->mainlist);
4692 mainvar = static_cast<Main *>((*fd)->mainlist->first);
4693 mainl = nullptr; /* blo_join_main free's mainl, can't use anymore */
4694
4695 if (mainvar->is_read_invalid) {
4696 return;
4697 }
4698
4699 lib_link_all(*fd, mainvar);
4700 after_liblink_merged_bmain_process(mainvar, (*fd)->reports);
4701
4702 /* Some versioning code does expect some proper userrefcounting, e.g. in conversion from
4703 * groups to collections... We could optimize out that first call when we are reading a
4704 * current version file, but again this is really not a bottle neck currently. So not worth
4705 * it. */
4706 BKE_main_id_refcount_recompute(mainvar, false);
4707
4708 /* FIXME: This is suspiciously early call compared to similar process in
4709 * #blo_read_file_internal, where it is called towards the very end, after all do_version,
4710 * liboverride updates etc. have been done. */
4711 /* FIXME: Probably also need to forbid layer collections updates until this call, as done in
4712 * #blo_read_file_internal? */
4714
4715 /* Yep, second splitting... but this is a very cheap operation, so no big deal. */
4716 blo_split_main((*fd)->mainlist, mainvar);
4717 Main *main_newid = BKE_main_new();
4718 for (mainvar = ((Main *)(*fd)->mainlist->first)->next; mainvar; mainvar = mainvar->next) {
4719 BLI_assert(mainvar->versionfile != 0);
4720 /* We need to split out IDs already existing,
4721 * or they will go again through do_versions - bad, very bad! */
4722 split_main_newid(mainvar, main_newid);
4723
4724 do_versions_after_linking((main_newid->curlib && main_newid->curlib->runtime->filedata) ?
4725 main_newid->curlib->runtime->filedata :
4726 *fd,
4727 main_newid);
4728
4729 add_main_to_main(mainvar, main_newid);
4730
4731 if (mainvar->is_read_invalid) {
4732 break;
4733 }
4734 }
4735
4736 blo_join_main((*fd)->mainlist);
4737 mainvar = static_cast<Main *>((*fd)->mainlist->first);
4738 MEM_freeN((*fd)->mainlist);
4739
4740 if (mainvar->is_read_invalid) {
4741 BKE_main_free(main_newid);
4742 return;
4743 }
4744
4745 /* This does not take into account old, deprecated data, so we also have to do it after
4746 * `do_versions_after_linking()`. */
4747 BKE_main_id_refcount_recompute(mainvar, false);
4748
4749 /* After all data has been read and versioned, uses ID_TAG_NEW. */
4751
4753
4754 /* Apply overrides of newly linked data if needed. Already existing IDs need to split out, to
4755 * avoid re-applying their own overrides. */
4756 BLI_assert(BKE_main_is_empty(main_newid));
4757 split_main_newid(mainvar, main_newid);
4758 BKE_lib_override_library_main_validate(main_newid, (*fd)->reports->reports);
4760 add_main_to_main(mainvar, main_newid);
4761 BKE_main_free(main_newid);
4762
4763 BKE_main_id_tag_all(mainvar, ID_TAG_NEW, false);
4764
4765 /* FIXME Temporary 'fix' to a problem in how temp ID are copied in
4766 * `BKE_lib_override_library_main_update`, see #103062.
4767 * Proper fix involves first addressing #90610. */
4770 }
4771
4772 /* Make all relative paths, relative to the open blend file. */
4774
4775 /* patch to prevent switch_endian happens twice */
4776 /* FIXME This is extremely bad design, #library_link_end should probably _always_ free the file
4777 * data? */
4778 if ((*fd)->flags & FD_FLAGS_SWITCH_ENDIAN) {
4779 blo_filedata_free(*fd);
4780 *fd = nullptr;
4781 }
4782
4783 /* Sanity checks. */
4784 blo_read_file_checks(mainvar);
4785}
4786
4788 BlendHandle **bh,
4791{
4792 FileData *fd = reinterpret_cast<FileData *>(*bh);
4793
4794 if (!mainl->is_read_invalid) {
4795 library_link_end(mainl, &fd, params->flag, reports);
4796 }
4797
4798 LISTBASE_FOREACH (Library *, lib, &params->bmain->libraries) {
4799 /* Now we can clear this runtime library filedata, it is not needed anymore. */
4800 if (lib->runtime->filedata == reinterpret_cast<FileData *>(*bh)) {
4801 /* The filedata is owned and managed by caller code, only clear matching library pointer. */
4802 lib->runtime->filedata = nullptr;
4803 }
4804 else if (lib->runtime->filedata) {
4805 /* In case other libraries had to be read as dependencies of the main linked one, they need
4806 * to be cleared here.
4807 *
4808 * TODO: In the future, could be worth keeping them in case data are linked from several
4809 * libraries at once? To avoid closing and re-opening the same file several times. Would need
4810 * a global cleanup callback then once all linking is done, though. */
4811 blo_filedata_free(lib->runtime->filedata);
4812 lib->runtime->filedata = nullptr;
4813 }
4814 }
4815
4816 *bh = reinterpret_cast<BlendHandle *>(fd);
4817}
4818
4819void *BLO_library_read_struct(FileData *fd, BHead *bh, const char *blockname)
4820{
4821 return read_struct(fd, bh, blockname, INDEX_ID_NULL);
4822}
4823
4825
4826/* -------------------------------------------------------------------- */
4829
4830static int has_linked_ids_to_read(Main *mainvar)
4831{
4832 MainListsArray lbarray = BKE_main_lists_get(*mainvar);
4833 int a = lbarray.size();
4834 while (a--) {
4835 LISTBASE_FOREACH (ID *, id, lbarray[a]) {
4837 !(id->flag & ID_FLAG_INDIRECT_WEAK_LINK))
4838 {
4839 return true;
4840 }
4841 }
4842 }
4843
4844 return false;
4845}
4846
4848 FileData *basefd, FileData *fd, Main *mainvar, ID *id, ID **r_id)
4849{
4850 BHead *bhead = nullptr;
4851 const bool is_valid = BKE_idtype_idcode_is_linkable(GS(id->name)) ||
4852 ((id->tag & ID_TAG_EXTERN) == 0);
4853
4854 if (fd) {
4855 /* About future longer ID names: This is one of the main places that prevent linking IDs with
4856 * names longer than MAX_ID_NAME - 1.
4857 *
4858 * See also #read_file_bhead_idname_map_create. */
4859 bhead = find_bhead_from_idname(fd, id->name);
4860 }
4861
4862 if (!is_valid) {
4863 BLO_reportf_wrap(basefd->reports,
4864 RPT_ERROR,
4865 RPT_("LIB: %s: '%s' is directly linked from '%s' (parent '%s'), but is a "
4866 "non-linkable data type"),
4868 id->name + 2,
4869 mainvar->curlib->runtime->filepath_abs,
4871 }
4872
4874 id->flag &= ~ID_FLAG_INDIRECT_WEAK_LINK;
4875
4876 if (bhead) {
4878 // printf("read lib block %s\n", id->name);
4879 read_libblock(fd, mainvar, bhead, id->tag, BLO_readfile_id_runtime_tags(*id), false, r_id);
4880 }
4881 else {
4882 CLOG_INFO(&LOG,
4883 3,
4884 "LIB: %s: '%s' missing from '%s', parent '%s'",
4886 id->name + 2,
4887 mainvar->curlib->runtime->filepath_abs,
4889 basefd->reports->count.missing_linked_id++;
4890
4891 /* Generate a placeholder for this ID (simplified version of read_libblock actually...). */
4892 if (r_id) {
4893 *r_id = is_valid ? create_placeholder(mainvar,
4894 GS(id->name),
4895 id->name + 2,
4896 id->tag,
4897 id->override_library != nullptr) :
4898 nullptr;
4899 }
4900 }
4901}
4902
4904 FileData *fd,
4905 ListBase *mainlist,
4906 Main *mainvar)
4907{
4909
4910 MainListsArray lbarray = BKE_main_lists_get(*mainvar);
4911 int a = lbarray.size();
4912 while (a--) {
4913 ID *id = static_cast<ID *>(lbarray[a]->first);
4914
4915 while (id) {
4916 ID *id_next = static_cast<ID *>(id->next);
4919 {
4920 BLI_remlink(lbarray[a], id);
4921 if (mainvar->id_map != nullptr) {
4922 BKE_main_idmap_remove_id(mainvar->id_map, id);
4923 }
4924
4925 /* When playing with lib renaming and such, you may end with cases where
4926 * you have more than one linked ID of the same data-block from same
4927 * library. This is absolutely horrible, hence we use a ghash to ensure
4928 * we go back to a single linked data when loading the file. */
4929 ID *realid = loaded_ids.lookup_default(id->name, nullptr);
4930 if (!realid) {
4931 read_library_linked_id(basefd, fd, mainvar, id, &realid);
4932 loaded_ids.add_overwrite(id->name, realid);
4933 }
4934
4935 /* `realid` shall never be nullptr - unless some source file/lib is broken
4936 * (known case: some directly linked shape-key from a missing lib...). */
4937 // BLI_assert(*realid != nullptr);
4938
4939 /* Now that we have a real ID, replace all pointers to placeholders in
4940 * fd->libmap with pointers to the real data-blocks. We do this for all
4941 * libraries since multiple might be referencing this ID. */
4942 change_link_placeholder_to_real_ID_pointer(mainlist, basefd, id, realid);
4943
4944 /* Transfer the readfile data from the placeholder to the real ID, but
4945 * only if the real ID has no readfile data yet. The same realid may be
4946 * referred to by multiple placeholders. */
4947 if (realid && !realid->runtime.readfile_data) {
4948 realid->runtime.readfile_data = id->runtime.readfile_data;
4949 id->runtime.readfile_data = nullptr;
4950 }
4951
4952 /* The 'readfile' runtime data needs to be freed here, as this ID placeholder does not go
4953 * through versioning (the usual place where this data is freed). Since `id` is not a real
4954 * ID, this shouldn't follow any pointers to embedded IDs. */
4956
4957 MEM_freeN(id);
4958 }
4959 id = id_next;
4960 }
4961
4962 loaded_ids.clear();
4963 }
4964
4966 basefd->reports->reports,
4968 mainvar->curlib->runtime->filepath_abs);
4969}
4970
4971static void read_library_clear_weak_links(FileData *basefd, ListBase *mainlist, Main *mainvar)
4972{
4973 /* Any remaining weak links at this point have been lost, silently drop
4974 * those by setting them to nullptr pointers. */
4975 MainListsArray lbarray = BKE_main_lists_get(*mainvar);
4976 int a = lbarray.size();
4977 while (a--) {
4978 ID *id = static_cast<ID *>(lbarray[a]->first);
4979
4980 while (id) {
4981 ID *id_next = static_cast<ID *>(id->next);
4982
4983 /* This function also visits already-loaded data-blocks, and thus their
4984 * `readfile_data` field might already have been freed. */
4987 {
4988 CLOG_INFO(&LOG, 3, "Dropping weak link to '%s'", id->name);
4989 change_link_placeholder_to_real_ID_pointer(mainlist, basefd, id, nullptr);
4990 BLI_freelinkN(lbarray[a], id);
4991 }
4992 id = id_next;
4993 }
4994 }
4995}
4996
4998 ListBase *mainlist,
4999 Main *mainl,
5000 Main *mainptr)
5001{
5002 FileData *fd = mainptr->curlib->runtime->filedata;
5003
5004 if (fd != nullptr) {
5005 /* File already open. */
5006 return fd;
5007 }
5008
5009 if (mainptr->curlib->packedfile) {
5010 /* Read packed file. */
5011 const PackedFile *pf = mainptr->curlib->packedfile;
5012
5013 BLO_reportf_wrap(basefd->reports,
5014 RPT_INFO,
5015 RPT_("Read packed library: '%s', parent '%s'"),
5016 mainptr->curlib->filepath,
5018 fd = blo_filedata_from_memory(pf->data, pf->size, basefd->reports);
5019
5020 /* Needed for library_append and read_libraries. */
5021 STRNCPY(fd->relabase, mainptr->curlib->runtime->filepath_abs);
5022 }
5023 else {
5024 /* Read file on disk. */
5025 BLO_reportf_wrap(basefd->reports,
5026 RPT_INFO,
5027 RPT_("Read library: '%s', '%s', parent '%s'"),
5028 mainptr->curlib->runtime->filepath_abs,
5029 mainptr->curlib->filepath,
5031 fd = blo_filedata_from_file(mainptr->curlib->runtime->filepath_abs, basefd->reports);
5032 }
5033
5034 if (fd) {
5035 /* Share the mainlist, so all libraries are added immediately in a
5036 * single list. It used to be that all FileData's had their own list,
5037 * but with indirectly linking this meant we didn't catch duplicate
5038 * libraries properly. */
5039 fd->mainlist = mainlist;
5040
5041 fd->reports = basefd->reports;
5042
5043 if (fd->libmap) {
5045 }
5046
5047 fd->libmap = oldnewmap_new();
5048
5049 mainptr->curlib->runtime->filedata = fd;
5050 mainptr->versionfile = fd->fileversion;
5051
5052 /* subversion */
5053 read_file_version(fd, mainptr);
5055 }
5056 else {
5057 mainptr->curlib->runtime->filedata = nullptr;
5058 mainptr->curlib->id.tag |= ID_TAG_MISSING;
5059 /* Set lib version to current main one... Makes assert later happy. */
5060 mainptr->versionfile = mainptr->curlib->runtime->versionfile = mainl->versionfile;
5061 mainptr->subversionfile = mainptr->curlib->runtime->subversionfile = mainl->subversionfile;
5062 }
5063
5064 if (fd == nullptr) {
5065 BLO_reportf_wrap(basefd->reports,
5066 RPT_INFO,
5067 RPT_("Cannot find lib '%s'"),
5068 mainptr->curlib->runtime->filepath_abs);
5069 basefd->reports->count.missing_libraries++;
5070 }
5071
5072 return fd;
5073}
5074
5075static void read_libraries(FileData *basefd, ListBase *mainlist)
5076{
5077 Main *mainl = static_cast<Main *>(mainlist->first);
5078 bool do_it = true;
5079
5080 /* At this point the base blend file has been read, and each library blend
5081 * encountered so far has a main with placeholders for linked data-blocks.
5082 *
5083 * Now we will read the library blend files and replace the placeholders
5084 * with actual data-blocks. We loop over library mains multiple times in
5085 * case a library needs to link additional data-blocks from another library
5086 * that had been read previously. */
5087 while (do_it) {
5088 do_it = false;
5089
5090 /* Loop over mains of all library blend files encountered so far. Note
5091 * this list gets longer as more indirectly library blends are found. */
5092 for (Main *mainptr = mainl->next; mainptr; mainptr = mainptr->next) {
5093 /* Does this library have any more linked data-blocks we need to read? */
5094 if (has_linked_ids_to_read(mainptr)) {
5095 CLOG_INFO(&LOG,
5096 3,
5097 "Reading linked data-blocks from %s (%s)",
5098 mainptr->curlib->id.name,
5099 mainptr->curlib->filepath);
5100
5101 /* Open file if it has not been done yet. */
5102 FileData *fd = read_library_file_data(basefd, mainlist, mainl, mainptr);
5103
5104 if (fd) {
5105 do_it = true;
5106
5107 if (mainptr->id_map == nullptr) {
5108 mainptr->id_map = BKE_main_idmap_create(mainptr, false, nullptr, MAIN_IDMAP_TYPE_NAME);
5109 }
5110 }
5111
5112 /* Read linked data-blocks for each link placeholder, and replace
5113 * the placeholder with the real data-block. */
5114 read_library_linked_ids(basefd, fd, mainlist, mainptr);
5115
5116 /* Test if linked data-blocks need to read further linked data-blocks
5117 * and create link placeholders for them. */
5119 }
5120 }
5121 }
5122
5123 for (Main *mainptr = mainl->next; mainptr; mainptr = mainptr->next) {
5124 /* Drop weak links for which no data-block was found.
5125 * Since this can remap pointers in `libmap` of all libraries, it needs to be performed in its
5126 * own loop, before any call to `lib_link_all` (and the freeing of the libraries' filedata). */
5127 read_library_clear_weak_links(basefd, mainlist, mainptr);
5128 }
5129
5130 Main *main_newid = BKE_main_new();
5131 for (Main *mainptr = mainl->next; mainptr; mainptr = mainptr->next) {
5132 /* Do versioning for newly added linked data-blocks. If no data-blocks
5133 * were read from a library versionfile will still be zero and we can
5134 * skip it. */
5135 if (mainptr->versionfile) {
5136 /* Split out already existing IDs to avoid them going through
5137 * do_versions multiple times, which would have bad consequences. */
5138 split_main_newid(mainptr, main_newid);
5139
5140 /* `filedata` can be NULL when loading linked data from nonexistent or invalid library
5141 * reference. Or during linking/appending, when processing data from a library not involved
5142 * in the current linking/appending operation.
5143 *
5144 * Skip versioning in these cases, since the only IDs here will be placeholders (missing
5145 * lib), or already existing IDs (linking/appending). */
5146 if (mainptr->curlib->runtime->filedata) {
5147 do_versions(mainptr->curlib->runtime->filedata, mainptr->curlib, main_newid);
5148 }
5149
5150 add_main_to_main(mainptr, main_newid);
5151 }
5152
5153 /* Lib linking. */
5154 if (mainptr->curlib->runtime->filedata) {
5155 lib_link_all(mainptr->curlib->runtime->filedata, mainptr);
5156 }
5157
5158 /* NOTE: No need to call #do_versions_after_linking() or #BKE_main_id_refcount_recompute()
5159 * here, as this function is only called for library 'subset' data handling, as part of
5160 * either full blend-file reading (#blo_read_file_internal()), or library-data linking
5161 * (#library_link_end()).
5162 *
5163 * For this to work reliably, `mainptr->curlib->runtime->filedata` also needs to be freed after
5164 * said versioning code has run. */
5165 }
5166 BKE_main_free(main_newid);
5167}
5168
5170 void *new_address,
5171 const void * /*old_address*/,
5172 const size_t expected_size)
5173{
5174 if (new_address != nullptr) {
5175 /* Not testing equality, since size might have been aligned up,
5176 * or might be passed the size of a base struct with inheritance. */
5177 if (MEM_allocN_len(new_address) < expected_size) {
5179 static_cast<Main *>(fd->mainlist->last),
5180 "Corrupt .blend file, unexpected data size.");
5181 /* Return null to trigger a hard-crash rather than allowing readfile code to further access
5182 * this invalid block of memory.
5183 *
5184 * It could also potentially allow the calling code to do its own error checking and abort
5185 * reading process, but that is not implemented currently. */
5186 return nullptr;
5187 }
5188 }
5189
5190 return new_address;
5191}
5192
5193void *BLO_read_get_new_data_address(BlendDataReader *reader, const void *old_address)
5194{
5195 return newdataadr(reader->fd, old_address);
5196}
5197
5199 const void *old_address,
5200 const size_t expected_size)
5201{
5202 void *new_address = newdataadr_no_us(reader->fd, old_address);
5203 return blo_verify_data_address(reader->fd, new_address, old_address, expected_size);
5204}
5205
5207 const void *old_address,
5208 const size_t expected_size)
5209{
5210 void *new_address = newdataadr(reader->fd, old_address);
5211 return blo_verify_data_address(reader->fd, new_address, old_address, expected_size);
5212}
5213
5215 const char *struct_name,
5216 const int64_t items_num,
5217 const void *old_address)
5218{
5219 const int struct_index = DNA_struct_find_with_alias(reader->fd->memsdna, struct_name);
5220 BLI_assert(STREQ(DNA_struct_identifier(const_cast<SDNA *>(reader->fd->memsdna), struct_index),
5221 struct_name));
5222 const size_t struct_size = size_t(DNA_struct_size(reader->fd->memsdna, struct_index));
5223 return BLO_read_struct_array_with_size(reader, old_address, struct_size * items_num);
5224}
5225
5227 ID *self_id,
5228 const bool is_linked_only,
5229 ID *id)
5230{
5231 return static_cast<ID *>(newlibadr(reader->fd, self_id, is_linked_only, id));
5232}
5233
5235{
5236 return BKE_main_idmap_lookup_uid(reader->fd->new_idmap_uid, session_uid);
5237}
5238
5240{
5241 return reader->fd->fileversion;
5242}
5243
5245{
5246 return (reader->fd->flags & FD_FLAGS_SWITCH_ENDIAN) != 0;
5247}
5248
5250 const char *stype,
5251 const char *vartype,
5252 const char *name)
5253{
5254 return DNA_struct_member_offset_by_name_with_alias(reader->fd->filesdna, stype, vartype, name);
5255}
5256
5258 const size_t expected_elem_size,
5259 ListBase *list)
5260{
5261 if (BLI_listbase_is_empty(list)) {
5262 return;
5263 }
5264
5265 list->first = BLO_read_struct_array_with_size(reader, list->first, expected_elem_size);
5266 Link *ln = static_cast<Link *>(list->first);
5267 Link *prev = nullptr;
5268 while (ln) {
5269 ln->next = static_cast<Link *>(
5270 BLO_read_struct_array_with_size(reader, ln->next, expected_elem_size));
5271 ln->prev = prev;
5272 prev = ln;
5273 ln = ln->next;
5274 }
5275 list->last = prev;
5276}
5277
5278void BLO_read_char_array(BlendDataReader *reader, const int64_t array_size, char **ptr_p)
5279{
5280 *ptr_p = reinterpret_cast<char *>(
5281 BLO_read_struct_array_with_size(reader, *((void **)ptr_p), sizeof(char) * array_size));
5282}
5283
5284void BLO_read_uint8_array(BlendDataReader *reader, const int64_t array_size, uint8_t **ptr_p)
5285{
5286 *ptr_p = reinterpret_cast<uint8_t *>(
5287 BLO_read_struct_array_with_size(reader, *((void **)ptr_p), sizeof(uint8_t) * array_size));
5288}
5289
5290void BLO_read_int8_array(BlendDataReader *reader, const int64_t array_size, int8_t **ptr_p)
5291{
5292 *ptr_p = reinterpret_cast<int8_t *>(
5293 BLO_read_struct_array_with_size(reader, *((void **)ptr_p), sizeof(int8_t) * array_size));
5294}
5295
5296void BLO_read_int16_array(BlendDataReader *reader, const int64_t array_size, int16_t **ptr_p)
5297{
5298 *ptr_p = reinterpret_cast<int16_t *>(
5299 BLO_read_struct_array_with_size(reader, *((void **)ptr_p), sizeof(int16_t) * array_size));
5300
5301 if (*ptr_p && BLO_read_requires_endian_switch(reader)) {
5302 BLI_endian_switch_int16_array(*ptr_p, array_size);
5303 }
5304}
5305
5306void BLO_read_int32_array(BlendDataReader *reader, const int64_t array_size, int32_t **ptr_p)
5307{
5308 *ptr_p = reinterpret_cast<int32_t *>(
5309 BLO_read_struct_array_with_size(reader, *((void **)ptr_p), sizeof(int32_t) * array_size));
5310
5311 if (*ptr_p && BLO_read_requires_endian_switch(reader)) {
5312 BLI_endian_switch_int32_array(*ptr_p, array_size);
5313 }
5314}
5315
5316void BLO_read_uint32_array(BlendDataReader *reader, const int64_t array_size, uint32_t **ptr_p)
5317{
5318 *ptr_p = reinterpret_cast<uint32_t *>(
5319 BLO_read_struct_array_with_size(reader, *((void **)ptr_p), sizeof(uint32_t) * array_size));
5320
5321 if (*ptr_p && BLO_read_requires_endian_switch(reader)) {
5322 BLI_endian_switch_uint32_array(*ptr_p, array_size);
5323 }
5324}
5325
5326void BLO_read_float_array(BlendDataReader *reader, const int64_t array_size, float **ptr_p)
5327{
5328 *ptr_p = reinterpret_cast<float *>(
5329 BLO_read_struct_array_with_size(reader, *((void **)ptr_p), sizeof(float) * array_size));
5330
5331 if (*ptr_p && BLO_read_requires_endian_switch(reader)) {
5332 BLI_endian_switch_float_array(*ptr_p, array_size);
5333 }
5334}
5335
5336void BLO_read_float3_array(BlendDataReader *reader, const int64_t array_size, float **ptr_p)
5337{
5338 BLO_read_float_array(reader, array_size * 3, ptr_p);
5339}
5340
5341void BLO_read_double_array(BlendDataReader *reader, const int64_t array_size, double **ptr_p)
5342{
5343 *ptr_p = reinterpret_cast<double *>(
5344 BLO_read_struct_array_with_size(reader, *((void **)ptr_p), sizeof(double) * array_size));
5345
5346 if (*ptr_p && BLO_read_requires_endian_switch(reader)) {
5347 BLI_endian_switch_double_array(*ptr_p, array_size);
5348 }
5349}
5350
5351void BLO_read_string(BlendDataReader *reader, char **ptr_p)
5352{
5353 BLO_read_data_address(reader, ptr_p);
5354
5355#ifndef NDEBUG
5356 const char *str = *ptr_p;
5357 if (str) {
5358 /* Verify that we have a null terminator. */
5359 for (size_t len = MEM_allocN_len(str); len > 0; len--) {
5360 if (str[len - 1] == '\0') {
5361 return;
5362 }
5363 }
5364
5365 BLI_assert_msg(0, "Corrupt .blend file, expected string to be null terminated.");
5366 }
5367#endif
5368}
5369
5370void BLO_read_string(BlendDataReader *reader, char *const *ptr_p)
5371{
5372 BLO_read_string(reader, const_cast<char **>(ptr_p));
5373}
5374
5375void BLO_read_string(BlendDataReader *reader, const char **ptr_p)
5376{
5377 BLO_read_string(reader, const_cast<char **>(ptr_p));
5378}
5379
5381 const int64_t array_size,
5382 const uint64_t *src,
5383 uint32_t *dst)
5384{
5385 const bool use_endian_swap = BLO_read_requires_endian_switch(reader);
5386 for (int i = 0; i < array_size; i++) {
5387 dst[i] = uint32_from_uint64_ptr(src[i], use_endian_swap);
5388 }
5389}
5390
5392 const int64_t array_size,
5393 const uint32_t *src,
5394 uint64_t *dst)
5395{
5396 /* Match pointer conversion rules from bh8_from_bh4 and cast_pointer_32_to_64. */
5397 for (int i = 0; i < array_size; i++) {
5398 dst[i] = src[i];
5399 }
5400}
5401
5402void BLO_read_pointer_array(BlendDataReader *reader, const int64_t array_size, void **ptr_p)
5403{
5404 FileData *fd = reader->fd;
5405
5406 void *orig_array = newdataadr(fd, *ptr_p);
5407 if (orig_array == nullptr) {
5408 *ptr_p = nullptr;
5409 return;
5410 }
5411
5412 int file_pointer_size = fd->filesdna->pointer_size;
5413 int current_pointer_size = fd->memsdna->pointer_size;
5414
5415 void *final_array = nullptr;
5416
5417 if (file_pointer_size == current_pointer_size) {
5418 /* No pointer conversion necessary. */
5419 final_array = orig_array;
5420 }
5421 else if (file_pointer_size == 8 && current_pointer_size == 4) {
5422 /* Convert pointers from 64 to 32 bit. */
5423 final_array = MEM_malloc_arrayN(array_size, 4, "new pointer array");
5425 reader, array_size, (uint64_t *)orig_array, (uint32_t *)final_array);
5426 MEM_freeN(orig_array);
5427 }
5428 else if (file_pointer_size == 4 && current_pointer_size == 8) {
5429 /* Convert pointers from 32 to 64 bit. */
5430 final_array = MEM_malloc_arrayN(array_size, 8, "new pointer array");
5432 reader, array_size, (uint32_t *)orig_array, (uint64_t *)final_array);
5433 MEM_freeN(orig_array);
5434 }
5435 else {
5437 }
5438
5439 *ptr_p = final_array;
5440}
5441
5443 BlendDataReader *reader,
5444 const void **ptr_p,
5445 const blender::FunctionRef<const blender::ImplicitSharingInfo *()> read_fn)
5446{
5447 const void *old_address = *ptr_p;
5448 if (BLO_read_data_is_undo(reader)) {
5449 if (reader->fd->flags & FD_FLAGS_IS_MEMFILE) {
5450 UndoReader *undo_reader = reinterpret_cast<UndoReader *>(reader->fd->file);
5451 const MemFile &memfile = *undo_reader->memfile;
5452 if (memfile.shared_storage) {
5453 /* Check if the data was saved with sharing-info. */
5454 if (const blender::ImplicitSharingInfo *sharing_info =
5455 memfile.shared_storage->map.lookup_default(old_address, nullptr))
5456 {
5457 /* Add a new owner of the data that is passed to the caller. */
5458 sharing_info->add_user();
5459 return {sharing_info, old_address};
5460 }
5461 }
5462 }
5463 }
5464
5465 if (const blender::ImplicitSharingInfoAndData *shared_data =
5466 reader->shared_data_by_stored_address.lookup_ptr(old_address))
5467 {
5468 /* The data was loaded before. No need to load it again. Just increase the user count to
5469 * indicate that it is shared. */
5470 if (shared_data->sharing_info) {
5471 shared_data->sharing_info->add_user();
5472 }
5473 return *shared_data;
5474 }
5475
5476 /* This is the first time this data is loaded. The callback also creates the corresponding
5477 * sharing info which may be reused later. */
5478 const blender::ImplicitSharingInfo *sharing_info = read_fn();
5479 const void *new_address = *ptr_p;
5480 const blender::ImplicitSharingInfoAndData shared_data{sharing_info, new_address};
5481 reader->shared_data_by_stored_address.add(old_address, shared_data);
5482 return shared_data;
5483}
5484
5486{
5487 return (reader->fd->flags & FD_FLAGS_IS_MEMFILE);
5488}
5489
5490void BLO_read_data_globmap_add(BlendDataReader *reader, void *oldaddr, void *newaddr)
5491{
5492 oldnewmap_insert(reader->fd->globmap, oldaddr, newaddr, 0);
5493}
5494
5496{
5497 link_glob_list(reader->fd, list);
5498}
5499
5501{
5502 return reader->fd->reports;
5503}
5504
5506{
5507 return (reader->fd->flags & FD_FLAGS_IS_MEMFILE);
5508}
5509
5511{
5512 return reader->main;
5513}
5514
5516{
5517 return reader->fd->reports;
5518}
5519
AnimData * BKE_animdata_from_id(const ID *id)
Definition anim_data.cc:82
void BKE_animdata_blend_read_data(BlendDataReader *reader, ID *id)
void BKE_asset_metadata_read(BlendDataReader *reader, AssetMetaData *asset_data)
Definition asset.cc:215
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:153
#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)
const IDTypeInfo * BKE_idtype_get_info_from_idtype_index(const int idtype_index)
Definition idtype.cc:128
const IDTypeInfo * BKE_idtype_get_info_from_id(const ID *id)
Definition idtype.cc:147
bool BKE_idtype_cache_key_cmp(const void *key_a_v, const void *key_b_v)
Definition idtype.cc:36
const char * BKE_idtype_idcode_to_name(short idcode)
Definition idtype.cc:165
bool BKE_idtype_idcode_is_linkable(short idcode)
Definition idtype.cc:198
void BKE_idtype_id_foreach_cache(ID *id, IDTypeForeachCacheFunctionCallback function_callback, void *user_data)
Definition idtype.cc:382
int BKE_idtype_idcode_to_index(short idcode)
Definition idtype.cc:229
@ IDTYPE_FLAGS_NO_MEMFILE_UNDO
Definition BKE_idtype.hh:55
uint BKE_idtype_cache_key_hash(const void *key_v)
Definition idtype.cc:28
bool BKE_idtype_idcode_is_valid(short idcode)
Definition idtype.cc:193
@ IDTYPE_CACHE_CB_FLAGS_PERSISTENT
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()
IDNewNameResult BKE_id_new_name_validate(Main &bmain, ListBase &lb, ID &id, const char *newname, IDNewNameMode mode, bool do_linked_data)
Definition lib_id.cc:1883
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:1770
#define MAIN_ID_SESSION_UID_UNSET
void BKE_libblock_init_empty(ID *id) ATTR_NONNULL(1)
Definition lib_id.cc:1433
void BKE_lib_libblock_session_uid_ensure(ID *id)
Definition lib_id.cc:1458
void id_us_ensure_real(ID *id)
Definition lib_id.cc:308
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:1052
void * BKE_id_new(Main *bmain, short type, const char *name)
Definition lib_id.cc:1495
const char * BKE_id_name(const ID &id)
void BKE_main_id_refcount_recompute(Main *bmain, bool do_linked_only)
Definition lib_id.cc:2015
ID * BKE_libblock_alloc_notest(short type) ATTR_WARN_UNUSED_RESULT
Definition lib_id.cc:1323
void BKE_main_id_tag_all(Main *mainvar, int tag, bool value)
Definition lib_id.cc:1214
void BKE_lib_override_library_main_validate(Main *bmain, ReportList *reports)
void BKE_lib_override_library_main_update(Main *bmain)
@ 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, LibraryForeachIDFlag flag)
Definition lib_query.cc:431
@ IDWALK_RET_NOP
LibraryForeachIDFlag
@ IDWALK_DO_DEPRECATED_POINTERS
@ IDWALK_INCLUDE_UI
@ IDWALK_NOP
@ 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
@ LIBRARY_IS_ASSET_EDIT_FILE
#define FOREACH_MAIN_ID_END
Definition BKE_main.hh:563
MainListsArray BKE_main_lists_get(Main &bmain)
Definition main.cc:974
ListBase * which_libbase(Main *bmain, short type)
Definition main.cc:887
#define FOREACH_MAIN_LISTBASE_ID_END
Definition BKE_main.hh:532
std::array< ListBase *, INDEX_ID_MAX - 1 > MainListsArray
Definition BKE_main.hh:621
#define FOREACH_MAIN_LISTBASE_ID_BEGIN(_lb, _id)
Definition BKE_main.hh:526
#define FOREACH_MAIN_LISTBASE_END
Definition BKE_main.hh:544
Main * BKE_main_new()
Definition main.cc:48
#define FOREACH_MAIN_LISTBASE_BEGIN(_bmain, _lb)
Definition BKE_main.hh:537
void BKE_main_free(Main *bmain)
Definition main.cc:175
#define FOREACH_MAIN_ID_BEGIN(_bmain, _id)
Definition BKE_main.hh:557
#define MAIN_VERSION_FILE_OLDER_OR_EQUAL(main, ver, subver)
Definition BKE_main.hh:642
#define BLEN_THUMB_MEMSIZE(_x, _y)
Definition BKE_main.hh:659
const char * BKE_main_blendfile_path(const Main *bmain) ATTR_NONNULL()
Definition main.cc:877
#define BLEN_THUMB_MEMSIZE_IS_VALID(_x, _y)
Definition BKE_main.hh:662
bool BKE_main_is_empty(Main *bmain)
Definition main.cc:462
const char * BKE_main_blendfile_path_from_global()
Definition main.cc:882
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
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
@ MAIN_IDMAP_TYPE_UID
@ MAIN_IDMAP_TYPE_NAME
void BKE_main_ensure_invariants(Main &bmain, std::optional< blender::Span< ID * > > modified_ids=std::nullopt)
bool BKE_main_namemap_validate_and_fix(Main &bmain)
void BKE_main_namemap_clear(Main &bmain)
General operations, lookup, etc. for materials.
void BKE_object_materials_sync_length(Main *bmain, Object *ob, 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)
bool BKE_reports_print_test(const ReportList *reports, eReportType type)
Definition report.cc:298
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:29
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition report.cc:126
bool BKE_screen_blend_read_data(BlendDataReader *reader, bScreen *screen)
Definition screen.cc:136
@ STEP_UNDO
@ STEP_REDO
#define BLI_assert_unreachable()
Definition BLI_assert.h:93
#define BLI_STATIC_ASSERT(a, msg)
Definition BLI_assert.h:83
#define BLI_assert(a)
Definition BLI_assert.h:46
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:53
#define ATTR_FALLTHROUGH
#define L_ENDIAN
#define ENDIAN_ORDER
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_int16_array(short *val, int size) ATTR_NONNULL(1)
void BLI_endian_switch_double_array(double *val, int size) ATTR_NONNULL(1)
File and directory operations.
#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.cc:819
GHash * BLI_ghash_new(GHashHashFP hashfp, GHashCmpFP cmpfp, const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.cc:686
void * BLI_ghash_lookup(const GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.cc:731
void BLI_ghash_insert(GHash *gh, void *key, void *val)
Definition BLI_ghash.cc:707
void BLI_ghash_free(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
Definition BLI_ghash.cc:860
void void void BLI_movelisttolist(ListBase *dst, ListBase *src) ATTR_NONNULL(1
#define LISTBASE_FOREACH(type, var, list)
BLI_INLINE void BLI_listbase_clear(ListBase *lb)
void * BLI_findstring(const ListBase *listbase, const char *id, int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition listbase.cc:608
BLI_INLINE bool BLI_listbase_is_empty(const ListBase *lb)
void BLI_freelinkN(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:270
#define LISTBASE_FOREACH_MUTABLE(type, var, list)
void void BLI_freelistN(ListBase *listbase) ATTR_NONNULL(1)
Definition listbase.cc:497
void BLI_addtail(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:111
void BLI_remlink(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:131
bool BLI_remlink_safe(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:154
int BLI_listbase_count(const ListBase *listbase) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition listbase.cc:524
void void BLI_INLINE bool BLI_listbase_is_single(const ListBase *lb)
#define BLI_MEMARENA_STD_BUFSIZE
MemArena * BLI_memarena_new(size_t bufsize, const char *name) ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL ATTR_NONNULL(2) ATTR_MALLOC
void BLI_memarena_free(MemArena *ma) ATTR_NONNULL(1)
void * BLI_memarena_alloc(MemArena *ma, size_t size) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1) ATTR_MALLOC ATTR_ALLOC_SIZE(2)
ATTR_WARN_UNUSED_RESULT const size_t num
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
char * STRNCPY(char(&dst)[N], const char *src)
Definition BLI_string.h:688
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, size_t dst_maxncpy) ATTR_NONNULL(1
size_t size_t size_t bool BLI_str_utf8_truncate_at_size(char *str, const size_t str_size)
size_t void BLI_uniquename_cb(blender::FunctionRef< bool(blender::StringRefNull)> unique_check, const char *defname, char delim, char *name, size_t name_maxncpy) ATTR_NONNULL(2
unsigned int uint
Platform independent time functions.
double BLI_time_now_seconds(void)
Definition time.cc:65
#define UNUSED_VARS(...)
#define UNUSED_VARS_NDEBUG(...)
#define SET_FLAG_FROM_TEST(value, test, flag)
#define UNLIKELY(x)
#define POINTER_OFFSET(v, ofs)
#define STREQ(a, b)
#define LIKELY(x)
Compatibility-like things for windows.
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)
uint32_t uint32_from_uint64_ptr(uint64_t ptr, const bool use_endian_swap)
@ BLO_CODE_ENDB
@ BLO_CODE_REND
@ BLO_CODE_TEST
@ BLO_CODE_GLOB
@ BLO_CODE_DATA
@ BLO_CODE_DNA1
@ BLO_CODE_USER
std::optional< BHead > BLO_readfile_read_bhead(FileReader *file, BHeadType type, bool do_endian_swap)
BlenderHeaderVariant BLO_readfile_blender_header_decode(FileReader *file)
#define MIN_SIZEOFBLENDERHEADER
std::variant< BlenderHeaderInvalid, BlenderHeaderUnknown, BlenderHeader > BlenderHeaderVariant
#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_COLLECTION_NO_HIERARCHY_REBUILD
@ BLO_LIBLINK_FORCE_INDIRECT
@ BLO_READ_SKIP_DATA
@ BLO_READ_SKIP_USERDEF
@ BLO_READ_SKIP_UNDO_OLD_MAIN
ID_Readfile_Data::Tags BLO_readfile_id_runtime_tags(ID &id)
Definition readfile.cc:2231
#define BLEN_THUMB_MEMSIZE_FILE(_x, _y)
@ BLENFILETYPE_BLEND
FileReader * BLO_memfile_new_filereader(MemFile *memfile, int undo_direction)
Definition undofile.cc:265
#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
@ ID_RECALC_SOURCE
Definition DNA_ID.h:1051
@ ID_RECALC_SYNC_TO_EVAL
Definition DNA_ID.h:1026
@ ID_RECALC_GEOMETRY
Definition DNA_ID.h:982
@ ID_RECALC_ALL
Definition DNA_ID.h:1096
@ ID_TAG_UNDO_OLD_ID_REUSED_UNCHANGED
Definition DNA_ID.h:844
@ ID_TAG_NEW
Definition DNA_ID.h:827
@ ID_TAG_UNDO_OLD_ID_REUSED_NOUNDO
Definition DNA_ID.h:855
@ ID_TAG_TEMP_MAIN
Definition DNA_ID.h:879
@ ID_TAG_INDIRECT
Definition DNA_ID.h:756
@ ID_TAG_EXTERN
Definition DNA_ID.h:750
@ ID_TAG_MISSING
Definition DNA_ID.h:775
@ ID_TAG_LOCAL
Definition DNA_ID.h:744
@ ID_TAG_UNDO_OLD_ID_REREAD_IN_PLACE
Definition DNA_ID.h:862
@ ID_TAG_LIBOVERRIDE_NEED_RESYNC
Definition DNA_ID.h:814
@ INDEX_ID_NULL
Definition DNA_ID.h:1266
@ ID_FLAG_INDIRECT_WEAK_LINK
Definition DNA_ID.h:693
@ ID_FLAG_FAKEUSER
Definition DNA_ID.h:682
@ ID_WM
@ ID_LI
@ ID_SCE
@ ID_AC
@ ID_SCR
@ ID_OB
Object groups, one object can be in many groups at once.
@ CONSTRAINT_TYPE_ACTION
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:63
@ SDNA_CMP_NOT_EQUAL
Definition DNA_genfile.h:69
void DNA_sdna_alias_data_ensure_structs_map(struct SDNA *sdna)
@ OB_MODE_EDIT
@ SCE_READFILE_LIBLINK_NEED_SETSCENE_CHECK
#define SDNA_RAW_DATA_STRUCT_INDEX
@ FILE_RELPATH
@ USER_MENU_TYPE_OPERATOR
Read Guarded memory(de)allocation.
ReportList * reports
Definition WM_types.hh:1025
BKE_main_namemap_clear * new_bmain
Definition blendfile.cc:603
BKE_main_namemap_clear * old_bmain
Definition blendfile.cc:602
std::swap * new_lb
Definition blendfile.cc:598
BMesh const char void * data
ATTR_WARN_UNUSED_RESULT const BMVert * v2
long long int int64_t
unsigned long long int uint64_t
void clear()
Definition BLI_map.hh:1038
const Value * lookup_ptr(const Key &key) const
Definition BLI_map.hh:508
bool add_overwrite(const Key &key, const Value &value)
Definition BLI_map.hh:325
ValueIterator values() const &
Definition BLI_map.hh:884
bool add(const Key &key, const Value &value)
Definition BLI_map.hh:295
Value lookup_default(const Key &key, const Value &default_value) const
Definition BLI_map.hh:570
void clear()
Definition BLI_map.hh:1038
bool add_overwrite(const Key &key, const Value &value)
Definition BLI_map.hh:325
Value lookup_default(const Key &key, const Value &default_value) const
Definition BLI_map.hh:570
bool contains(const Key &key) const
Definition BLI_set.hh:310
void add_new(const Key &key)
Definition BLI_set.hh:233
const char * insert(const keyT &key, std::string alloc_string)
std::string id_name(void *id)
#define offsetof(t, d)
#define str(s)
#define pf(_x, _i)
Prefetch 64.
Definition gim_memory.h:48
#define main()
#define printf(...)
#define ID_FAKE_USERS(id)
#define MEM_SAFE_FREE(v)
#define ID_IS_LINKED(_id)
#define MAX_ID_NAME
#define ID_SCRN
#define ID_LINK_PLACEHOLDER
#define INDEX_ID_MAX
#define GS(a)
#define ID_TAG_KEEP_ON_UNDO
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
format
#define LOG(severity)
Definition log.h:32
void * MEM_mallocN(size_t len, const char *str)
Definition mallocn.cc:128
void * MEM_mallocN_aligned(size_t len, size_t alignment, const char *str)
Definition mallocn.cc:138
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
void * MEM_malloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:133
size_t(* MEM_allocN_len)(const void *vmemh)
Definition mallocn.cc:36
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
#define G(x, y, z)
bool foreach_strip_adt(const AnimData &adt, blender::FunctionRef< bool(NlaStrip *)> callback)
void node_tree_blend_read_data(BlendDataReader *reader, ID *owner_id, bNodeTree *ntree)
Definition node.cc:2146
void node_tree_update_all_new(Main &main)
Definition node.cc:5190
bNodeTree ** node_tree_ptr_from_id(ID *id)
Definition node.cc:4816
bNodeTree * node_tree_from_id(ID *id)
Definition node.cc:4840
AllocStringStorage< keyT, hashT > & alloc_string_storage_get(const std::string &storage_identifier)
static int lib_link_cb(LibraryIDLinkCallbackData *cb_data)
Definition readfile.cc:3464
static BHead * find_bhead(FileData *fd, void *old)
Definition readfile.cc:4194
static void * newdataadr_no_us(FileData *fd, const void *adr)
Definition readfile.cc:1518
static void read_libraries(FileData *basefd, ListBase *mainlist)
Definition readfile.cc:5075
static void long_id_names_ensure_unique_id_names(Main *bmain)
Definition readfile.cc:971
void * blo_do_versions_newlibadr(FileData *fd, ID *self_id, const bool is_linked_only, const void *adr)
Definition readfile.cc:1534
static void lib_link_scenes_check_set(Main *bmain)
Definition readfile.cc:2455
void BLO_read_struct_list_with_size(BlendDataReader *reader, const size_t expected_elem_size, ListBase *list)
Definition readfile.cc:5257
static bool read_libblock_undo_restore_library(FileData *fd, Main *new_main, const ID *id, ID *id_old, BHead *bhead)
Definition readfile.cc:2790
static void link_glob_list(FileData *fd, ListBase *lb)
Definition readfile.cc:1991
static ID * read_id_struct(FileData *fd, BHead *bh, const char *blockname, const int id_type_index)
Definition readfile.cc:1962
static ID * create_placeholder(Main *mainvar, const short idcode, const char *idname, const int tag, const bool was_liboverride)
Definition readfile.cc:2575
static void lib_link_all(FileData *fd, Main *bmain)
Definition readfile.cc:3492
void blo_cache_storage_end(FileData *fd)
Definition readfile.cc:1771
static void long_id_names_process_action_slots_identifiers(Main *bmain)
Definition readfile.cc:1013
static FileData * filedata_new(BlendFileReadReport *reports)
Definition readfile.cc:1131
void BLO_read_int32_array(BlendDataReader *reader, const int64_t array_size, int32_t **ptr_p)
Definition readfile.cc:5306
BlendThumbnail * BLO_thumbnail_from_file(const char *filepath)
Definition readfile.cc:1467
static void direct_link_library(FileData *fd, Library *lib, Main *main)
Definition readfile.cc:2481
int BLO_read_struct_member_offset(const BlendDataReader *reader, const char *stype, const char *vartype, const char *name)
Definition readfile.cc:5249
static void read_file_bhead_idname_map_create(FileData *fd)
Definition readfile.cc:507
static int direct_link_id_restore_recalc_exceptions(const ID *id_current)
Definition readfile.cc:2166
void BLO_read_uint8_array(BlendDataReader *reader, const int64_t array_size, uint8_t **ptr_p)
Definition readfile.cc:5284
static void convert_pointer_array_32_to_64(BlendDataReader *, const int64_t array_size, const uint32_t *src, uint64_t *dst)
Definition readfile.cc:5391
const char * blo_bhead_id_name(FileData *fd, const BHead *bhead)
Definition readfile.cc:816
void BLO_library_link_params_init(LibraryLink_Params *params, Main *bmain, const int flag, const int id_tag_extra)
Definition readfile.cc:4603
static void split_main_newid(Main *mainptr, Main *main_newid)
Definition readfile.cc:4639
void BLO_read_float_array(BlendDataReader *reader, const int64_t array_size, float **ptr_p)
Definition readfile.cc:5326
static void link_global(FileData *fd, BlendFileData *bfd)
Definition readfile.cc:3287
static BHead * read_global(BlendFileData *bfd, FileData *fd, BHead *bhead)
Definition readfile.cc:3237
int BLO_read_fileversion_get(BlendDataReader *reader)
Definition readfile.cc:5239
BHead * blo_bhead_next(FileData *fd, BHead *thisblock)
Definition readfile.cc:745
void BLO_read_uint32_array(BlendDataReader *reader, const int64_t array_size, uint32_t **ptr_p)
Definition readfile.cc:5316
blender::ImplicitSharingInfoAndData blo_read_shared_impl(BlendDataReader *reader, const void **ptr_p, const blender::FunctionRef< const blender::ImplicitSharingInfo *()> read_fn)
Definition readfile.cc:5442
static void read_undo_reuse_noundo_local_ids(FileData *fd)
Definition readfile.cc:2732
BlendFileReadReport * BLO_read_data_reports(BlendDataReader *reader)
Definition readfile.cc:5500
BHead * blo_bhead_first(FileData *fd)
Definition readfile.cc:717
static bool read_libblock_is_identical(FileData *fd, BHead *bhead)
Definition readfile.cc:2704
static void change_ID_pointer_to_real_ID_pointer_fd(FileData *fd, const void *old, void *newp)
Definition readfile.cc:1561
Main * BLO_read_lib_get_main(BlendLibReader *reader)
Definition readfile.cc:5510
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:2177
static bool blo_bhead_is_id(const BHead *bhead)
Definition readfile.cc:490
static void direct_link_id_override_property(BlendDataReader *reader, IDOverrideLibraryProperty *op)
Definition readfile.cc:2085
static const char * library_parent_filepath(Library *lib)
Definition readfile.cc:237
static void change_ID_pointer_to_real_ID_pointer(ListBase *mainlist, FileData *basefd, void *old, void *newp)
Definition readfile.cc:1597
static void direct_link_id_common(BlendDataReader *reader, Library *current_library, ID *id, ID *id_old, int id_tag, ID_Readfile_Data::Tags id_read_tags)
Definition readfile.cc:2273
static void direct_link_id_embedded_id(BlendDataReader *reader, Library *current_library, ID *id, ID *id_old)
Definition readfile.cc:2109
static bool oldnewmap_insert(OldNewMap *onm, const void *oldaddr, void *newaddr, const int nr)
Definition readfile.cc:268
void BLO_read_glob_list(BlendDataReader *reader, ListBase *list)
Definition readfile.cc:5495
static int has_linked_ids_to_read(Main *mainvar)
Definition readfile.cc:4830
static BHead * blo_bhead_read_full(FileData *fd, BHead *thisblock)
Definition readfile.cc:799
static void do_versions_userdef(FileData *, BlendFileData *bfd)
Definition readfile.cc:3310
static void split_libdata(ListBase *lb_src, Main **lib_main_array, const uint lib_main_array_len)
Definition readfile.cc:380
static void library_link_end(Main *mainl, FileData **fd, const int flag, ReportList *reports)
Definition readfile.cc:4662
void blo_do_versions_oldnewmap_insert(OldNewMap *onm, const void *oldaddr, void *newaddr, const int nr)
Definition readfile.cc:282
static void add_main_to_main(Main *mainvar, Main *from)
Definition readfile.cc:341
static OldNewMap * oldnewmap_new()
Definition readfile.cc:259
static void after_liblink_id_process(BlendLibReader *reader, ID *id)
Definition readfile.cc:2072
bool BLO_read_data_is_undo(BlendDataReader *reader)
Definition readfile.cc:5485
static bool read_libblock_undo_restore_linked(FileData *fd, Main *libmain, const ID *id, ID **r_id_old, BHead *bhead)
Definition readfile.cc:2838
static void * newdataadr(FileData *fd, const void *adr)
Definition readfile.cc:1512
void * BLO_read_get_new_data_address_no_us(BlendDataReader *reader, const void *old_address, const size_t expected_size)
Definition readfile.cc:5198
static void do_versions_after_linking(FileData *fd, Main *main)
Definition readfile.cc:3403
void BLO_library_link_end(Main *mainl, BlendHandle **bh, const LibraryLink_Params *params, ReportList *reports)
Definition readfile.cc:4787
static BHead * read_data_into_datamap(FileData *fd, BHead *bhead, const char *allocname, const int id_type_index)
Definition readfile.cc:2678
ID * BLO_read_get_new_id_address(BlendLibReader *reader, ID *self_id, const bool is_linked_only, ID *id)
Definition readfile.cc:5226
static void readfile_id_runtime_data_ensure(ID &id)
Definition readfile.cc:2223
static void read_libraries_report_invalid_id_names(FileData *fd, ReportList *reports, const bool has_forward_compatibility_issues, const char *filepath)
Definition readfile.cc:4270
static BHead * find_bhead_from_idname(FileData *fd, const char *idname)
Definition readfile.cc:4237
static void blo_cache_storage_entry_restore_in_new(ID *id, const IDCacheKey *key, void **cache_p, const uint flags, void *cache_storage_v)
Definition readfile.cc:1649
BlendFileReadReport * BLO_read_lib_reports(BlendLibReader *reader)
Definition readfile.cc:5515
AssetMetaData * blo_bhead_id_asset_data_address(const FileData *fd, const BHead *bhead)
Definition readfile.cc:829
BlendFileData * blo_read_file_internal(FileData *fd, const char *filepath)
Definition readfile.cc:3771
static void switch_endian_structs(const SDNA *filesdna, BHead *bhead)
Definition readfile.cc:1787
void BLO_readfile_id_runtime_data_free(ID &id)
Definition readfile.cc:2245
static BHead * read_libblock(FileData *fd, Main *main, BHead *bhead, int id_tag, ID_Readfile_Data::Tags id_read_tags, const bool placeholder_set_indirect_extern, ID **r_id)
Definition readfile.cc:3078
static void sort_bhead_old_map(FileData *fd)
Definition readfile.cc:4153
FileData * blo_filedata_from_memfile(MemFile *memfile, const BlendFileReadParams *params, BlendFileReadReport *reports)
Definition readfile.cc:1393
void BLO_read_double_array(BlendDataReader *reader, const int64_t array_size, double **ptr_p)
Definition readfile.cc:5341
static void fix_relpaths_library(const char *basepath, Main *main)
Definition readfile.cc:2541
static bool read_libblock_undo_restore(FileData *fd, Main *main, BHead *bhead, const int id_tag, ID **r_id_old)
Definition readfile.cc:2977
static void convert_pointer_array_64_to_32(BlendDataReader *reader, const int64_t array_size, const uint64_t *src, uint32_t *dst)
Definition readfile.cc:5380
void BLO_read_int16_array(BlendDataReader *reader, const int64_t array_size, int16_t **ptr_p)
Definition readfile.cc:5296
static void expand_doit_library(void *fdhandle, Main *mainvar, void *old)
Definition readfile.cc:4307
bool BLO_read_lib_is_undo(BlendLibReader *reader)
Definition readfile.cc:5505
void * BLO_read_struct_array_with_size(BlendDataReader *reader, const void *old_address, const size_t expected_size)
Definition readfile.cc:5206
static const void * peek_struct_undo(FileData *fd, BHead *bhead)
Definition readfile.cc:1984
static void * oldnewmap_liblookup(OldNewMap *onm, const void *addr, const bool is_linked_only)
Definition readfile.cc:303
static void oldnewmap_free(OldNewMap *onm)
Definition readfile.cc:330
static void oldnewmap_lib_insert(FileData *fd, const void *oldaddr, ID *newaddr, const int id_code)
Definition readfile.cc:277
void * BLO_read_struct_by_name_array(BlendDataReader *reader, const char *struct_name, const int64_t items_num, const void *old_address)
Definition readfile.cc:5214
static void blo_cache_storage_entry_clear_in_old(ID *, const IDCacheKey *key, void **cache_p, const uint, void *cache_storage_v)
Definition readfile.cc:1684
static BHeadN * get_bhead(FileData *fd)
Definition readfile.cc:623
static ID * link_named_part(Main *mainl, FileData *fd, const short idcode, const char *name, const int flag)
Definition readfile.cc:4498
static void after_liblink_merged_bmain_process(Main *bmain, BlendFileReadReport *reports)
Definition readfile.cc:3564
void BLO_read_string(BlendDataReader *reader, char **ptr_p)
Definition readfile.cc:5351
void BLO_read_data_globmap_add(BlendDataReader *reader, void *oldaddr, void *newaddr)
Definition readfile.cc:5490
ID_Readfile_Data::Tags BLO_readfile_id_runtime_tags(ID &id)
Definition readfile.cc:2231
static int expand_cb(LibraryIDLinkCallbackData *cb_data)
Definition readfile.cc:4428
static void read_undo_remap_noundo_data(FileData *fd)
Definition readfile.cc:3733
FileData * blo_filedata_from_file(const char *filepath, BlendFileReadReport *reports)
Definition readfile.cc:1331
void BLO_read_int8_array(BlendDataReader *reader, const int64_t array_size, int8_t **ptr_p)
Definition readfile.cc:5290
static void read_library_linked_id(FileData *basefd, FileData *fd, Main *mainvar, ID *id, ID **r_id)
Definition readfile.cc:4847
static void read_library_linked_ids(FileData *basefd, FileData *fd, ListBase *mainlist, Main *mainvar)
Definition readfile.cc:4903
static void do_versions(FileData *fd, Library *lib, Main *main)
Definition readfile.cc:3321
static const char * get_alloc_name(FileData *fd, BHead *bh, const char *blockname, const int id_type_index=INDEX_ID_NULL)
Definition readfile.cc:1810
FileData * blo_filedata_from_memory(const void *mem, const int memsize, BlendFileReadReport *reports)
Definition readfile.cc:1361
#define BHEADN_FROM_BHEAD(bh)
Definition readfile.cc:202
static void change_link_placeholder_to_real_ID_pointer_fd(FileData *fd, const void *old, void *newp)
Definition readfile.cc:1543
Main * BLO_library_link_begin(BlendHandle **bh, const char *filepath, const LibraryLink_Params *params)
Definition readfile.cc:4631
bool BLO_read_requires_endian_switch(BlendDataReader *reader)
Definition readfile.cc:5244
static ID * library_id_is_yet_read(FileData *fd, Main *mainvar, BHead *bhead)
Definition readfile.cc:4253
static FileData * blo_filedata_from_file_descriptor(const char *filepath, BlendFileReadReport *reports, const int filedes)
Definition readfile.cc:1250
static void direct_link_keymapitem(BlendDataReader *reader, wmKeyMapItem *kmi)
Definition readfile.cc:3598
static void blo_cache_storage_entry_register(ID *id, const IDCacheKey *key, void **cache_p, uint, void *cache_storage_v)
Definition readfile.cc:1629
static void * newlibadr(FileData *fd, ID *, const bool is_linked_only, const void *adr)
Definition readfile.cc:1529
void blo_split_main(ListBase *mainlist, Main *main)
Definition readfile.cc:402
static int verg_bheadsort(const void *v1, const void *v2)
Definition readfile.cc:4139
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:4614
static bool read_file_dna(FileData *fd, const char **r_error_message)
Definition readfile.cc:865
void blo_do_versions_key_uidgen(Key *key)
Definition readfile.cc:2405
static void placeholders_ensure_valid(Main *bmain)
Definition readfile.cc:2614
static BHead * find_bhead_from_code_name(FileData *fd, const short idcode, const char *name)
Definition readfile.cc:4228
void blo_cache_storage_init(FileData *fd, Main *bmain)
Definition readfile.cc:1708
void blo_make_old_idmap_from_main(FileData *fd, Main *bmain)
Definition readfile.cc:1610
short BLO_version_from_file(const char *filepath)
Definition readfile.cc:1494
BHead * blo_read_asset_data_block(FileData *fd, BHead *bhead, AssetMetaData **r_asset_data)
Definition readfile.cc:3214
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:2887
static void change_link_placeholder_to_real_ID_pointer(ListBase *mainlist, FileData *basefd, void *old, void *newp)
Definition readfile.cc:1584
static FileData * blo_filedata_from_file_minimal(const char *filepath)
Definition readfile.cc:1347
static void oldnewmap_clear(OldNewMap *onm)
Definition readfile.cc:319
void BLO_readfile_id_runtime_data_free_all(Main &bmain)
Definition readfile.cc:2250
static void read_libblock_undo_restore_at_old_address(FileData *fd, Main *main, ID *id, ID *id_old)
Definition readfile.cc:2935
static bool direct_link_id(FileData *fd, Main *main, const int tag, const ID_Readfile_Data::Tags id_read_tags, ID *id, ID *id_old)
Definition readfile.cc:2626
static BHead * find_previous_lib(FileData *fd, BHead *bhead)
Definition readfile.cc:4178
#define BHEAD_USE_READ_ON_DEMAND(bhead)
Definition readfile.cc:208
static void read_library_clear_weak_links(FileData *basefd, ListBase *mainlist, Main *mainvar)
Definition readfile.cc:4971
void BLO_read_char_array(BlendDataReader *reader, const int64_t array_size, char **ptr_p)
Definition readfile.cc:5278
void * BLO_library_read_struct(FileData *fd, BHead *bh, const char *blockname)
Definition readfile.cc:4819
void BLO_read_float3_array(BlendDataReader *reader, const int64_t array_size, float **ptr_p)
Definition readfile.cc:5336
static bool is_minversion_older_than_blender(FileData *fd, ReportList *reports)
Definition readfile.cc:1153
void BLO_expand_main(void *fdhandle, Main *mainvar, BLOExpandDoitCallback callback)
Definition readfile.cc:4458
ID * BLO_read_get_new_id_address_from_session_uid(BlendLibReader *reader, const uint session_uid)
Definition readfile.cc:5234
void * BLO_read_get_new_data_address(BlendDataReader *reader, const void *old_address)
Definition readfile.cc:5193
ID_Readfile_Data::Tags & BLO_readfile_id_runtime_tags_for_write(ID &id)
Definition readfile.cc:2239
static Main * library_link_begin(Main *mainvar, FileData *fd, const char *filepath, const int id_tag_extra)
Definition readfile.cc:4570
static void blo_read_file_checks(Main *bmain)
Definition readfile.cc:3755
ID * BLO_library_link_named_part(Main *mainl, BlendHandle **bh, const short idcode, const char *name, const LibraryLink_Params *params)
Definition readfile.cc:4549
static bool blo_bhead_read_data(FileData *fd, BHead *thisblock, void *buf)
Definition readfile.cc:772
static Main * blo_find_main(FileData *fd, const char *filepath, const char *relabase)
Definition readfile.cc:534
static BHead * read_userdef(BlendFileData *bfd, FileData *fd, BHead *bhead)
Definition readfile.cc:3606
void blo_filedata_free(FileData *fd)
Definition readfile.cc:1410
static int * read_file_thumbnail(FileData *fd)
Definition readfile.cc:920
static bool blo_bhead_is_id_valid_type(const BHead *bhead)
Definition readfile.cc:497
static void * blo_verify_data_address(FileData *fd, void *new_address, const void *, const size_t expected_size)
Definition readfile.cc:5169
static void after_liblink_id_embedded_id_process(BlendLibReader *reader, ID *id)
Definition readfile.cc:2028
static FileData * change_ID_link_filedata_get(Main *bmain, FileData *basefd)
Definition readfile.cc:1574
BHead * blo_bhead_prev(FileData *, BHead *thisblock)
Definition readfile.cc:737
static void read_undo_move_libmain_data(FileData *fd, Main *new_main, Main *old_main, Main *libmain, BHead *bhead)
Definition readfile.cc:2766
void BLO_read_pointer_array(BlendDataReader *reader, const int64_t array_size, void **ptr_p)
Definition readfile.cc:5402
void blo_readfile_invalidate(FileData *fd, Main *bmain, const char *message)
Definition readfile.cc:586
static void read_blender_header(FileData *fd)
Definition readfile.cc:837
static void read_file_version(FileData *fd, Main *main)
Definition readfile.cc:454
static void * oldnewmap_lookup_and_inc(OldNewMap *onm, const void *addr, const bool increase_users)
Definition readfile.cc:290
void blo_cache_storage_old_bmain_clear(FileData *fd, Main *bmain_old)
Definition readfile.cc:1744
static CLG_LogRef LOG_UNDO
Definition readfile.cc:179
static FileData * blo_filedata_from_file_open(const char *filepath, BlendFileReadReport *reports)
Definition readfile.cc:1316
static int read_undo_remap_noundo_data_cb(LibraryIDLinkCallbackData *cb_data)
Definition readfile.cc:3711
static void * read_struct(FileData *fd, BHead *bh, const char *blockname, const int id_type_index)
Definition readfile.cc:1887
void blo_join_main(ListBase *mainlist)
Definition readfile.cc:355
static FileData * blo_decode_and_check(FileData *fd, ReportList *reports)
Definition readfile.cc:1199
void BLO_reportf_wrap(BlendFileReadReport *reports, const eReportType type, const char *format,...)
Definition readfile.cc:214
void * blo_read_get_new_globaldata_address(FileData *fd, const void *adr)
Definition readfile.cc:1523
static FileData * read_library_file_data(FileData *basefd, ListBase *mainlist, Main *mainl, Main *mainptr)
Definition readfile.cc:4997
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_450(FileData *fd, 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_450(FileData *fd, Library *lib, Main *bmain)
void do_versions_after_linking_410(FileData *fd, Main *bmain)
void blo_do_versions_250(FileData *fd, Library *lib, Main *bmain)
void blo_do_versions_410(FileData *fd, Library *lib, Main *bmain)
void do_versions_after_linking_400(FileData *fd, Main *bmain)
void do_versions_after_linking_430(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:49
@ FD_FLAGS_POINTSIZE_DIFFERS
Definition readfile.hh:50
@ FD_FLAGS_IS_MEMFILE
Definition readfile.hh:52
@ FD_FLAGS_FILE_OK
Definition readfile.hh:51
@ FD_FLAGS_SWITCH_ENDIAN
Definition readfile.hh:48
@ FD_FLAGS_FILE_FUTURE
Definition readfile.hh:57
@ FD_FLAGS_HAS_INVALID_ID_NAMES
Definition readfile.hh:62
void do_versions_after_linking_440(FileData *fd, Main *bmain)
void do_versions_after_linking_420(FileData *fd, Main *bmain)
void blo_do_versions_userdef(UserDef *userdef)
void blo_do_versions_420(FileData *fd, Library *lib, Main *bmain)
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 blo_do_versions_440(FileData *fd, Library *lib, Main *bmain)
void blo_do_versions_430(FileData *fd, Library *lib, Main *bmain)
void do_versions_after_linking_260(Main *bmain)
void blo_do_versions_260(FileData *fd, Library *lib, Main *bmain)
void blo_do_versions_pre250(FileData *fd, Library *lib, Main *bmain)
void blo_do_versions_280(FileData *fd, Library *lib, Main *bmain)
char identifier[66]
char last_slot_identifier[66]
char tmp_last_slot_identifier[66]
The meta-data of an asset. By creating and giving this for a data-block (ID.asset_data),...
off64_t file_offset
Definition readfile.cc:194
bool has_data
Definition readfile.cc:196
BHeadN * prev
Definition readfile.cc:191
bool is_memchunk_identical
Definition readfile.cc:198
BHead bhead
Definition readfile.cc:199
BHeadN * next
Definition readfile.cc:191
const void * old
Definition readfile.cc:4136
BHead * bhead
Definition readfile.cc:4135
int64_t len
int64_t nr
const void * old
MemArena * memarena
Definition readfile.cc:1620
GHash * cache_map
Definition readfile.cc:1619
blender::Map< const void *, blender::ImplicitSharingInfoAndData > shared_data_by_stored_address
Definition readfile.cc:615
FileData * fd
Definition readfile.cc:609
FileData * fd
Definition readfile.cc:4302
BLOExpandDoitCallback callback
Definition readfile.cc:4304
UserDef * user
ViewLayer * cur_view_layer
char filepath[1024]
eBlenFileType type
bScreen * curscreen
struct BlendFileReadReport::@142320212234231245113115306176140270124216310033 duration
struct BlendFileReadReport::@322005145130211163057315230271062050320025262277 count
FileData * fd
Definition readfile.cc:619
char rect[0]
Definition BKE_main.hh:50
BHeadType bhead_type() const
eBLOReadSkip skip_flags
Definition readfile.hh:120
int undo_direction
Definition readfile.hh:91
int id_asset_data_offset
Definition readfile.hh:114
ListBase * old_mainlist
Definition readfile.hh:149
enum eFileDataFlag flags
Definition readfile.hh:80
ListBase bhead_list
Definition readfile.hh:79
int fileversion
Definition readfile.hh:109
BlenderHeader blender_header
Definition readfile.hh:82
void * storage_handle
Definition readfile.hh:168
int fileflags
Definition readfile.hh:117
DNA_ReconstructInfo * reconstruct_info
Definition readfile.hh:107
BHeadSort * bheadmap
Definition readfile.hh:142
ListBase * mainlist
Definition readfile.hh:147
std::optional< blender::Map< blender::StringRefNull, BHead * > > bhead_idname_map
Definition readfile.hh:145
IDNameLib_Map * new_idmap_uid
Definition readfile.hh:163
OldNewMap * globmap
Definition readfile.hh:131
OldNewMap * datamap
Definition readfile.hh:130
int id_tag_extra
Definition readfile.hh:128
FileReader * file
Definition readfile.hh:84
char relabase[FILE_MAX]
Definition readfile.hh:100
const char * compflags
Definition readfile.hh:106
BLOCacheStorage * cache_storage
Definition readfile.hh:140
int globalf
Definition readfile.hh:116
int id_name_offset
Definition readfile.hh:111
OldNewMap * libmap
Definition readfile.hh:138
BlendFileReadReport * reports
Definition readfile.hh:165
bool is_eof
Definition readfile.hh:81
int tot_bheadmap
Definition readfile.hh:143
const SDNA * memsdna
Definition readfile.hh:104
IDNameLib_Map * old_idmap_uid
Definition readfile.hh:153
SDNA * filesdna
Definition readfile.hh:103
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:74
ListBase properties
Definition DNA_ID.h:326
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
struct ID_Readfile_Data * readfile_data
Definition DNA_ID.h:401
Definition DNA_ID.h:404
unsigned int recalc_after_undo_push
Definition DNA_ID.h:438
unsigned int recalc
Definition DNA_ID.h:427
int tag
Definition DNA_ID.h:424
struct AssetMetaData * asset_data
Definition DNA_ID.h:413
struct Library * lib
Definition DNA_ID.h:410
IDProperty * system_properties
Definition DNA_ID.h:454
int us
Definition DNA_ID.h:425
int icon_id
Definition DNA_ID.h:426
struct ID * newid
Definition DNA_ID.h:408
void * prev
Definition DNA_ID.h:407
IDProperty * properties
Definition DNA_ID.h:446
IDOverrideLibrary * override_library
Definition DNA_ID.h:459
struct ID * orig_id
Definition DNA_ID.h:466
short flag
Definition DNA_ID.h:420
char name[66]
Definition DNA_ID.h:415
unsigned int recalc_up_to_undo_push
Definition DNA_ID.h:437
unsigned int session_uid
Definition DNA_ID.h:444
struct LibraryWeakReference * library_weak_reference
Definition DNA_ID.h:491
struct ID_Runtime runtime
Definition DNA_ID.h:493
int uidgen
ListBase block
LibraryForeachIDCallbackFlag cb_flag
struct PackedFile * packedfile
Definition DNA_ID.h:509
char filepath[1024]
Definition DNA_ID.h:507
ID id
Definition DNA_ID.h:505
LibraryRuntimeHandle * runtime
Definition DNA_ID.h:516
void * last
void * first
ListBase scenes
Definition BKE_main.hh:245
ListBase wm
Definition BKE_main.hh:276
short subversionfile
Definition BKE_main.hh:156
bool is_asset_edit_file
Definition BKE_main.hh:171
bool has_forward_compatibility_issues
Definition BKE_main.hh:164
char filepath[1024]
Definition BKE_main.hh:155
BlendThumbnail * blen_thumb
Definition BKE_main.hh:231
Main * prev
Definition BKE_main.hh:142
short minversionfile
Definition BKE_main.hh:157
uint64_t build_commit_timestamp
Definition BKE_main.hh:174
ListBase libraries
Definition BKE_main.hh:246
IDNameLib_Map * id_map
Definition BKE_main.hh:301
char build_hash[16]
Definition BKE_main.hh:176
Main * next
Definition BKE_main.hh:142
short minsubversionfile
Definition BKE_main.hh:157
short versionfile
Definition BKE_main.hh:156
bool is_read_invalid
Definition BKE_main.hh:203
Library * curlib
Definition BKE_main.hh:241
ListBase objects
Definition BKE_main.hh:247
blender::Map< const void *, const blender::ImplicitSharingInfo * > map
MemFileSharedStorage * shared_storage
void * newp
Definition readfile.cc:249
char last_slot_identifier[66]
ListBase constraints
struct bPose * pose
blender::Map< const void *, NewAddress > map
Definition readfile.cc:256
int pointer_size
struct Collection * master_collection
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 ActionSlot ** slot_array
ListBase chanbase
struct IDProperty * prop
struct PointerRNA * ptr
i
Definition text_draw.cc:230
uint len
void version_forward_compat_system_idprops(Main *bmain)
short do_versions_new_to_old_idcode_get(const short id_code_new)
static DynamicLibrary lib
uint8_t flag
Definition wm_window.cc:139