Blender V4.3
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
14#include <cstring> /* for #strrchr #strncmp #strstr */
15
16#include "CLG_log.h"
17
18#include "BLI_utildefines.h"
19
20#include "BLI_linklist.h"
21
22#include "MEM_guardedalloc.h"
23
25#include "DNA_key_types.h"
26#include "DNA_node_types.h"
27#include "DNA_sdna_types.h"
29
30#include "BKE_key.hh"
31#include "BKE_lib_id.hh"
32#include "BKE_lib_remap.hh"
33#include "BKE_library.hh"
34#include "BKE_main.hh"
35#include "BKE_node.hh"
36#include "BKE_report.hh"
37
38#include "BLO_blend_validate.hh"
39#include "BLO_readfile.hh"
40
41#include "readfile.hh"
42
43static CLG_LogRef LOG = {"blo.blend_validate"};
44
46{
47 ListBase mainlist;
48 bool is_valid = true;
49
50 BKE_main_lock(bmain);
51
52 blo_split_main(&mainlist, bmain);
53
54 ListBase *lbarray[INDEX_ID_MAX];
55 int i = set_listbasepointers(bmain, lbarray);
56 while (i--) {
57 for (ID *id = static_cast<ID *>(lbarray[i]->first); id != nullptr;
58 id = static_cast<ID *>(id->next))
59 {
60 if (ID_IS_LINKED(id)) {
61 is_valid = false;
62 BKE_reportf(reports,
64 "ID %s is in local database while being linked from library %s!",
65 id->name,
66 id->lib->filepath);
67 }
68 }
69 }
70
71 for (Main *curmain = bmain->next; curmain != nullptr; curmain = curmain->next) {
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 i = set_listbasepointers(curmain, lbarray);
93 while (i--) {
94 ID *id = static_cast<ID *>(lbarray[i]->first);
95 if (id == nullptr) {
96 continue;
97 }
98
99 if (GS(id->name) == ID_LI) {
100 is_valid = false;
101 BKE_reportf(reports,
102 RPT_ERROR,
103 "Library ID %s in library %s, this should not happen!",
104 id->name,
105 curlib->filepath);
106 continue;
107 }
108
109 int totnames = 0;
110 LinkNode *names = BLO_blendhandle_get_datablock_names(bh, GS(id->name), false, &totnames);
111 for (; id != nullptr; id = static_cast<ID *>(id->next)) {
112 if (!ID_IS_LINKED(id)) {
113 is_valid = false;
114 BKE_reportf(reports,
115 RPT_ERROR,
116 "ID %s has null lib pointer while being in library %s!",
117 id->name,
118 curlib->filepath);
119 continue;
120 }
121 if (id->lib != curlib) {
122 is_valid = false;
123 BKE_reportf(reports, RPT_ERROR, "ID %s has mismatched lib pointer!", id->name);
124 continue;
125 }
126
127 LinkNode *name = names;
128 for (; name; name = name->next) {
129 const char *str_name = (const char *)name->link;
130 if (id->name[2] == str_name[0] && STREQ(str_name, id->name + 2)) {
131 break;
132 }
133 }
134
135 if (name == nullptr) {
136 is_valid = false;
137 BKE_reportf(reports,
138 RPT_ERROR,
139 "ID %s not found in library %s anymore!",
140 id->name,
141 id->lib->filepath);
142 continue;
143 }
144 }
145
146 BLI_linklist_freeN(names);
147 }
148
150 }
151
152 blo_join_main(&mainlist);
153
155 BLI_assert(mainlist.first == (void *)bmain);
156
157 BKE_main_unlock(bmain);
158
159 return is_valid;
160}
161
163{
164 ListBase *lb;
165 ID *id;
166 bool is_valid = true;
167
168 BKE_main_lock(bmain);
169
170 FOREACH_MAIN_LISTBASE_BEGIN (bmain, lb) {
172 if (!BKE_key_idtype_support(GS(id->name))) {
173 break;
174 }
175 if (!ID_IS_LINKED(id)) {
176 /* We assume lib data is valid... */
177 Key *shapekey = BKE_key_from_id(id);
178 if (shapekey != nullptr && shapekey->from != id) {
179 is_valid = false;
180 BKE_reportf(reports,
181 RPT_ERROR,
182 "ID %s uses shapekey %s, but its 'from' pointer is invalid (%p), fixing...",
183 id->name,
184 shapekey->id.name,
185 shapekey->from);
186 shapekey->from = id;
187 }
188 }
189 }
191 }
193
194 BKE_main_unlock(bmain);
195
196 /* NOTE: #BKE_id_delete also locks `bmain`, so we need to do this loop outside of the lock here.
197 */
198 LISTBASE_FOREACH_MUTABLE (Key *, shapekey, &bmain->shapekeys) {
199 if (shapekey->from != nullptr) {
200 continue;
201 }
202
203 BKE_reportf(reports,
204 RPT_ERROR,
205 "Shapekey %s has an invalid 'from' pointer (%p), it will be deleted",
206 shapekey->id.name,
207 shapekey->from);
208 /* NOTE: also need to remap UI data ID pointers here, since `bmain` is not the current
209 * `G_MAIN`, default UI-handling remapping callback (defined by call to
210 * `BKE_library_callback_remap_editor_id_reference_set`) won't work on expected data here. */
212 }
213
214 return is_valid;
215}
216
218{
219 ID *id_iter;
220 FOREACH_MAIN_ID_BEGIN (bmain, id_iter) {
222 if (node_tree) {
224 if (!ID_IS_OVERRIDE_LIBRARY(id_iter)) {
225 node_tree->id.flag &= ~ID_FLAG_EMBEDDED_DATA_LIB_OVERRIDE;
226 }
227 }
228 }
229
230 if (GS(id_iter->name) == ID_SCE) {
231 Scene *scene = reinterpret_cast<Scene *>(id_iter);
232 if (scene->master_collection &&
233 (scene->master_collection->id.flag & ID_FLAG_EMBEDDED_DATA_LIB_OVERRIDE))
234 {
235 scene->master_collection->id.flag &= ~ID_FLAG_EMBEDDED_DATA_LIB_OVERRIDE;
236 }
237 }
238 }
240}
241
243{
244 ID *id_iter;
245 FOREACH_MAIN_ID_BEGIN (bmain, id_iter) {
246 if (id_iter->flag & ID_FLAG_EMBEDDED_DATA) {
248 &LOG, "ID %s is flagged as embedded, while existing in Main data-base", id_iter->name);
249 id_iter->flag &= ~ID_FLAG_EMBEDDED_DATA;
250 }
251
253 if (node_tree) {
254 if ((node_tree->id.flag & ID_FLAG_EMBEDDED_DATA) == 0) {
256 "ID %s has an embedded nodetree which is not flagged as embedded",
257 id_iter->name);
259 }
260 }
261
262 if (GS(id_iter->name) == ID_SCE) {
263 Scene *scene = reinterpret_cast<Scene *>(id_iter);
264 if (scene->master_collection &&
265 (scene->master_collection->id.flag & ID_FLAG_EMBEDDED_DATA) == 0)
266 {
268 "ID %s has an embedded Collection which is not flagged as embedded",
269 id_iter->name);
270 scene->master_collection->id.flag |= ID_FLAG_EMBEDDED_DATA;
271 }
272 }
273 }
275}
Key * BKE_key_from_id(ID *id)
Definition key.cc:1800
bool BKE_key_idtype_support(short id_type)
Definition key.cc:1763
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:135
#define FOREACH_MAIN_ID_END
Definition BKE_main.hh:500
#define FOREACH_MAIN_LISTBASE_ID_END
Definition BKE_main.hh:469
#define FOREACH_MAIN_LISTBASE_ID_BEGIN(_lb, _id)
Definition BKE_main.hh:463
#define FOREACH_MAIN_LISTBASE_END
Definition BKE_main.hh:481
void BKE_main_lock(Main *bmain)
Definition main.cc:479
int set_listbasepointers(Main *bmain, ListBase *lb[])
Definition main.cc:929
#define FOREACH_MAIN_LISTBASE_BEGIN(_bmain, _lb)
Definition BKE_main.hh:474
#define FOREACH_MAIN_ID_BEGIN(_bmain, _id)
Definition BKE_main.hh:494
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:125
#define BLI_assert(a)
Definition BLI_assert.h:50
#define LISTBASE_FOREACH_MUTABLE(type, var, list)
void void BLI_INLINE bool BLI_listbase_is_single(const struct 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
#define ID_IS_LINKED(_id)
Definition DNA_ID.h:654
@ ID_FLAG_EMBEDDED_DATA_LIB_OVERRIDE
Definition DNA_ID.h:736
@ ID_FLAG_EMBEDDED_DATA
Definition DNA_ID.h:725
#define INDEX_ID_MAX
Definition DNA_ID.h:1328
#define ID_IS_OVERRIDE_LIBRARY(_id)
Definition DNA_ID.h:683
@ ID_LI
@ ID_SCE
Object groups, one object can be in many groups at once.
Read Guarded memory(de)allocation.
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)
static CLG_LogRef LOG
#define GS(x)
Definition iris.cc:202
bNodeTree * node_tree_from_id(ID *id)
Definition node.cc:3732
void blo_split_main(ListBase *mainlist, Main *main)
Definition readfile.cc:397
void blo_join_main(ListBase *mainlist)
Definition readfile.cc:350
Definition DNA_ID.h:413
short flag
Definition DNA_ID.h:430
char name[66]
Definition DNA_ID.h:425
ID * from
char filepath_abs[1024]
Definition DNA_ID.h:509
char filepath[1024]
Definition DNA_ID.h:531
struct Library_Runtime runtime
Definition DNA_ID.h:535
ID id
Definition DNA_ID.h:529
void * link
void * first
ListBase shapekeys
Definition BKE_main.hh:223
Main * next
Definition BKE_main.hh:123
struct Collection * master_collection