Blender  V3.3
readblenentry.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2001-2002 NaN Holding BV. All rights reserved. */
3 
9 #include <stddef.h>
10 
11 #include <math.h>
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15 
16 #include "MEM_guardedalloc.h"
17 
18 #include "BLI_ghash.h"
19 #include "BLI_linklist.h"
20 #include "BLI_listbase.h"
21 #include "BLI_string.h"
22 #include "BLI_utildefines.h"
23 
24 #include "DNA_genfile.h"
25 #include "DNA_sdna_types.h"
26 
27 #include "BKE_icons.h"
28 #include "BKE_idtype.h"
29 #include "BKE_main.h"
30 
31 #include "BLO_blend_defs.h"
32 #include "BLO_readfile.h"
33 #include "BLO_undofile.h"
34 
35 #include "readfile.h"
36 
37 #include "BLI_sys_types.h" /* Needed for `intptr_t`. */
38 
39 #ifdef WIN32
40 # include "BLI_winstuff.h"
41 #endif
42 
43 /* local prototypes --------------------- */
44 void BLO_blendhandle_print_sizes(BlendHandle *bh, void *fp);
45 
46 /* Access routines used by filesel. */
47 
49 {
50  BlendHandle *bh;
51 
52  bh = (BlendHandle *)blo_filedata_from_file(filepath, reports);
53 
54  return bh;
55 }
56 
58  int memsize,
59  BlendFileReadReport *reports)
60 {
61  BlendHandle *bh;
62 
63  bh = (BlendHandle *)blo_filedata_from_memory(mem, memsize, reports);
64 
65  return bh;
66 }
67 
69 {
70  FileData *fd = (FileData *)bh;
71  BHead *bhead;
72 
73  fprintf(fp, "[\n");
74  for (bhead = blo_bhead_first(fd); bhead; bhead = blo_bhead_next(fd, bhead)) {
75  if (bhead->code == ENDB) {
76  break;
77  }
78 
79  const SDNA_Struct *struct_info = fd->filesdna->structs[bhead->SDNAnr];
80  const char *name = fd->filesdna->types[struct_info->type];
81  char buf[4];
82 
83  buf[0] = (bhead->code >> 24) & 0xFF;
84  buf[1] = (bhead->code >> 16) & 0xFF;
85  buf[2] = (bhead->code >> 8) & 0xFF;
86  buf[3] = (bhead->code >> 0) & 0xFF;
87 
88  buf[0] = buf[0] ? buf[0] : ' ';
89  buf[1] = buf[1] ? buf[1] : ' ';
90  buf[2] = buf[2] ? buf[2] : ' ';
91  buf[3] = buf[3] ? buf[3] : ' ';
92 
93  fprintf(fp,
94  "['%.4s', '%s', %d, %ld ],\n",
95  buf,
96  name,
97  bhead->nr,
98  (long int)(bhead->len + sizeof(BHead)));
99  }
100  fprintf(fp, "]\n");
101 }
102 
104  int ofblocktype,
105  const bool use_assets_only,
106  int *r_tot_names)
107 {
108  FileData *fd = (FileData *)bh;
109  LinkNode *names = NULL;
110  BHead *bhead;
111  int tot = 0;
112 
113  for (bhead = blo_bhead_first(fd); bhead; bhead = blo_bhead_next(fd, bhead)) {
114  if (bhead->code == ofblocktype) {
115  const char *idname = blo_bhead_id_name(fd, bhead);
116  if (use_assets_only && blo_bhead_id_asset_data_address(fd, bhead) == NULL) {
117  continue;
118  }
119 
120  BLI_linklist_prepend(&names, BLI_strdup(idname + 2));
121  tot++;
122  }
123  else if (bhead->code == ENDB) {
124  break;
125  }
126  }
127 
128  *r_tot_names = tot;
129  return names;
130 }
131 
133  int ofblocktype,
134  const bool use_assets_only,
135  int *r_tot_info_items)
136 {
137  FileData *fd = (FileData *)bh;
138  LinkNode *infos = NULL;
139  BHead *bhead;
140  int tot = 0;
141 
142  for (bhead = blo_bhead_first(fd); bhead; bhead = blo_bhead_next(fd, bhead)) {
143  if (bhead->code == ENDB) {
144  break;
145  }
146  if (bhead->code == ofblocktype) {
147  const char *name = blo_bhead_id_name(fd, bhead) + 2;
148  AssetMetaData *asset_meta_data = blo_bhead_id_asset_data_address(fd, bhead);
149 
150  const bool is_asset = asset_meta_data != NULL;
151  const bool skip_datablock = use_assets_only && !is_asset;
152  if (skip_datablock) {
153  continue;
154  }
155  struct BLODataBlockInfo *info = MEM_mallocN(sizeof(*info), __func__);
156 
157  /* Lastly, read asset data from the following blocks. */
158  if (asset_meta_data) {
159  bhead = blo_read_asset_data_block(fd, bhead, &asset_meta_data);
160  /* blo_read_asset_data_block() reads all DATA heads and already advances bhead to the
161  * next non-DATA one. Go back, so the loop doesn't skip the non-DATA head. */
162  bhead = blo_bhead_prev(fd, bhead);
163  }
164 
165  STRNCPY(info->name, name);
166  info->asset_data = asset_meta_data;
167 
168  BLI_linklist_prepend(&infos, info);
169  tot++;
170  }
171  }
172 
173  *r_tot_info_items = tot;
174  return infos;
175 }
176 
192  BHead *bhead,
194  const PreviewImage *preview_from_file)
195 {
196  for (int preview_index = 0; preview_index < NUM_ICON_SIZES; preview_index++) {
197  if (preview_from_file->rect[preview_index] && preview_from_file->w[preview_index] &&
198  preview_from_file->h[preview_index]) {
199  bhead = blo_bhead_next(fd, bhead);
200  BLI_assert((preview_from_file->w[preview_index] * preview_from_file->h[preview_index] *
201  sizeof(uint)) == bhead->len);
202  result->rect[preview_index] = BLO_library_read_struct(fd, bhead, "PreviewImage Icon Rect");
203  }
204  else {
205  /* This should not be needed, but can happen in 'broken' .blend files,
206  * better handle this gracefully than crashing. */
207  BLI_assert(preview_from_file->rect[preview_index] == NULL &&
208  preview_from_file->w[preview_index] == 0 &&
209  preview_from_file->h[preview_index] == 0);
210  result->rect[preview_index] = NULL;
211  result->w[preview_index] = result->h[preview_index] = 0;
212  }
213  BKE_previewimg_finish(result, preview_index);
214  }
215 
216  return bhead;
217 }
218 
220  int ofblocktype,
221  const char *name)
222 {
223  FileData *fd = (FileData *)bh;
224  bool looking = false;
225  const int sdna_preview_image = DNA_struct_find_nr(fd->filesdna, "PreviewImage");
226 
227  for (BHead *bhead = blo_bhead_first(fd); bhead; bhead = blo_bhead_next(fd, bhead)) {
228  if (bhead->code == DATA) {
229  if (looking && bhead->SDNAnr == sdna_preview_image) {
230  PreviewImage *preview_from_file = BLO_library_read_struct(fd, bhead, "PreviewImage");
231 
232  if (preview_from_file == NULL) {
233  break;
234  }
235 
236  PreviewImage *result = MEM_dupallocN(preview_from_file);
237  bhead = blo_blendhandle_read_preview_rects(fd, bhead, result, preview_from_file);
238  MEM_freeN(preview_from_file);
239  return result;
240  }
241  }
242  else if (looking || bhead->code == ENDB) {
243  /* We were looking for a preview image, but didn't find any belonging to block. So it doesn't
244  * exist. */
245  break;
246  }
247  else if (bhead->code == ofblocktype) {
248  const char *idname = blo_bhead_id_name(fd, bhead);
249  if (STREQ(&idname[2], name)) {
250  looking = true;
251  }
252  }
253  }
254 
255  return NULL;
256 }
257 
258 LinkNode *BLO_blendhandle_get_previews(BlendHandle *bh, int ofblocktype, int *r_tot_prev)
259 {
260  FileData *fd = (FileData *)bh;
261  LinkNode *previews = NULL;
262  BHead *bhead;
263  int looking = 0;
264  PreviewImage *prv = NULL;
265  PreviewImage *new_prv = NULL;
266  int tot = 0;
267 
268  for (bhead = blo_bhead_first(fd); bhead; bhead = blo_bhead_next(fd, bhead)) {
269  if (bhead->code == ofblocktype) {
270  const char *idname = blo_bhead_id_name(fd, bhead);
271  switch (GS(idname)) {
272  case ID_MA: /* fall through */
273  case ID_TE: /* fall through */
274  case ID_IM: /* fall through */
275  case ID_WO: /* fall through */
276  case ID_LA: /* fall through */
277  case ID_OB: /* fall through */
278  case ID_GR: /* fall through */
279  case ID_SCE: /* fall through */
280  case ID_AC: /* fall through */
281  case ID_NT: /* fall through */
282  new_prv = MEM_callocN(sizeof(PreviewImage), "newpreview");
283  BLI_linklist_prepend(&previews, new_prv);
284  tot++;
285  looking = 1;
286  break;
287  default:
288  break;
289  }
290  }
291  else if (bhead->code == DATA) {
292  if (looking) {
293  if (bhead->SDNAnr == DNA_struct_find_nr(fd->filesdna, "PreviewImage")) {
294  prv = BLO_library_read_struct(fd, bhead, "PreviewImage");
295 
296  if (prv) {
297  memcpy(new_prv, prv, sizeof(PreviewImage));
298  bhead = blo_blendhandle_read_preview_rects(fd, bhead, new_prv, prv);
299  MEM_freeN(prv);
300  }
301  }
302  }
303  }
304  else if (bhead->code == ENDB) {
305  break;
306  }
307  else {
308  looking = 0;
309  new_prv = NULL;
310  prv = NULL;
311  }
312  }
313 
314  *r_tot_prev = tot;
315  return previews;
316 }
317 
319 {
320  FileData *fd = (FileData *)bh;
321  GSet *gathered = BLI_gset_ptr_new("linkable_groups gh");
322  LinkNode *names = NULL;
323  BHead *bhead;
324 
325  for (bhead = blo_bhead_first(fd); bhead; bhead = blo_bhead_next(fd, bhead)) {
326  if (bhead->code == ENDB) {
327  break;
328  }
329  if (BKE_idtype_idcode_is_valid(bhead->code)) {
330  if (BKE_idtype_idcode_is_linkable(bhead->code)) {
331  const char *str = BKE_idtype_idcode_to_name(bhead->code);
332 
333  if (BLI_gset_add(gathered, (void *)str)) {
335  }
336  }
337  }
338  }
339 
340  BLI_gset_free(gathered, NULL);
341 
342  return names;
343 }
344 
346 {
347  FileData *fd = (FileData *)bh;
348 
349  blo_filedata_free(fd);
350 }
351 
352 void BLO_read_invalidate_message(BlendHandle *bh, Main *bmain, const char *message)
353 {
354  FileData *fd = (FileData *)bh;
355 
356  blo_readfile_invalidate(fd, bmain, message);
357 }
358 
359 /**********/
360 
361 BlendFileData *BLO_read_from_file(const char *filepath,
362  eBLOReadSkip skip_flags,
363  BlendFileReadReport *reports)
364 {
365  BlendFileData *bfd = NULL;
366  FileData *fd;
367 
368  fd = blo_filedata_from_file(filepath, reports);
369  if (fd) {
370  fd->skip_flags = skip_flags;
371  bfd = blo_read_file_internal(fd, filepath);
372  blo_filedata_free(fd);
373  }
374 
375  return bfd;
376 }
377 
379  int memsize,
380  eBLOReadSkip skip_flags,
381  ReportList *reports)
382 {
383  BlendFileData *bfd = NULL;
384  FileData *fd;
385  BlendFileReadReport bf_reports = {.reports = reports};
386 
387  fd = blo_filedata_from_memory(mem, memsize, &bf_reports);
388  if (fd) {
389  fd->skip_flags = skip_flags;
390  bfd = blo_read_file_internal(fd, "");
391  blo_filedata_free(fd);
392  }
393 
394  return bfd;
395 }
396 
398  const char *filepath,
399  MemFile *memfile,
400  const struct BlendFileReadParams *params,
401  ReportList *reports)
402 {
403  BlendFileData *bfd = NULL;
404  FileData *fd;
405  ListBase old_mainlist;
406  BlendFileReadReport bf_reports = {.reports = reports};
407 
408  fd = blo_filedata_from_memfile(memfile, params, &bf_reports);
409  if (fd) {
410  fd->skip_flags = params->skip_flags;
411  BLI_strncpy(fd->relabase, filepath, sizeof(fd->relabase));
412 
413  /* separate libraries from old main */
414  blo_split_main(&old_mainlist, oldmain);
415  /* add the library pointers in oldmap lookup */
416  blo_add_library_pointer_map(&old_mainlist, fd);
417 
418  if ((params->skip_flags & BLO_READ_SKIP_UNDO_OLD_MAIN) == 0) {
419  /* Build idmap of old main (we only care about local data here, so we can do that after
420  * split_main() call. */
421  blo_make_old_idmap_from_main(fd, old_mainlist.first);
422  }
423 
424  /* removed packed data from this trick - it's internal data that needs saves */
425 
426  /* Store all existing ID caches pointers into a mapping, to allow restoring them into newly
427  * read IDs whenever possible. */
428  blo_cache_storage_init(fd, oldmain);
429 
430  bfd = blo_read_file_internal(fd, filepath);
431 
432  /* Ensure relinked caches are not freed together with their old IDs. */
434 
435  /* Still in-use libraries have already been moved from oldmain to new mainlist,
436  * but oldmain itself shall *never* be 'transferred' to new mainlist! */
437  BLI_assert(old_mainlist.first == oldmain);
438 
439  /* That way, libs (aka mains) we did not reuse in new undone/redone state
440  * will be cleared together with oldmain... */
441  blo_join_main(&old_mainlist);
442 
443  blo_filedata_free(fd);
444  }
445 
446  return bfd;
447 }
448 
450 {
451  if (bfd->main) {
452  BKE_main_free(bfd->main);
453  }
454 
455  if (bfd->user) {
456  MEM_freeN(bfd->user);
457  }
458 
459  MEM_freeN(bfd);
460 }
void BKE_previewimg_finish(struct PreviewImage *prv, int size)
Definition: icons.cc:584
const char * BKE_idtype_idcode_to_name(short idcode)
Definition: idtype.c:142
bool BKE_idtype_idcode_is_linkable(short idcode)
Definition: idtype.c:175
bool BKE_idtype_idcode_is_valid(short idcode)
Definition: idtype.c:170
void BKE_main_free(struct Main *mainvar)
Definition: main.c:40
#define BLI_assert(a)
Definition: BLI_assert.h:46
struct GSet GSet
Definition: BLI_ghash.h:340
GSet * BLI_gset_ptr_new(const char *info)
void BLI_gset_free(GSet *gs, GSetKeyFreeFP keyfreefp)
Definition: BLI_ghash.c:1037
bool BLI_gset_add(GSet *gs, void *key)
Definition: BLI_ghash.c:969
#define STRNCPY(dst, src)
Definition: BLI_string.h:483
char * BLI_strdup(const char *str) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL() ATTR_MALLOC
Definition: string.c:42
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, size_t maxncpy) ATTR_NONNULL()
Definition: string.c:64
unsigned int uint
Definition: BLI_sys_types.h:67
#define STREQ(a, b)
Compatibility-like things for windows.
defines for blend-file codes.
@ ENDB
@ DATA
external readfile function prototypes.
eBLOReadSkip
Definition: BLO_readfile.h:120
@ BLO_READ_SKIP_UNDO_OLD_MAIN
Definition: BLO_readfile.h:125
struct BlendHandle BlendHandle
Definition: BLO_readfile.h:35
void * BLO_library_read_struct(struct FileData *fd, struct BHead *bh, const char *blockname)
Definition: readfile.c:4796
@ NUM_ICON_SIZES
Definition: DNA_ID_enums.h:18
@ ID_TE
Definition: DNA_ID_enums.h:52
@ ID_IM
Definition: DNA_ID_enums.h:53
@ ID_NT
Definition: DNA_ID_enums.h:68
@ ID_LA
Definition: DNA_ID_enums.h:55
@ ID_SCE
Definition: DNA_ID_enums.h:45
@ ID_WO
Definition: DNA_ID_enums.h:59
@ ID_MA
Definition: DNA_ID_enums.h:51
@ ID_AC
Definition: DNA_ID_enums.h:67
@ ID_GR
Definition: DNA_ID_enums.h:65
@ ID_OB
Definition: DNA_ID_enums.h:47
blenloader genfile private function prototypes
int DNA_struct_find_nr(const struct SDNA *sdna, const char *str)
Read Guarded memory(de)allocation.
#define str(s)
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
#define GS(x)
Definition: iris.c:225
static char ** names
Definition: makesdna.c:65
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:27
void *(* MEM_dupallocN)(const void *vmemh)
Definition: mallocn.c:28
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:31
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:33
BlendHandle * BLO_blendhandle_from_file(const char *filepath, BlendFileReadReport *reports)
Definition: readblenentry.c:48
PreviewImage * BLO_blendhandle_get_preview_for_id(BlendHandle *bh, int ofblocktype, const char *name)
BlendFileData * BLO_read_from_memory(const void *mem, int memsize, eBLOReadSkip skip_flags, ReportList *reports)
static BHead * blo_blendhandle_read_preview_rects(FileData *fd, BHead *bhead, PreviewImage *result, const PreviewImage *preview_from_file)
void BLO_read_invalidate_message(BlendHandle *bh, Main *bmain, const char *message)
LinkNode * BLO_blendhandle_get_datablock_info(BlendHandle *bh, int ofblocktype, const bool use_assets_only, int *r_tot_info_items)
BlendFileData * BLO_read_from_file(const char *filepath, eBLOReadSkip skip_flags, BlendFileReadReport *reports)
BlendFileData * BLO_read_from_memfile(Main *oldmain, const char *filepath, MemFile *memfile, const struct BlendFileReadParams *params, ReportList *reports)
LinkNode * BLO_blendhandle_get_linkable_groups(BlendHandle *bh)
void BLO_blendhandle_print_sizes(BlendHandle *bh, void *fp)
Definition: readblenentry.c:68
LinkNode * BLO_blendhandle_get_previews(BlendHandle *bh, int ofblocktype, int *r_tot_prev)
LinkNode * BLO_blendhandle_get_datablock_names(BlendHandle *bh, int ofblocktype, const bool use_assets_only, int *r_tot_names)
void BLO_blendhandle_close(BlendHandle *bh)
BlendHandle * BLO_blendhandle_from_memory(const void *mem, int memsize, BlendFileReadReport *reports)
Definition: readblenentry.c:57
void BLO_blendfiledata_free(BlendFileData *bfd)
FileData * blo_filedata_from_memfile(MemFile *memfile, const struct BlendFileReadParams *params, BlendFileReadReport *reports)
Definition: readfile.c:1416
BlendFileData * blo_read_file_internal(FileData *fd, const char *filepath)
Definition: readfile.c:3963
FileData * blo_filedata_from_file(const char *filepath, BlendFileReadReport *reports)
Definition: readfile.c:1357
BHead * blo_bhead_first(FileData *fd)
Definition: readfile.c:937
AssetMetaData * blo_bhead_id_asset_data_address(const FileData *fd, const BHead *bhead)
Definition: readfile.c:1036
void blo_split_main(ListBase *mainlist, Main *main)
Definition: readfile.c:496
BHead * blo_bhead_next(FileData *fd, BHead *thisblock)
Definition: readfile.c:965
void blo_cache_storage_init(FileData *fd, Main *bmain)
Definition: readfile.c:1861
void blo_make_old_idmap_from_main(FileData *fd, Main *bmain)
Definition: readfile.c:1775
const char * blo_bhead_id_name(const FileData *fd, const BHead *bhead)
Definition: readfile.c:1031
BHead * blo_bhead_prev(FileData *UNUSED(fd), BHead *thisblock)
Definition: readfile.c:957
void blo_filedata_free(FileData *fd)
Definition: readfile.c:1433
void blo_readfile_invalidate(FileData *fd, Main *bmain, const char *message)
Definition: readfile.c:693
void blo_cache_storage_old_bmain_clear(FileData *fd, Main *bmain_old)
Definition: readfile.c:1897
BHead * blo_read_asset_data_block(FileData *fd, BHead *bhead, AssetMetaData **r_asset_data)
Definition: readfile.c:3558
void blo_add_library_pointer_map(ListBase *old_mainlist, FileData *fd)
Definition: readfile.c:1759
void blo_join_main(ListBase *mainlist)
Definition: readfile.c:455
FileData * blo_filedata_from_memory(const void *mem, int memsize, BlendFileReadReport *reports)
Definition: readfile.c:1386
The meta-data of an asset. By creating and giving this for a data-block (ID.asset_data),...
int SDNAnr
int code
struct AssetMetaData * asset_data
Definition: BLO_readfile.h:184
struct Main * main
Definition: BLO_readfile.h:56
struct UserDef * user
Definition: BLO_readfile.h:57
struct ReportList * reports
Definition: BLO_readfile.h:80
eBLOReadSkip skip_flags
Definition: readfile.h:79
struct SDNA * filesdna
Definition: readfile.h:63
char relabase[FILE_MAX]
Definition: readfile.h:60
void * first
Definition: DNA_listBase.h:31
Definition: BKE_main.h:121
unsigned int h[2]
Definition: DNA_ID.h:532
unsigned int * rect[2]
Definition: DNA_ID.h:535
unsigned int w[2]
Definition: DNA_ID.h:531
SDNA_Struct ** structs
const char ** types