doxygen: add newline after \file
[blender.git] / source / blender / blenloader / intern / blend_validate.c
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
17 /** \file
18  * \ingroup blenloader
19  *
20  * Utils to check/validate a Main is in sane state, only checks relations between datablocks and libraries for now.
21  *
22  * \note Does not *fix* anything, only reports found errors.
23  */
24
25 #include <string.h> // for strrchr strncmp strstr
26
27 #include "BLI_utildefines.h"
28
29 #include "BLI_blenlib.h"
30 #include "BLI_linklist.h"
31
32 #include "MEM_guardedalloc.h"
33
34 #include "DNA_sdna_types.h"
35 #include "DNA_key_types.h"
36 #include "DNA_windowmanager_types.h"
37
38 #include "BKE_key.h"
39 #include "BKE_library.h"
40 #include "BKE_main.h"
41 #include "BKE_report.h"
42
43 #include "BLO_blend_validate.h"
44 #include "BLO_readfile.h"
45
46 #include "readfile.h"
47
48 /** Check (but do *not* fix) that all linked data-blocks are still valid (i.e. pointing to the right library). */
49 bool BLO_main_validate_libraries(Main *bmain, ReportList *reports)
50 {
51         ListBase mainlist;
52         bool is_valid = true;
53
54         BKE_main_lock(bmain);
55
56         blo_split_main(&mainlist, bmain);
57
58         ListBase *lbarray[MAX_LIBARRAY];
59         int i = set_listbasepointers(bmain, lbarray);
60         while (i--) {
61                 for (ID *id = lbarray[i]->first; id != NULL; id = id->next) {
62                         if (id->lib != NULL) {
63                                 is_valid = false;
64                                 BKE_reportf(reports, RPT_ERROR,
65                                             "ID %s is in local database while being linked from library %s!", id->name, id->lib->name);
66                         }
67                 }
68         }
69
70         for (Main *curmain = bmain->next; curmain != NULL; curmain = curmain->next) {
71                 Library *curlib = curmain->curlib;
72                 if (curlib == NULL) {
73                         BKE_reportf(reports, RPT_ERROR,
74                                     "Library database with NULL library datablock!");
75                         continue;
76                 }
77
78                 BKE_library_filepath_set(bmain, curlib, curlib->name);
79                 BlendHandle *bh = BLO_blendhandle_from_file(curlib->filepath, reports);
80
81                 if (bh == NULL) {
82                         BKE_reportf(reports, RPT_ERROR,
83                                     "Library ID %s not found at expected path %s!", curlib->id.name, curlib->filepath);
84                         continue;
85                 }
86
87                 i = set_listbasepointers(curmain, lbarray);
88                 while (i--) {
89                         ID *id = lbarray[i]->first;
90                         if (id == NULL) {
91                                 continue;
92                         }
93
94                         if (GS(id->name) == ID_LI) {
95                                 is_valid = false;
96                                 BKE_reportf(reports, RPT_ERROR,
97                                             "Library ID %s in library %s, this should not happen!", id->name, curlib->name);
98                                 continue;
99                         }
100
101                         int totnames = 0;
102                         LinkNode *names = BLO_blendhandle_get_datablock_names(bh, GS(id->name), &totnames);
103                         for (; id != NULL; id = id->next) {
104                                 if (id->lib == NULL) {
105                                         is_valid = false;
106                                         BKE_reportf(reports, RPT_ERROR,
107                                                     "ID %s has NULL lib pointer while being in library %s!", id->name, curlib->name);
108                                         continue;
109                                 }
110                                 if (id->lib != curlib) {
111                                         is_valid = false;
112                                         BKE_reportf(reports, RPT_ERROR,
113                                                     "ID %s has mismatched lib pointer!", id->name);
114                                         continue;
115                                 }
116
117                                 LinkNode *name = names;
118                                 for (; name; name = name->next) {
119                                         char *str_name = (char *)name->link;
120                                         if (id->name[2] == str_name[0] && STREQ(str_name, id->name + 2)) {
121                                                 break;
122                                         }
123                                 }
124
125                                 if (name == NULL) {
126                                         is_valid = false;
127                                         BKE_reportf(reports, RPT_ERROR,
128                                                     "ID %s not found in library %s anymore!", id->name, id->lib->name);
129                                         continue;
130                                 }
131                         }
132
133                         BLI_linklist_free(names, free);
134                 }
135
136                 BLO_blendhandle_close(bh);
137         }
138
139         blo_join_main(&mainlist);
140
141         BLI_assert(BLI_listbase_is_single(&mainlist));
142         BLI_assert(mainlist.first == (void *)bmain);
143
144         BKE_main_unlock(bmain);
145
146         return is_valid;
147 }
148
149 /** Check (and fix if needed) that shape key's 'from' pointer is valid. */
150 bool BLO_main_validate_shapekeys(Main *bmain, ReportList *reports)
151 {
152         bool is_valid = true;
153
154         BKE_main_lock(bmain);
155
156         ListBase *lbarray[MAX_LIBARRAY];
157         int i = set_listbasepointers(bmain, lbarray);
158         while (i--) {
159                 for (ID *id = lbarray[i]->first; id != NULL; id = id->next) {
160                         if (!BKE_key_idtype_support(GS(id->name))) {
161                                 break;
162                         }
163                         if (id->lib == NULL) {
164                                 /* We assume lib data is valid... */
165                                 Key *shapekey = BKE_key_from_id(id);
166                                 if (shapekey != NULL && shapekey->from != id) {
167                                         is_valid = false;
168                                         BKE_reportf(reports, RPT_ERROR,
169                                                     "ID %s uses shapekey %s, but its 'from' pointer is invalid (%p), fixing...",
170                                                     id->name, shapekey->id.name, shapekey->from);
171                                         shapekey->from = id;
172                                 }
173                         }
174                 }
175         }
176
177         BKE_main_unlock(bmain);
178
179         return is_valid;
180 }