Blender V5.0
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 = {"blend.validate"};
40
42{
43 blo_split_main(bmain);
44 BLI_assert(bmain->split_mains);
45 blender::VectorSet<Main *> &split_mains = *bmain->split_mains;
46 BLI_assert(split_mains[0] == bmain);
47 bool is_valid = true;
48
49 BKE_main_lock(bmain);
50
51 MainListsArray lbarray = BKE_main_lists_get(*bmain);
52 int i = lbarray.size();
53 while (i--) {
54 for (ID *id = static_cast<ID *>(lbarray[i]->first); id != nullptr;
55 id = static_cast<ID *>(id->next))
56 {
57 if (ID_IS_LINKED(id)) {
58 is_valid = false;
59 BKE_reportf(reports,
61 "ID %s is in local database while being linked from library %s!",
62 id->name,
63 id->lib->filepath);
64 }
65 }
66 }
67
68 for (Main *curmain : split_mains) {
69 if (curmain == bmain) {
70 continue;
71 }
72 Library *curlib = curmain->curlib;
73 if (curlib == nullptr) {
74 BKE_report(reports, RPT_ERROR, "Library database with null library data-block pointer!");
75 continue;
76 }
77
78 BKE_library_filepath_set(bmain, curlib, curlib->filepath);
79 BlendFileReadReport bf_reports{};
80 bf_reports.reports = reports;
81 BlendHandle *bh = BLO_blendhandle_from_file(curlib->runtime->filepath_abs, &bf_reports);
82
83 if (bh == nullptr) {
84 BKE_reportf(reports,
86 "Library ID %s not found at expected path %s!",
87 curlib->id.name,
88 curlib->runtime->filepath_abs);
89 continue;
90 }
91
92 lbarray = BKE_main_lists_get(*curmain);
93 i = lbarray.size();
94 while (i--) {
95 ID *id = static_cast<ID *>(lbarray[i]->first);
96 if (id == nullptr) {
97 continue;
98 }
99
100 if (GS(id->name) == ID_LI) {
101 is_valid = false;
102 BKE_reportf(reports,
103 RPT_ERROR,
104 "Library ID %s in library %s, this should not happen!",
105 id->name,
106 curlib->filepath);
107 continue;
108 }
109
110 int totnames = 0;
111 LinkNode *names = BLO_blendhandle_get_datablock_names(bh, GS(id->name), false, &totnames);
112 for (; id != nullptr; id = static_cast<ID *>(id->next)) {
113 if (!ID_IS_LINKED(id)) {
114 is_valid = false;
115 BKE_reportf(reports,
116 RPT_ERROR,
117 "ID %s has null lib pointer while being in library %s!",
118 id->name,
119 curlib->filepath);
120 continue;
121 }
122 if (id->lib != curlib) {
123 is_valid = false;
124 BKE_reportf(reports, RPT_ERROR, "ID %s has mismatched lib pointer!", id->name);
125 continue;
126 }
127
128 LinkNode *name = names;
129 for (; name; name = name->next) {
130 const char *str_name = (const char *)name->link;
131 if (id->name[2] == str_name[0] && STREQ(str_name, id->name + 2)) {
132 break;
133 }
134 }
135
136 if (name == nullptr) {
137 is_valid = false;
138 BKE_reportf(reports,
139 RPT_ERROR,
140 "ID %s not found in library %s anymore!",
141 id->name,
142 id->lib->filepath);
143 continue;
144 }
145 }
146
147 BLI_linklist_freeN(names);
148 }
149
151 }
152
153 blo_join_main(bmain);
154 BLI_assert(!bmain->split_mains);
155
156 BKE_main_unlock(bmain);
157
158 return is_valid;
159}
160
162{
163 ListBase *lb;
164 ID *id;
165 bool is_valid = true;
166
167 BKE_main_lock(bmain);
168
169 FOREACH_MAIN_LISTBASE_BEGIN (bmain, lb) {
171 if (!BKE_key_idtype_support(GS(id->name))) {
172 break;
173 }
174 if (!ID_IS_LINKED(id)) {
175 /* We assume lib data is valid... */
176 Key *shapekey = BKE_key_from_id(id);
177 if (shapekey != nullptr && shapekey->from != id) {
178 is_valid = false;
179 BKE_reportf(reports,
180 RPT_ERROR,
181 "ID %s uses shapekey %s, but its 'from' pointer is invalid (%p), fixing...",
182 id->name,
183 shapekey->id.name,
184 shapekey->from);
185 shapekey->from = id;
186 }
187 }
188 }
190 }
192
193 BKE_main_unlock(bmain);
194
195 /* NOTE: #BKE_id_delete also locks `bmain`, so we need to do this loop outside of the lock here.
196 */
197 LISTBASE_FOREACH_MUTABLE (Key *, shapekey, &bmain->shapekeys) {
198 if (shapekey->from != nullptr) {
199 continue;
200 }
201
202 BKE_reportf(reports,
203 RPT_ERROR,
204 "ShapeKey %s has an invalid 'from' pointer (%p), it will be deleted",
205 shapekey->id.name,
206 shapekey->from);
207 /* NOTE: also need to remap UI data ID pointers here, since `bmain` is not the current
208 * `G_MAIN`, default UI-handling remapping callback (defined by call to
209 * `BKE_library_callback_remap_editor_id_reference_set`) won't work on expected data here. */
211 }
212
213 return is_valid;
214}
215
217{
218 ID *id_iter;
219 FOREACH_MAIN_ID_BEGIN (bmain, id_iter) {
220 bNodeTree *node_tree = blender::bke::node_tree_from_id(id_iter);
221 if (node_tree) {
222 if (node_tree->id.flag & ID_FLAG_EMBEDDED_DATA_LIB_OVERRIDE) {
223 if (!ID_IS_OVERRIDE_LIBRARY(id_iter)) {
225 }
226 }
227 }
228
229 if (GS(id_iter->name) == ID_SCE) {
230 Scene *scene = reinterpret_cast<Scene *>(id_iter);
231 if (scene->master_collection &&
233 {
235 }
236 }
237 }
239}
240
242{
243 ID *id_iter;
244 FOREACH_MAIN_ID_BEGIN (bmain, id_iter) {
245 if (id_iter->flag & ID_FLAG_EMBEDDED_DATA) {
247 &LOG, "ID %s is flagged as embedded, while existing in Main data-base", id_iter->name);
248 id_iter->flag &= ~ID_FLAG_EMBEDDED_DATA;
249 }
250
251 bNodeTree *node_tree = blender::bke::node_tree_from_id(id_iter);
252 if (node_tree) {
253 if ((node_tree->id.flag & ID_FLAG_EMBEDDED_DATA) == 0) {
255 "ID %s has an embedded nodetree which is not flagged as embedded",
256 id_iter->name);
257 node_tree->id.flag |= ID_FLAG_EMBEDDED_DATA;
258 }
259 }
260
261 if (GS(id_iter->name) == ID_SCE) {
262 Scene *scene = reinterpret_cast<Scene *>(id_iter);
263 if (scene->master_collection &&
265 {
267 "ID %s has an embedded Collection which is not flagged as embedded",
268 id_iter->name);
270 }
271 }
272 }
274}
Key * BKE_key_from_id(ID *id)
Definition key.cc:1771
bool BKE_key_idtype_support(short id_type)
Definition key.cc:1734
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:229
#define FOREACH_MAIN_ID_END
Definition BKE_main.hh:583
MainListsArray BKE_main_lists_get(Main &bmain)
Definition main.cc:987
#define FOREACH_MAIN_LISTBASE_ID_END
Definition BKE_main.hh:552
std::array< ListBase *, INDEX_ID_MAX - 1 > MainListsArray
Definition BKE_main.hh:645
#define FOREACH_MAIN_LISTBASE_ID_BEGIN(_lb, _id)
Definition BKE_main.hh:546
#define FOREACH_MAIN_LISTBASE_END
Definition BKE_main.hh:564
void BKE_main_lock(Main *bmain)
Definition main.cc:486
#define FOREACH_MAIN_LISTBASE_BEGIN(_bmain, _lb)
Definition BKE_main.hh:557
#define FOREACH_MAIN_ID_BEGIN(_bmain, _id)
Definition BKE_main.hh:577
void BKE_main_unlock(Main *bmain)
Definition main.cc:491
void BKE_reportf(ReportList *reports, eReportType type, const char *format,...) ATTR_PRINTF_FORMAT(3
@ RPT_ERROR
Definition BKE_report.hh:39
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition report.cc:153
#define BLI_assert(a)
Definition BLI_assert.h:46
#define LISTBASE_FOREACH_MUTABLE(type, var, list)
#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:188
#define ID_IS_LINKED(_id)
Definition DNA_ID.h:694
#define ID_IS_OVERRIDE_LIBRARY(_id)
Definition DNA_ID.h:730
@ ID_FLAG_EMBEDDED_DATA_LIB_OVERRIDE
Definition DNA_ID.h:785
@ ID_FLAG_EMBEDDED_DATA
Definition DNA_ID.h:774
@ ID_LI
@ ID_SCE
Object groups, one object can be in many groups at once.
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 GS(x)
#define LOG(level)
Definition log.h:97
bNodeTree * node_tree_from_id(ID *id)
Definition node.cc:4568
const char * name
void blo_join_main(Main *bmain)
Definition readfile.cc:359
void blo_split_main(Main *bmain, const bool do_split_packed_ids)
Definition readfile.cc:415
Definition DNA_ID.h:414
struct Library * lib
Definition DNA_ID.h:420
char name[258]
Definition DNA_ID.h:432
short flag
Definition DNA_ID.h:438
ID * from
char filepath[1024]
Definition DNA_ID.h:552
ID id
Definition DNA_ID.h:550
LibraryRuntimeHandle * runtime
Definition DNA_ID.h:579
ListBase shapekeys
Definition BKE_main.hh:290
std::shared_ptr< blender::VectorSet< Main * > > split_mains
Definition BKE_main.hh:166
struct Collection * master_collection
i
Definition text_draw.cc:230