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