Cleanup: rename 'name' to 'filepath' for DNA types
[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,
21  * only checks relations between data-blocks and libraries for now.
22  *
23  * \note Does not *fix* anything, only reports found errors.
24  */
25
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"
37 #include "DNA_windowmanager_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
50 /**
51  * Check (but do *not* fix) that all linked data-blocks are still valid
52  * (i.e. pointing to the right library).
53  */
54 bool BLO_main_validate_libraries(Main *bmain, ReportList *reports)
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[MAX_LIBARRAY];
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), &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
151       BLI_linklist_free(names, free);
152     }
153
154     BLO_blendhandle_close(bh);
155   }
156
157   blo_join_main(&mainlist);
158
159   BLI_assert(BLI_listbase_is_single(&mainlist));
160   BLI_assert(mainlist.first == (void *)bmain);
161
162   BKE_main_unlock(bmain);
163
164   return is_valid;
165 }
166
167 /** Check (and fix if needed) that shape key's 'from' pointer is valid. */
168 bool BLO_main_validate_shapekeys(Main *bmain, ReportList *reports)
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) {
177     FOREACH_MAIN_LISTBASE_ID_BEGIN (lb, id) {
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     }
196     FOREACH_MAIN_LISTBASE_ID_END;
197   }
198   FOREACH_MAIN_LISTBASE_END;
199
200   BKE_main_unlock(bmain);
201
202   return is_valid;
203 }