Blender V5.0
readblenentry.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2001-2002 NaN Holding BV. All rights reserved.
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
9
10#include <cstddef>
11#include <cstdlib>
12#include <cstring>
13
14#include "MEM_guardedalloc.h"
15
16#include "BLI_ghash.h"
17#include "BLI_linklist.h"
18#include "BLI_path_utils.hh" /* Only for assertions. */
19#include "BLI_string.h"
20#include "BLI_utildefines.h"
21
22#include "DNA_genfile.h"
23
24#include "BKE_asset.hh"
25#include "BKE_idtype.hh"
26#include "BKE_main.hh"
27#include "BKE_preview_image.hh"
28
29#include "BLO_readfile.hh"
30
31#include "readfile.hh"
32
33#include "BLI_sys_types.h" /* Needed for `intptr_t`. */
34
35#ifdef WIN32
36# include "BLI_winstuff.h"
37#endif
38
39/* Access routines used by file-selector. */
40
42{
43 if (datablock_info->free_asset_data) {
44 BKE_asset_metadata_free(&datablock_info->asset_data);
45 datablock_info->free_asset_data = false;
46 }
47}
48
50{
51 BLI_linklist_free(datablock_infos, [](void *link) {
52 BLODataBlockInfo *datablock_info = static_cast<BLODataBlockInfo *>(link);
53 BLO_datablock_info_free(datablock_info);
54 MEM_freeN(datablock_info);
55 });
56}
57
58BlendHandle *BLO_blendhandle_from_file(const char *filepath, BlendFileReadReport *reports)
59{
60 BlendHandle *bh;
61
62 bh = (BlendHandle *)blo_filedata_from_file(filepath, reports);
63
64 return bh;
65}
66
67BlendHandle *BLO_blendhandle_from_memory(const void *mem,
68 int memsize,
69 BlendFileReadReport *reports)
70{
71 BlendHandle *bh;
72
73 bh = (BlendHandle *)blo_filedata_from_memory(mem, memsize, reports);
74
75 return bh;
76}
77
79{
80 const FileData *fd = reinterpret_cast<const FileData *>(bh);
81 return blender::int3(fd->fileversion / 100, fd->fileversion % 100, fd->filesubversion);
82}
83
84/* Return `false` if the block should be skipped because it is either an invalid block, or it does
85 * not meet to required conditions. */
87 BHead *bhead,
88 bool use_assets_only,
89 const char *&r_idname,
90 short &r_idflag,
91 AssetMetaData *&r_asset_meta_data)
92{
93 r_idname = blo_bhead_id_name(fd, bhead);
94 if (!r_idname || r_idname[0] == '\0') {
95 return false;
96 }
97 r_idflag = blo_bhead_id_flag(fd, bhead);
98 /* Do not list (and therefore allow direct linking of) packed data.
99 * While supporting this is conceptually possible, it would require significant changes in
100 * the UI (file browser) and UX (link operation) to convey this concept and handle it
101 * correctly. */
102 if (r_idflag & ID_FLAG_LINKED_AND_PACKED) {
103 return false;
104 }
105 r_asset_meta_data = blo_bhead_id_asset_data_address(fd, bhead);
106 if (use_assets_only && r_asset_meta_data == nullptr) {
107 return false;
108 }
109 return true;
110}
111
113 int ofblocktype,
114 const bool use_assets_only,
115 int *r_tot_names)
116{
117 FileData *fd = (FileData *)bh;
118 LinkNode *names = nullptr;
119 BHead *bhead;
120 int tot = 0;
121
122 for (bhead = blo_bhead_first(fd); bhead; bhead = blo_bhead_next(fd, bhead)) {
123 if (bhead->code == ofblocktype) {
124 const char *idname;
125 short idflag;
126 AssetMetaData *asset_meta_data;
128 fd, bhead, use_assets_only, idname, idflag, asset_meta_data))
129 {
130 continue;
131 }
132
133 BLI_linklist_prepend(&names, BLI_strdup(idname + 2));
134 tot++;
135 }
136 else if (bhead->code == BLO_CODE_ENDB) {
137 break;
138 }
139 }
140
141 *r_tot_names = tot;
142 return names;
143}
144
146 int ofblocktype,
147 const bool use_assets_only,
148 int *r_tot_info_items)
149{
150 FileData *fd = (FileData *)bh;
151 LinkNode *infos = nullptr;
152 BHead *bhead;
153 int tot = 0;
154
155 const int sdna_nr_preview_image = DNA_struct_find_with_alias(fd->filesdna, "PreviewImage");
156
157 for (bhead = blo_bhead_first(fd); bhead; bhead = blo_bhead_next(fd, bhead)) {
158 if (bhead->code == BLO_CODE_ENDB) {
159 break;
160 }
161 if (bhead->code == ofblocktype) {
162 BHead *id_bhead = bhead;
163
164 const char *idname;
165 short idflag;
166 AssetMetaData *asset_meta_data;
168 fd, id_bhead, use_assets_only, idname, idflag, asset_meta_data))
169 {
170 continue;
171 }
172
173 const char *name = idname + 2;
175
176 /* Lastly, read asset data from the following blocks. */
177 if (asset_meta_data) {
178 bhead = blo_read_asset_data_block(fd, bhead, &asset_meta_data);
179 /* blo_read_asset_data_block() reads all DATA heads and already advances bhead to the
180 * next non-DATA one. Go back, so the loop doesn't skip the non-DATA head. */
181 bhead = blo_bhead_prev(fd, bhead);
182 }
183
184 STRNCPY(info->name, name);
185 info->asset_data = asset_meta_data;
186 info->free_asset_data = true;
187
188 bool has_preview = false;
189 /* See if we can find a preview in the data of this ID. */
190 for (BHead *data_bhead = blo_bhead_next(fd, id_bhead); data_bhead->code == BLO_CODE_DATA;
191 data_bhead = blo_bhead_next(fd, data_bhead))
192 {
193 if (data_bhead->SDNAnr == sdna_nr_preview_image) {
194 has_preview = true;
195 break;
196 }
197 }
198 info->no_preview_found = !has_preview;
199
200 BLI_linklist_prepend(&infos, info);
201 tot++;
202 }
203 }
204
205 *r_tot_info_items = tot;
206 return infos;
207}
208
224 BHead *bhead,
226 const PreviewImage *preview_from_file)
227{
228 for (int preview_index = 0; preview_index < NUM_ICON_SIZES; preview_index++) {
229 if (preview_from_file->rect[preview_index] && preview_from_file->w[preview_index] &&
230 preview_from_file->h[preview_index])
231 {
232 bhead = blo_bhead_next(fd, bhead);
233 BLI_assert((preview_from_file->w[preview_index] * preview_from_file->h[preview_index] *
234 sizeof(uint)) == bhead->len);
235 result->rect[preview_index] = static_cast<uint *>(
236 BLO_library_read_struct(fd, bhead, "PreviewImage Icon Rect"));
237 }
238 else {
239 /* This should not be needed, but can happen in 'broken' .blend files,
240 * better handle this gracefully than crashing. */
241 BLI_assert(preview_from_file->rect[preview_index] == nullptr &&
242 preview_from_file->w[preview_index] == 0 &&
243 preview_from_file->h[preview_index] == 0);
244 result->rect[preview_index] = nullptr;
245 result->w[preview_index] = result->h[preview_index] = 0;
246 }
247 BKE_previewimg_finish(result, preview_index);
248 }
249
250 return bhead;
251}
252
254 int ofblocktype,
255 const char *name)
256{
257 FileData *fd = (FileData *)bh;
258 bool looking = false;
259 const int sdna_preview_image = DNA_struct_find_with_alias(fd->filesdna, "PreviewImage");
260
261 for (BHead *bhead = blo_bhead_first(fd); bhead; bhead = blo_bhead_next(fd, bhead)) {
262 if (bhead->code == BLO_CODE_DATA) {
263 if (looking && bhead->SDNAnr == sdna_preview_image) {
264 PreviewImage *preview_from_file = static_cast<PreviewImage *>(
265 BLO_library_read_struct(fd, bhead, "PreviewImage"));
266
267 if (preview_from_file == nullptr) {
268 break;
269 }
270
271 PreviewImage *result = static_cast<PreviewImage *>(MEM_dupallocN(preview_from_file));
272 result->runtime = MEM_new<blender::bke::PreviewImageRuntime>(__func__);
273 bhead = blo_blendhandle_read_preview_rects(fd, bhead, result, preview_from_file);
274 MEM_freeN(preview_from_file);
275 return result;
276 }
277 }
278 else if (looking || bhead->code == BLO_CODE_ENDB) {
279 /* We were looking for a preview image, but didn't find any belonging to block. So it doesn't
280 * exist. */
281 break;
282 }
283 else if (bhead->code == ofblocktype) {
284 const char *idname = blo_bhead_id_name(fd, bhead);
285 if (idname && STREQ(&idname[2], name)) {
286 looking = true;
287 }
288 }
289 }
290
291 return nullptr;
292}
293
295{
296 FileData *fd = (FileData *)bh;
297 GSet *gathered = BLI_gset_ptr_new("linkable_groups gh");
298 LinkNode *names = nullptr;
299 BHead *bhead;
300
301 for (bhead = blo_bhead_first(fd); bhead; bhead = blo_bhead_next(fd, bhead)) {
302 if (bhead->code == BLO_CODE_ENDB) {
303 break;
304 }
305 if (BKE_idtype_idcode_is_valid(bhead->code)) {
307 const char *str = BKE_idtype_idcode_to_name(bhead->code);
308
309 if (BLI_gset_add(gathered, (void *)str)) {
311 }
312 }
313 }
314 }
315
316 BLI_gset_free(gathered, nullptr);
317
318 return names;
319}
320
321void BLO_blendhandle_close(BlendHandle *bh)
322{
323 FileData *fd = (FileData *)bh;
324
326}
327
328void BLO_read_invalidate_message(BlendHandle *bh, Main *bmain, const char *message)
329{
330 FileData *fd = reinterpret_cast<FileData *>(bh);
331
332 blo_readfile_invalidate(fd, bmain, message);
333}
334
335/**********/
336
337BlendFileData *BLO_read_from_file(const char *filepath,
338 eBLOReadSkip skip_flags,
339 BlendFileReadReport *reports)
340{
341 BLI_assert(!BLI_path_is_rel(filepath));
343
344 BlendFileData *bfd = nullptr;
345 FileData *fd;
346
347 fd = blo_filedata_from_file(filepath, reports);
348 if (fd) {
349 fd->skip_flags = skip_flags;
350 bfd = blo_read_file_internal(fd, filepath);
352 }
353
354 return bfd;
355}
356
358 int memsize,
359 eBLOReadSkip skip_flags,
360 ReportList *reports)
361{
362 BlendFileData *bfd = nullptr;
363 FileData *fd;
364 BlendFileReadReport bf_reports{};
365 bf_reports.reports = reports;
366
367 fd = blo_filedata_from_memory(mem, memsize, &bf_reports);
368 if (fd) {
369 fd->skip_flags = skip_flags;
370 bfd = blo_read_file_internal(fd, "");
372 }
373
374 return bfd;
375}
376
378 const char *filepath,
379 MemFile *memfile,
381 ReportList *reports)
382{
383 BlendFileData *bfd = nullptr;
384 FileData *fd;
385 BlendFileReadReport bf_reports{};
386 bf_reports.reports = reports;
387
388 fd = blo_filedata_from_memfile(memfile, params, &bf_reports);
389 if (fd) {
390 fd->skip_flags = eBLOReadSkip(params->skip_flags);
391 STRNCPY(fd->relabase, filepath);
392
393 /* Build old ID map for all old IDs. */
394 blo_make_old_idmap_from_main(fd, oldmain);
395
396 /* Separate linked data from old main.
397 * WARNING: Do not split out packed IDs here, as these are handled similarly as local IDs in
398 * undo context. */
399 blo_split_main(oldmain, false);
400 fd->old_bmain = oldmain;
401
402 /* Removed packed data from this trick - it's internal data that needs saves. */
403
404 /* Store all existing ID caches pointers into a mapping, to allow restoring them into newly
405 * read IDs whenever possible.
406 *
407 * Note that this is only required for local data, since linked data are always re-used
408 * 'as-is'. */
409 blo_cache_storage_init(fd, oldmain);
410
411 bfd = blo_read_file_internal(fd, filepath);
412
413 /* Ensure relinked caches are not freed together with their old IDs. */
415
416 /* Still in-use libraries have already been moved from oldmain to new main
417 * (fd->bmain->split_mains), but oldmain itself shall *never* be 'transferred' to the new
418 * split_mains!
419 */
420 BLI_assert(oldmain->split_mains && (*oldmain->split_mains)[0] == oldmain);
421
422 /* That way, libraries (aka mains) we did not reuse in new undone/redone state
423 * will be cleared together with `oldmain`. */
424 blo_join_main(oldmain);
425
427 }
428
429 return bfd;
430}
431
433{
434 if (bfd->main) {
435 BKE_main_free(bfd->main);
436 }
437
438 if (bfd->user) {
439 MEM_freeN(bfd->user);
440 }
441
442 MEM_delete(bfd);
443}
444
446 BlendfileLinkAppendContext *lapp_context,
447 BlendFileReadReport *reports)
448{
449 do_versions_after_setup(new_bmain, lapp_context, reports);
450}
void BKE_asset_metadata_free(AssetMetaData **asset_data)
Definition asset.cc:38
const char * BKE_idtype_idcode_to_name(short idcode)
Definition idtype.cc:164
bool BKE_idtype_idcode_is_linkable(short idcode)
Definition idtype.cc:197
bool BKE_idtype_idcode_is_valid(short idcode)
Definition idtype.cc:192
void BKE_main_free(Main *bmain)
Definition main.cc:192
void BKE_previewimg_finish(PreviewImage *prv, int size)
#define BLI_assert(a)
Definition BLI_assert.h:46
struct GSet GSet
Definition BLI_ghash.h:337
GSet * BLI_gset_ptr_new(const char *info)
void BLI_gset_free(GSet *gs, GSetKeyFreeFP keyfreefp)
bool BLI_gset_add(GSet *gs, void *key)
Definition BLI_ghash.cc:966
bool BLI_path_is_abs_from_cwd(const char *path) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT
bool BLI_path_is_rel(const char *path) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT
char * BLI_strdup(const char *str) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1) ATTR_MALLOC
Definition string.cc:41
char * STRNCPY(char(&dst)[N], const char *src)
Definition BLI_string.h:693
unsigned int uint
#define STREQ(a, b)
Compatibility-like things for windows.
@ BLO_CODE_ENDB
@ BLO_CODE_DATA
external readfile function prototypes.
eBLOReadSkip
void * BLO_library_read_struct(FileData *fd, BHead *bh, const char *blockname)
Definition readfile.cc:5315
@ ID_FLAG_LINKED_AND_PACKED
Definition DNA_ID.h:804
@ NUM_ICON_SIZES
blenloader genfile private function prototypes
int DNA_struct_find_with_alias(const struct SDNA *sdna, const char *str)
Read Guarded memory(de)allocation.
#define str(s)
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
void * MEM_mallocN(size_t len, const char *str)
Definition mallocn.cc:128
void * MEM_dupallocN(const void *vmemh)
Definition mallocn.cc:143
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
VecBase< int32_t, 3 > int3
const char * name
LinkNode * BLO_blendhandle_get_datablock_info(BlendHandle *bh, int ofblocktype, const bool use_assets_only, int *r_tot_info_items)
void BLO_datablock_info_linklist_free(LinkNode *datablock_infos)
void BLO_datablock_info_free(BLODataBlockInfo *datablock_info)
void BLO_read_invalidate_message(BlendHandle *bh, Main *bmain, const char *message)
PreviewImage * BLO_blendhandle_get_preview_for_id(BlendHandle *bh, int ofblocktype, const char *name)
static bool blendhandle_load_id_data_and_validate(FileData *fd, BHead *bhead, bool use_assets_only, const char *&r_idname, short &r_idflag, AssetMetaData *&r_asset_meta_data)
BlendHandle * BLO_blendhandle_from_file(const char *filepath, BlendFileReadReport *reports)
BlendHandle * BLO_blendhandle_from_memory(const void *mem, int memsize, BlendFileReadReport *reports)
blender::int3 BLO_blendhandle_get_version(const BlendHandle *bh)
BlendFileData * BLO_read_from_memfile(Main *oldmain, const char *filepath, MemFile *memfile, const BlendFileReadParams *params, ReportList *reports)
BlendFileData * BLO_read_from_memory(const void *mem, int memsize, eBLOReadSkip skip_flags, ReportList *reports)
BlendFileData * BLO_read_from_file(const char *filepath, eBLOReadSkip skip_flags, BlendFileReadReport *reports)
static BHead * blo_blendhandle_read_preview_rects(FileData *fd, BHead *bhead, PreviewImage *result, const PreviewImage *preview_from_file)
LinkNode * BLO_blendhandle_get_datablock_names(BlendHandle *bh, int ofblocktype, const bool use_assets_only, int *r_tot_names)
void BLO_read_do_version_after_setup(Main *new_bmain, BlendfileLinkAppendContext *lapp_context, BlendFileReadReport *reports)
LinkNode * BLO_blendhandle_get_linkable_groups(BlendHandle *bh)
void BLO_blendhandle_close(BlendHandle *bh)
void BLO_blendfiledata_free(BlendFileData *bfd)
void blo_join_main(Main *bmain)
Definition readfile.cc:359
const char * blo_bhead_id_name(FileData *fd, const BHead *bhead)
Definition readfile.cc:784
BHead * blo_bhead_next(FileData *fd, BHead *thisblock)
Definition readfile.cc:713
BHead * blo_bhead_first(FileData *fd)
Definition readfile.cc:685
AssetMetaData * blo_bhead_id_asset_data_address(const FileData *fd, const BHead *bhead)
Definition readfile.cc:808
BlendFileData * blo_read_file_internal(FileData *fd, const char *filepath)
Definition readfile.cc:3978
FileData * blo_filedata_from_memfile(MemFile *memfile, const BlendFileReadParams *params, BlendFileReadReport *reports)
Definition readfile.cc:1382
FileData * blo_filedata_from_file(const char *filepath, BlendFileReadReport *reports)
Definition readfile.cc:1320
FileData * blo_filedata_from_memory(const void *mem, const int memsize, BlendFileReadReport *reports)
Definition readfile.cc:1350
void blo_cache_storage_init(FileData *fd, Main *bmain)
Definition readfile.cc:1691
void blo_make_old_idmap_from_main(FileData *fd, Main *bmain)
Definition readfile.cc:1593
BHead * blo_read_asset_data_block(FileData *fd, BHead *bhead, AssetMetaData **r_asset_data)
Definition readfile.cc:3400
void blo_split_main(Main *bmain, const bool do_split_packed_ids)
Definition readfile.cc:415
short blo_bhead_id_flag(const FileData *fd, const BHead *bhead)
Definition readfile.cc:798
void blo_filedata_free(FileData *fd)
Definition readfile.cc:1399
BHead * blo_bhead_prev(FileData *, BHead *thisblock)
Definition readfile.cc:705
void blo_readfile_invalidate(FileData *fd, Main *bmain, const char *message)
Definition readfile.cc:556
void blo_cache_storage_old_bmain_clear(FileData *fd, Main *bmain_old)
Definition readfile.cc:1727
void do_versions_after_setup(Main *new_bmain, BlendfileLinkAppendContext *lapp_context, BlendFileReadReport *reports)
The meta-data of an asset. By creating and giving this for a data-block (ID.asset_data),...
int64_t len
AssetMetaData * asset_data
UserDef * user
eBLOReadSkip skip_flags
Definition readfile.hh:130
int fileversion
Definition readfile.hh:111
Main * old_bmain
Definition readfile.hh:168
int filesubversion
Definition readfile.hh:116
char relabase[FILE_MAX]
Definition readfile.hh:102
SDNA * filesdna
Definition readfile.hh:105
std::shared_ptr< blender::VectorSet< Main * > > split_mains
Definition BKE_main.hh:166
unsigned int h[2]
Definition DNA_ID.h:643
unsigned int * rect[2]
Definition DNA_ID.h:646
unsigned int w[2]
Definition DNA_ID.h:642