Blender V4.5
blend_validate.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
13
14#include "CLG_log.h"
15
16#include "BLI_listbase.h"
17#include "BLI_utildefines.h"
18
19#include "BLI_linklist.h"
20
22#include "DNA_key_types.h"
23#include "DNA_node_types.h"
25
26#include "BKE_key.hh"
27#include "BKE_lib_id.hh"
28#include "BKE_lib_remap.hh"
29#include "BKE_library.hh"
30#include "BKE_main.hh"
31#include "BKE_node.hh"
32#include "BKE_report.hh"
33
34#include "BLO_blend_validate.hh"
35#include "BLO_readfile.hh"
36
37#include "readfile.hh"
38
39static CLG_LogRef LOG = {"blo.blend_validate"};
40
42{
43 ListBase mainlist;
44 bool is_valid = true;
45
46 BKE_main_lock(bmain);
47
48 blo_split_main(&mainlist, bmain);
49
50 MainListsArray lbarray = BKE_main_lists_get(*bmain);
51 int i = lbarray.size();
52 while (i--) {
53 for (ID *id = static_cast<ID *>(lbarray[i]->first); id != nullptr;
54 id = static_cast<ID *>(id->next))
55 {
56 if (ID_IS_LINKED(id)) {
57 is_valid = false;
60 "ID %s is in local database while being linked from library %s!",
61 id->name,
62 id->lib->filepath);
63 }
64 }
65 }
66
67 for (Main *curmain = bmain->next; curmain != nullptr; curmain = curmain->next) {
68 Library *curlib = curmain->curlib;
69 if (curlib == nullptr) {
70 BKE_report(reports, RPT_ERROR, "Library database with null library data-block pointer!");
71 continue;
72 }
73
74 BKE_library_filepath_set(bmain, curlib, curlib->filepath);
75 BlendFileReadReport bf_reports{};
76 bf_reports.reports = reports;
77 BlendHandle *bh = BLO_blendhandle_from_file(curlib->runtime->filepath_abs, &bf_reports);
78
79 if (bh == nullptr) {
82 "Library ID %s not found at expected path %s!",
83 curlib->id.name,
84 curlib->runtime->filepath_abs);
85 continue;
86 }
87
88 lbarray = BKE_main_lists_get(*curmain);
89 i = lbarray.size();
90 while (i--) {
91 ID *id = static_cast<ID *>(lbarray[i]->first);
92 if (id == nullptr) {
93 continue;
94 }
95
96 if (GS(id->name) == ID_LI) {
97 is_valid = false;
100 "Library ID %s in library %s, this should not happen!",
101 id->name,
102 curlib->filepath);
103 continue;
104 }
105
106 int totnames = 0;
107 LinkNode *names = BLO_blendhandle_get_datablock_names(bh, GS(id->name), false, &totnames);
108 for (; id != nullptr; id = static_cast<ID *>(id->next)) {
109 if (!ID_IS_LINKED(id)) {
110 is_valid = false;
112 RPT_ERROR,
113 "ID %s has null lib pointer while being in library %s!",
114 id->name,
115 curlib->filepath);
116 continue;
117 }
118 if (id->lib != curlib) {
119 is_valid = false;
120 BKE_reportf(reports, RPT_ERROR, "ID %s has mismatched lib pointer!", id->name);
121 continue;
122 }
123
124 LinkNode *name = names;
125 for (; name; name = name->next) {
126 const char *str_name = (const char *)name->link;
127 if (id->name[2] == str_name[0] && STREQ(str_name, id->name + 2)) {
128 break;
129 }
130 }
131
132 if (name == nullptr) {
133 is_valid = false;
135 RPT_ERROR,
136 "ID %s not found in library %s anymore!",
137 id->name,
138 id->lib->filepath);
139 continue;
140 }
141 }
142
143 BLI_linklist_freeN(names);
144 }
145
147 }
148
149 blo_join_main(&mainlist);
150
152 BLI_assert(mainlist.first == (void *)bmain);
153
154 BKE_main_unlock(bmain);
155
156 return is_valid;
157}
158
160{
161 ListBase *lb;
162 ID *id;
163 bool is_valid = true;
164
165 BKE_main_lock(bmain);
166
167 FOREACH_MAIN_LISTBASE_BEGIN (bmain, lb) {
169 if (!BKE_key_idtype_support(GS(id->name))) {
170 break;
171 }
172 if (!ID_IS_LINKED(id)) {
173 /* We assume lib data is valid... */
174 Key *shapekey = BKE_key_from_id(id);
175 if (shapekey != nullptr && shapekey->from != id) {
176 is_valid = false;
178 RPT_ERROR,
179 "ID %s uses shapekey %s, but its 'from' pointer is invalid (%p), fixing...",
180 id->name,
181 shapekey->id.name,
182 shapekey->from);
183 shapekey->from = id;
184 }
185 }
186 }
188 }
190
191 BKE_main_unlock(bmain);
192
193 /* NOTE: #BKE_id_delete also locks `bmain`, so we need to do this loop outside of the lock here.
194 */
195 LISTBASE_FOREACH_MUTABLE (Key *, shapekey, &bmain->shapekeys) {
196 if (shapekey->from != nullptr) {
197 continue;
198 }
199
201 RPT_ERROR,
202 "Shapekey %s has an invalid 'from' pointer (%p), it will be deleted",
203 shapekey->id.name,
204 shapekey->from);
205 /* NOTE: also need to remap UI data ID pointers here, since `bmain` is not the current
206 * `G_MAIN`, default UI-handling remapping callback (defined by call to
207 * `BKE_library_callback_remap_editor_id_reference_set`) won't work on expected data here. */
209 }
210
211 return is_valid;
212}
213
215{
216 ID *id_iter;
217 FOREACH_MAIN_ID_BEGIN (bmain, id_iter) {
218 bNodeTree *node_tree = blender::bke::node_tree_from_id(id_iter);
219 if (node_tree) {
220 if (node_tree->id.flag & ID_FLAG_EMBEDDED_DATA_LIB_OVERRIDE) {
221 if (!ID_IS_OVERRIDE_LIBRARY(id_iter)) {
223 }
224 }
225 }
226
227 if (GS(id_iter->name) == ID_SCE) {
228 Scene *scene = reinterpret_cast<Scene *>(id_iter);
229 if (scene->master_collection &&
231 {
233 }
234 }
235 }
237}
238
240{
241 ID *id_iter;
242 FOREACH_MAIN_ID_BEGIN (bmain, id_iter) {
243 if (id_iter->flag & ID_FLAG_EMBEDDED_DATA) {
245 &LOG, "ID %s is flagged as embedded, while existing in Main data-base", id_iter->name);
246 id_iter->flag &= ~ID_FLAG_EMBEDDED_DATA;
247 }
248
249 bNodeTree *node_tree = blender::bke::node_tree_from_id(id_iter);
250 if (node_tree) {
251 if ((node_tree->id.flag & ID_FLAG_EMBEDDED_DATA) == 0) {
253 "ID %s has an embedded nodetree which is not flagged as embedded",
254 id_iter->name);
255 node_tree->id.flag |= ID_FLAG_EMBEDDED_DATA;
256 }
257 }
258
259 if (GS(id_iter->name) == ID_SCE) {
260 Scene *scene = reinterpret_cast<Scene *>(id_iter);
261 if (scene->master_collection &&
263 {
265 "ID %s has an embedded Collection which is not flagged as embedded",
266 id_iter->name);
268 }
269 }
270 }
272}
Key * BKE_key_from_id(ID *id)
Definition key.cc:1804
bool BKE_key_idtype_support(short id_type)
Definition key.cc:1767
void BKE_id_delete_ex(Main *bmain, void *idv, const int extra_remapping_flags) ATTR_NONNULL(1
@ ID_REMAP_FORCE_UI_POINTERS
void BKE_library_filepath_set(Main *bmain, Library *lib, const char *filepath)
Definition library.cc:171
#define FOREACH_MAIN_ID_END
Definition BKE_main.hh:563
MainListsArray BKE_main_lists_get(Main &bmain)
Definition main.cc:969
#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
void BKE_main_lock(Main *bmain)
Definition main.cc:479
#define FOREACH_MAIN_LISTBASE_BEGIN(_bmain, _lb)
Definition BKE_main.hh:537
#define FOREACH_MAIN_ID_BEGIN(_bmain, _id)
Definition BKE_main.hh:557
void BKE_main_unlock(Main *bmain)
Definition main.cc:484
void BKE_reportf(ReportList *reports, eReportType type, const char *format,...) ATTR_PRINTF_FORMAT(3
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition report.cc:126
#define BLI_assert(a)
Definition BLI_assert.h:46
#define LISTBASE_FOREACH_MUTABLE(type, var, list)
void void BLI_INLINE bool BLI_listbase_is_single(const ListBase *lb)
#define STREQ(a, b)
Utilities ensuring .blend file (i.e. Main) is in valid state during write and/or read process.
external readfile function prototypes.
BlendHandle * BLO_blendhandle_from_file(const char *filepath, BlendFileReadReport *reports)
void BLO_blendhandle_close(BlendHandle *bh) ATTR_NONNULL(1)
LinkNode * BLO_blendhandle_get_datablock_names(BlendHandle *bh, int ofblocktype, bool use_assets_only, int *r_tot_names)
#define CLOG_ERROR(clg_ref,...)
Definition CLG_log.h:182
@ ID_FLAG_EMBEDDED_DATA_LIB_OVERRIDE
Definition DNA_ID.h:698
@ ID_FLAG_EMBEDDED_DATA
Definition DNA_ID.h:687
@ ID_LI
@ ID_SCE
Object groups, one object can be in many groups at once.
ReportList * reports
Definition WM_types.hh:1025
void BLO_main_validate_embedded_liboverrides(Main *bmain, ReportList *)
void BLO_main_validate_embedded_flag(Main *bmain, ReportList *)
bool BLO_main_validate_libraries(Main *bmain, ReportList *reports)
bool BLO_main_validate_shapekeys(Main *bmain, ReportList *reports)
#define ID_IS_LINKED(_id)
#define ID_IS_OVERRIDE_LIBRARY(_id)
#define GS(a)
#define LOG(severity)
Definition log.h:32
bNodeTree * node_tree_from_id(ID *id)
Definition node.cc:4840
void blo_split_main(ListBase *mainlist, Main *main)
Definition readfile.cc:402
void blo_join_main(ListBase *mainlist)
Definition readfile.cc:355
Definition DNA_ID.h:404
struct Library * lib
Definition DNA_ID.h:410
short flag
Definition DNA_ID.h:420
char name[66]
Definition DNA_ID.h:415
ID * from
char filepath[1024]
Definition DNA_ID.h:507
ID id
Definition DNA_ID.h:505
LibraryRuntimeHandle * runtime
Definition DNA_ID.h:516
void * link
struct LinkNode * next
void * first
ListBase shapekeys
Definition BKE_main.hh:259
Main * next
Definition BKE_main.hh:142
struct Collection * master_collection
i
Definition text_draw.cc:230