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 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
17 * All rights reserved.
18 * .blend file reading entry point
19 */
20
21 /** \file
22 * \ingroup blenloader
23 */
24
25 #include <stddef.h>
26
27 #include <math.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31
32 #include "MEM_guardedalloc.h"
33
34 #include "BLI_ghash.h"
35 #include "BLI_linklist.h"
36 #include "BLI_listbase.h"
37 #include "BLI_string.h"
38 #include "BLI_utildefines.h"
39
40 #include "DNA_genfile.h"
41 #include "DNA_sdna_types.h"
42
43 #include "BKE_idtype.h"
44 #include "BKE_main.h"
45
46 #include "BLO_blend_defs.h"
47 #include "BLO_readfile.h"
48 #include "BLO_undofile.h"
49
50 #include "readfile.h"
51
52 #include "BLI_sys_types.h" // needed for intptr_t
53
54 #ifdef WIN32
55 # include "BLI_winstuff.h"
56 #endif
57
58 /* local prototypes --------------------- */
59 void BLO_blendhandle_print_sizes(BlendHandle *bh, void *fp);
60
61 /* Access routines used by filesel. */
62
63 /**
64 * Open a blendhandle from a file path.
65 *
66 * \param filepath: The file path to open.
67 * \param reports: Report errors in opening the file (can be NULL).
68 * \return A handle on success, or NULL on failure.
69 */
BLO_blendhandle_from_file(const char * filepath,ReportList * reports)70 BlendHandle *BLO_blendhandle_from_file(const char *filepath, ReportList *reports)
71 {
72 BlendHandle *bh;
73
74 bh = (BlendHandle *)blo_filedata_from_file(filepath, reports);
75
76 return bh;
77 }
78
79 /**
80 * Open a blendhandle from memory.
81 *
82 * \param mem: The data to load from.
83 * \param memsize: The size of the data.
84 * \return A handle on success, or NULL on failure.
85 */
BLO_blendhandle_from_memory(const void * mem,int memsize)86 BlendHandle *BLO_blendhandle_from_memory(const void *mem, int memsize)
87 {
88 BlendHandle *bh;
89
90 bh = (BlendHandle *)blo_filedata_from_memory(mem, memsize, NULL);
91
92 return bh;
93 }
94
BLO_blendhandle_print_sizes(BlendHandle * bh,void * fp)95 void BLO_blendhandle_print_sizes(BlendHandle *bh, void *fp)
96 {
97 FileData *fd = (FileData *)bh;
98 BHead *bhead;
99
100 fprintf(fp, "[\n");
101 for (bhead = blo_bhead_first(fd); bhead; bhead = blo_bhead_next(fd, bhead)) {
102 if (bhead->code == ENDB) {
103 break;
104 }
105
106 const SDNA_Struct *struct_info = fd->filesdna->structs[bhead->SDNAnr];
107 const char *name = fd->filesdna->types[struct_info->type];
108 char buf[4];
109
110 buf[0] = (bhead->code >> 24) & 0xFF;
111 buf[1] = (bhead->code >> 16) & 0xFF;
112 buf[2] = (bhead->code >> 8) & 0xFF;
113 buf[3] = (bhead->code >> 0) & 0xFF;
114
115 buf[0] = buf[0] ? buf[0] : ' ';
116 buf[1] = buf[1] ? buf[1] : ' ';
117 buf[2] = buf[2] ? buf[2] : ' ';
118 buf[3] = buf[3] ? buf[3] : ' ';
119
120 fprintf(fp,
121 "['%.4s', '%s', %d, %ld ],\n",
122 buf,
123 name,
124 bhead->nr,
125 (long int)(bhead->len + sizeof(BHead)));
126 }
127 fprintf(fp, "]\n");
128 }
129
130 /**
131 * Gets the names of all the data-blocks in a file of a certain type
132 * (e.g. all the scene names in a file).
133 *
134 * \param bh: The blendhandle to access.
135 * \param ofblocktype: The type of names to get.
136 * \param tot_names: The length of the returned list.
137 * \return A BLI_linklist of strings. The string links should be freed with malloc.
138 */
BLO_blendhandle_get_datablock_names(BlendHandle * bh,int ofblocktype,int * tot_names)139 LinkNode *BLO_blendhandle_get_datablock_names(BlendHandle *bh, int ofblocktype, int *tot_names)
140 {
141 FileData *fd = (FileData *)bh;
142 LinkNode *names = NULL;
143 BHead *bhead;
144 int tot = 0;
145
146 for (bhead = blo_bhead_first(fd); bhead; bhead = blo_bhead_next(fd, bhead)) {
147 if (bhead->code == ofblocktype) {
148 const char *idname = blo_bhead_id_name(fd, bhead);
149
150 BLI_linklist_prepend(&names, strdup(idname + 2));
151 tot++;
152 }
153 else if (bhead->code == ENDB) {
154 break;
155 }
156 }
157
158 *tot_names = tot;
159 return names;
160 }
161
162 /**
163 * Gets the previews of all the data-blocks in a file of a certain type
164 * (e.g. all the scene previews in a file).
165 *
166 * \param bh: The blendhandle to access.
167 * \param ofblocktype: The type of names to get.
168 * \param tot_prev: The length of the returned list.
169 * \return A BLI_linklist of PreviewImage. The PreviewImage links should be freed with malloc.
170 */
BLO_blendhandle_get_previews(BlendHandle * bh,int ofblocktype,int * tot_prev)171 LinkNode *BLO_blendhandle_get_previews(BlendHandle *bh, int ofblocktype, int *tot_prev)
172 {
173 FileData *fd = (FileData *)bh;
174 LinkNode *previews = NULL;
175 BHead *bhead;
176 int looking = 0;
177 PreviewImage *prv = NULL;
178 PreviewImage *new_prv = NULL;
179 int tot = 0;
180
181 for (bhead = blo_bhead_first(fd); bhead; bhead = blo_bhead_next(fd, bhead)) {
182 if (bhead->code == ofblocktype) {
183 const char *idname = blo_bhead_id_name(fd, bhead);
184 switch (GS(idname)) {
185 case ID_MA: /* fall through */
186 case ID_TE: /* fall through */
187 case ID_IM: /* fall through */
188 case ID_WO: /* fall through */
189 case ID_LA: /* fall through */
190 case ID_OB: /* fall through */
191 case ID_GR: /* fall through */
192 case ID_SCE: /* fall through */
193 new_prv = MEM_callocN(sizeof(PreviewImage), "newpreview");
194 BLI_linklist_prepend(&previews, new_prv);
195 tot++;
196 looking = 1;
197 break;
198 default:
199 break;
200 }
201 }
202 else if (bhead->code == DATA) {
203 if (looking) {
204 if (bhead->SDNAnr == DNA_struct_find_nr(fd->filesdna, "PreviewImage")) {
205 prv = BLO_library_read_struct(fd, bhead, "PreviewImage");
206 if (prv) {
207 memcpy(new_prv, prv, sizeof(PreviewImage));
208 if (prv->rect[0] && prv->w[0] && prv->h[0]) {
209 bhead = blo_bhead_next(fd, bhead);
210 BLI_assert((new_prv->w[0] * new_prv->h[0] * sizeof(uint)) == bhead->len);
211 new_prv->rect[0] = BLO_library_read_struct(fd, bhead, "PreviewImage Icon Rect");
212 }
213 else {
214 /* This should not be needed, but can happen in 'broken' .blend files,
215 * better handle this gracefully than crashing. */
216 BLI_assert(prv->rect[0] == NULL && prv->w[0] == 0 && prv->h[0] == 0);
217 new_prv->rect[0] = NULL;
218 new_prv->w[0] = new_prv->h[0] = 0;
219 }
220
221 if (prv->rect[1] && prv->w[1] && prv->h[1]) {
222 bhead = blo_bhead_next(fd, bhead);
223 BLI_assert((new_prv->w[1] * new_prv->h[1] * sizeof(uint)) == bhead->len);
224 new_prv->rect[1] = BLO_library_read_struct(fd, bhead, "PreviewImage Image Rect");
225 }
226 else {
227 /* This should not be needed, but can happen in 'broken' .blend files,
228 * better handle this gracefully than crashing. */
229 BLI_assert(prv->rect[1] == NULL && prv->w[1] == 0 && prv->h[1] == 0);
230 new_prv->rect[1] = NULL;
231 new_prv->w[1] = new_prv->h[1] = 0;
232 }
233 MEM_freeN(prv);
234 }
235 }
236 }
237 }
238 else if (bhead->code == ENDB) {
239 break;
240 }
241 else {
242 looking = 0;
243 new_prv = NULL;
244 prv = NULL;
245 }
246 }
247
248 *tot_prev = tot;
249 return previews;
250 }
251
252 /**
253 * Gets the names of all the linkable data-block types available in a file.
254 * (e.g. "Scene", "Mesh", "Light", etc.).
255 *
256 * \param bh: The blendhandle to access.
257 * \return A BLI_linklist of strings. The string links should be freed with malloc.
258 */
BLO_blendhandle_get_linkable_groups(BlendHandle * bh)259 LinkNode *BLO_blendhandle_get_linkable_groups(BlendHandle *bh)
260 {
261 FileData *fd = (FileData *)bh;
262 GSet *gathered = BLI_gset_ptr_new("linkable_groups gh");
263 LinkNode *names = NULL;
264 BHead *bhead;
265
266 for (bhead = blo_bhead_first(fd); bhead; bhead = blo_bhead_next(fd, bhead)) {
267 if (bhead->code == ENDB) {
268 break;
269 }
270 if (BKE_idtype_idcode_is_valid(bhead->code)) {
271 if (BKE_idtype_idcode_is_linkable(bhead->code)) {
272 const char *str = BKE_idtype_idcode_to_name(bhead->code);
273
274 if (BLI_gset_add(gathered, (void *)str)) {
275 BLI_linklist_prepend(&names, strdup(str));
276 }
277 }
278 }
279 }
280
281 BLI_gset_free(gathered, NULL);
282
283 return names;
284 }
285
286 /**
287 * Close and free a blendhandle. The handle becomes invalid after this call.
288 *
289 * \param bh: The handle to close.
290 */
BLO_blendhandle_close(BlendHandle * bh)291 void BLO_blendhandle_close(BlendHandle *bh)
292 {
293 FileData *fd = (FileData *)bh;
294
295 blo_filedata_free(fd);
296 }
297
298 /**********/
299
300 /**
301 * Open a blender file from a pathname. The function returns NULL
302 * and sets a report in the list if it cannot open the file.
303 *
304 * \param filepath: The path of the file to open.
305 * \param reports: If the return value is NULL, errors indicating the cause of the failure.
306 * \return The data of the file.
307 */
BLO_read_from_file(const char * filepath,eBLOReadSkip skip_flags,ReportList * reports)308 BlendFileData *BLO_read_from_file(const char *filepath,
309 eBLOReadSkip skip_flags,
310 ReportList *reports)
311 {
312 BlendFileData *bfd = NULL;
313 FileData *fd;
314
315 fd = blo_filedata_from_file(filepath, reports);
316 if (fd) {
317 fd->reports = reports;
318 fd->skip_flags = skip_flags;
319 bfd = blo_read_file_internal(fd, filepath);
320 blo_filedata_free(fd);
321 }
322
323 return bfd;
324 }
325
326 /**
327 * Open a blender file from memory. The function returns NULL
328 * and sets a report in the list if it cannot open the file.
329 *
330 * \param mem: The file data.
331 * \param memsize: The length of \a mem.
332 * \param reports: If the return value is NULL, errors indicating the cause of the failure.
333 * \return The data of the file.
334 */
BLO_read_from_memory(const void * mem,int memsize,eBLOReadSkip skip_flags,ReportList * reports)335 BlendFileData *BLO_read_from_memory(const void *mem,
336 int memsize,
337 eBLOReadSkip skip_flags,
338 ReportList *reports)
339 {
340 BlendFileData *bfd = NULL;
341 FileData *fd;
342
343 fd = blo_filedata_from_memory(mem, memsize, reports);
344 if (fd) {
345 fd->reports = reports;
346 fd->skip_flags = skip_flags;
347 bfd = blo_read_file_internal(fd, "");
348 blo_filedata_free(fd);
349 }
350
351 return bfd;
352 }
353
354 /**
355 * Used for undo/redo, skips part of libraries reading
356 * (assuming their data are already loaded & valid).
357 *
358 * \param oldmain: old main,
359 * from which we will keep libraries and other data-blocks that should not have changed.
360 * \param filename: current file, only for retrieving library data.
361 */
BLO_read_from_memfile(Main * oldmain,const char * filename,MemFile * memfile,const struct BlendFileReadParams * params,ReportList * reports)362 BlendFileData *BLO_read_from_memfile(Main *oldmain,
363 const char *filename,
364 MemFile *memfile,
365 const struct BlendFileReadParams *params,
366 ReportList *reports)
367 {
368 BlendFileData *bfd = NULL;
369 FileData *fd;
370 ListBase old_mainlist;
371
372 fd = blo_filedata_from_memfile(memfile, params, reports);
373 if (fd) {
374 fd->reports = reports;
375 fd->skip_flags = params->skip_flags;
376 BLI_strncpy(fd->relabase, filename, sizeof(fd->relabase));
377
378 /* clear ob->proxy_from pointers in old main */
379 blo_clear_proxy_pointers_from_lib(oldmain);
380
381 /* separate libraries from old main */
382 blo_split_main(&old_mainlist, oldmain);
383 /* add the library pointers in oldmap lookup */
384 blo_add_library_pointer_map(&old_mainlist, fd);
385
386 if ((params->skip_flags & BLO_READ_SKIP_UNDO_OLD_MAIN) == 0) {
387 /* Build idmap of old main (we only care about local data here, so we can do that after
388 * split_main() call. */
389 blo_make_old_idmap_from_main(fd, old_mainlist.first);
390 }
391
392 /* removed packed data from this trick - it's internal data that needs saves */
393
394 /* Store all existing ID caches pointers into a mapping, to allow restoring them into newly
395 * read IDs whenever possible. */
396 blo_cache_storage_init(fd, oldmain);
397
398 bfd = blo_read_file_internal(fd, filename);
399
400 /* Ensure relinked caches are not freed together with their old IDs. */
401 blo_cache_storage_old_bmain_clear(fd, oldmain);
402
403 /* Still in-use libraries have already been moved from oldmain to new mainlist,
404 * but oldmain itself shall *never* be 'transferred' to new mainlist! */
405 BLI_assert(old_mainlist.first == oldmain);
406
407 /* That way, libs (aka mains) we did not reuse in new undone/redone state
408 * will be cleared together with oldmain... */
409 blo_join_main(&old_mainlist);
410
411 blo_filedata_free(fd);
412 }
413
414 return bfd;
415 }
416
417 /**
418 * Frees a BlendFileData structure and *all* the data associated with it
419 * (the userdef data, and the main libblock data).
420 *
421 * \param bfd: The structure to free.
422 */
BLO_blendfiledata_free(BlendFileData * bfd)423 void BLO_blendfiledata_free(BlendFileData *bfd)
424 {
425 if (bfd->main) {
426 BKE_main_free(bfd->main);
427 }
428
429 if (bfd->user) {
430 MEM_freeN(bfd->user);
431 }
432
433 MEM_freeN(bfd);
434 }
435