Blender  V2.93
blend_validate.c
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  */
16 
26 #include <string.h> /* for #strrchr #strncmp #strstr */
27 
28 #include "BLI_utildefines.h"
29 
30 #include "BLI_blenlib.h"
31 #include "BLI_linklist.h"
32 
33 #include "MEM_guardedalloc.h"
34 
35 #include "DNA_key_types.h"
36 #include "DNA_sdna_types.h"
38 
39 #include "BKE_key.h"
40 #include "BKE_lib_id.h"
41 #include "BKE_library.h"
42 #include "BKE_main.h"
43 #include "BKE_report.h"
44 
45 #include "BLO_blend_validate.h"
46 #include "BLO_readfile.h"
47 
48 #include "readfile.h"
49 
55 {
56  ListBase mainlist;
57  bool is_valid = true;
58 
59  BKE_main_lock(bmain);
60 
61  blo_split_main(&mainlist, bmain);
62 
63  ListBase *lbarray[INDEX_ID_MAX];
64  int i = set_listbasepointers(bmain, lbarray);
65  while (i--) {
66  for (ID *id = lbarray[i]->first; id != NULL; id = id->next) {
67  if (id->lib != NULL) {
68  is_valid = false;
69  BKE_reportf(reports,
70  RPT_ERROR,
71  "ID %s is in local database while being linked from library %s!",
72  id->name,
73  id->lib->filepath);
74  }
75  }
76  }
77 
78  for (Main *curmain = bmain->next; curmain != NULL; curmain = curmain->next) {
79  Library *curlib = curmain->curlib;
80  if (curlib == NULL) {
81  BKE_report(reports, RPT_ERROR, "Library database with NULL library data-block!");
82  continue;
83  }
84 
85  BKE_library_filepath_set(bmain, curlib, curlib->filepath);
86  BlendHandle *bh = BLO_blendhandle_from_file(curlib->filepath_abs, reports);
87 
88  if (bh == NULL) {
89  BKE_reportf(reports,
90  RPT_ERROR,
91  "Library ID %s not found at expected path %s!",
92  curlib->id.name,
93  curlib->filepath_abs);
94  continue;
95  }
96 
97  i = set_listbasepointers(curmain, lbarray);
98  while (i--) {
99  ID *id = lbarray[i]->first;
100  if (id == NULL) {
101  continue;
102  }
103 
104  if (GS(id->name) == ID_LI) {
105  is_valid = false;
106  BKE_reportf(reports,
107  RPT_ERROR,
108  "Library ID %s in library %s, this should not happen!",
109  id->name,
110  curlib->filepath);
111  continue;
112  }
113 
114  int totnames = 0;
115  LinkNode *names = BLO_blendhandle_get_datablock_names(bh, GS(id->name), false, &totnames);
116  for (; id != NULL; id = id->next) {
117  if (id->lib == NULL) {
118  is_valid = false;
119  BKE_reportf(reports,
120  RPT_ERROR,
121  "ID %s has NULL lib pointer while being in library %s!",
122  id->name,
123  curlib->filepath);
124  continue;
125  }
126  if (id->lib != curlib) {
127  is_valid = false;
128  BKE_reportf(reports, RPT_ERROR, "ID %s has mismatched lib pointer!", id->name);
129  continue;
130  }
131 
132  LinkNode *name = names;
133  for (; name; name = name->next) {
134  char *str_name = (char *)name->link;
135  if (id->name[2] == str_name[0] && STREQ(str_name, id->name + 2)) {
136  break;
137  }
138  }
139 
140  if (name == NULL) {
141  is_valid = false;
142  BKE_reportf(reports,
143  RPT_ERROR,
144  "ID %s not found in library %s anymore!",
145  id->name,
146  id->lib->filepath);
147  continue;
148  }
149  }
150 
152  }
153 
155  }
156 
157  blo_join_main(&mainlist);
158 
160  BLI_assert(mainlist.first == (void *)bmain);
161 
162  BKE_main_unlock(bmain);
163 
164  return is_valid;
165 }
166 
169 {
170  ListBase *lb;
171  ID *id;
172  bool is_valid = true;
173 
174  BKE_main_lock(bmain);
175 
176  FOREACH_MAIN_LISTBASE_BEGIN (bmain, lb) {
178  if (!BKE_key_idtype_support(GS(id->name))) {
179  break;
180  }
181  if (id->lib == NULL) {
182  /* We assume lib data is valid... */
183  Key *shapekey = BKE_key_from_id(id);
184  if (shapekey != NULL && shapekey->from != id) {
185  is_valid = false;
186  BKE_reportf(reports,
187  RPT_ERROR,
188  "ID %s uses shapekey %s, but its 'from' pointer is invalid (%p), fixing...",
189  id->name,
190  shapekey->id.name,
191  shapekey->from);
192  shapekey->from = id;
193  }
194  }
195  }
197  }
199 
200  BKE_main_unlock(bmain);
201 
202  /* NOTE: #BKE_id_delete also locks `bmain`, so we need to do this loop outside of the lock here.
203  */
204  LISTBASE_FOREACH_MUTABLE (Key *, shapekey, &bmain->shapekeys) {
205  if (shapekey->from != NULL) {
206  continue;
207  }
208 
209  BKE_reportf(reports,
210  RPT_ERROR,
211  "Shapekey %s has an invalid 'from' pointer (%p), it will be deleted",
212  shapekey->id.name,
213  shapekey->from);
214  BKE_id_delete(bmain, shapekey);
215  }
216 
217  return is_valid;
218 }
struct Key * BKE_key_from_id(struct ID *id)
Definition: key.c:1786
bool BKE_key_idtype_support(const short id_type)
Definition: key.c:1749
void BKE_id_delete(struct Main *bmain, void *idv) ATTR_NONNULL()
void BKE_library_filepath_set(struct Main *bmain, struct Library *lib, const char *filepath)
Definition: library.c:92
#define FOREACH_MAIN_LISTBASE_ID_END
Definition: BKE_main.h:219
int set_listbasepointers(struct Main *main, struct ListBase *lb[])
#define FOREACH_MAIN_LISTBASE_ID_BEGIN(_lb, _id)
Definition: BKE_main.h:213
#define FOREACH_MAIN_LISTBASE_END
Definition: BKE_main.h:231
void BKE_main_unlock(struct Main *bmain)
Definition: main.c:207
void BKE_main_lock(struct Main *bmain)
Definition: main.c:202
#define FOREACH_MAIN_LISTBASE_BEGIN(_bmain, _lb)
Definition: BKE_main.h:224
void BKE_report(ReportList *reports, ReportType type, const char *message)
Definition: report.c:104
void BKE_reportf(ReportList *reports, ReportType type, const char *format,...) ATTR_PRINTF_FORMAT(3
#define BLI_assert(a)
Definition: BLI_assert.h:58
#define LISTBASE_FOREACH_MUTABLE(type, var, list)
Definition: BLI_listbase.h:188
void void BLI_INLINE bool BLI_listbase_is_single(const struct ListBase *lb)
Definition: BLI_listbase.h:120
#define STREQ(a, b)
Utils ensuring .blend file (i.e. Main) is in valid state during write and/or read process.
external readfile function prototypes.
struct BlendHandle BlendHandle
Definition: BLO_readfile.h:49
struct LinkNode * BLO_blendhandle_get_datablock_names(BlendHandle *bh, int ofblocktype, const bool use_assets_only, int *r_tot_names)
BlendHandle * BLO_blendhandle_from_file(const char *filepath, struct ReportList *reports)
Definition: readblenentry.c:71
void BLO_blendhandle_close(BlendHandle *bh)
@ INDEX_ID_MAX
Definition: DNA_ID.h:859
@ ID_LI
Definition: DNA_ID_enums.h:58
Read Guarded memory(de)allocation.
bool BLO_main_validate_libraries(Main *bmain, ReportList *reports)
bool BLO_main_validate_shapekeys(Main *bmain, ReportList *reports)
bool is_valid
#define GS(x)
Definition: iris.c:241
static char ** names
Definition: makesdna.c:162
void blo_split_main(ListBase *mainlist, Main *main)
Definition: readfile.c:496
void blo_join_main(ListBase *mainlist)
Definition: readfile.c:462
Definition: DNA_ID.h:273
struct Library * lib
Definition: DNA_ID.h:277
char name[66]
Definition: DNA_ID.h:283
ID * from
ID id
Definition: DNA_key_types.h:79
char filepath[1024]
Definition: DNA_ID.h:352
ID id
Definition: DNA_ID.h:349
char filepath_abs[1024]
Definition: DNA_ID.h:362
void * link
Definition: BLI_linklist.h:40
struct LinkNode * next
Definition: BLI_linklist.h:39
void * first
Definition: DNA_listBase.h:47
Definition: BKE_main.h:116
struct Main * next
Definition: BKE_main.h:117
ListBase shapekeys
Definition: BKE_main.h:159