Blender V4.5
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,
70{
71 BlendHandle *bh;
72
73 bh = (BlendHandle *)blo_filedata_from_memory(mem, memsize, reports);
74
75 return bh;
76}
77
79 int ofblocktype,
80 const bool use_assets_only,
81 int *r_tot_names)
82{
83 FileData *fd = (FileData *)bh;
84 LinkNode *names = nullptr;
85 BHead *bhead;
86 int tot = 0;
87
88 for (bhead = blo_bhead_first(fd); bhead; bhead = blo_bhead_next(fd, bhead)) {
89 if (bhead->code == ofblocktype) {
90 const char *idname = blo_bhead_id_name(fd, bhead);
91 if (!idname) {
92 continue;
93 }
94 if (use_assets_only && blo_bhead_id_asset_data_address(fd, bhead) == nullptr) {
95 continue;
96 }
97
98 BLI_linklist_prepend(&names, BLI_strdup(idname + 2));
99 tot++;
100 }
101 else if (bhead->code == BLO_CODE_ENDB) {
102 break;
103 }
104 }
105
106 *r_tot_names = tot;
107 return names;
108}
109
111 int ofblocktype,
112 const bool use_assets_only,
113 int *r_tot_info_items)
114{
115 FileData *fd = (FileData *)bh;
116 LinkNode *infos = nullptr;
117 BHead *bhead;
118 int tot = 0;
119
120 const int sdna_nr_preview_image = DNA_struct_find_with_alias(fd->filesdna, "PreviewImage");
121
122 for (bhead = blo_bhead_first(fd); bhead; bhead = blo_bhead_next(fd, bhead)) {
123 if (bhead->code == BLO_CODE_ENDB) {
124 break;
125 }
126 if (bhead->code == ofblocktype) {
127 BHead *id_bhead = bhead;
128
129 const char *idname = blo_bhead_id_name(fd, bhead);
130 if (!idname) {
131 continue;
132 }
133 const char *name = idname + 2;
134 AssetMetaData *asset_meta_data = blo_bhead_id_asset_data_address(fd, bhead);
135
136 const bool is_asset = asset_meta_data != nullptr;
137 const bool skip_datablock = use_assets_only && !is_asset;
138 if (skip_datablock) {
139 continue;
140 }
142
143 /* Lastly, read asset data from the following blocks. */
144 if (asset_meta_data) {
145 bhead = blo_read_asset_data_block(fd, bhead, &asset_meta_data);
146 /* blo_read_asset_data_block() reads all DATA heads and already advances bhead to the
147 * next non-DATA one. Go back, so the loop doesn't skip the non-DATA head. */
148 bhead = blo_bhead_prev(fd, bhead);
149 }
150
151 STRNCPY(info->name, name);
152 info->asset_data = asset_meta_data;
153 info->free_asset_data = true;
154
155 bool has_preview = false;
156 /* See if we can find a preview in the data of this ID. */
157 for (BHead *data_bhead = blo_bhead_next(fd, id_bhead); data_bhead->code == BLO_CODE_DATA;
158 data_bhead = blo_bhead_next(fd, data_bhead))
159 {
160 if (data_bhead->SDNAnr == sdna_nr_preview_image) {
161 has_preview = true;
162 break;
163 }
164 }
165 info->no_preview_found = !has_preview;
166
167 BLI_linklist_prepend(&infos, info);
168 tot++;
169 }
170 }
171
172 *r_tot_info_items = tot;
173 return infos;
174}
175
191 BHead *bhead,
193 const PreviewImage *preview_from_file)
194{
195 for (int preview_index = 0; preview_index < NUM_ICON_SIZES; preview_index++) {
196 if (preview_from_file->rect[preview_index] && preview_from_file->w[preview_index] &&
197 preview_from_file->h[preview_index])
198 {
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] = static_cast<uint *>(
203 BLO_library_read_struct(fd, bhead, "PreviewImage Icon Rect"));
204 }
205 else {
206 /* This should not be needed, but can happen in 'broken' .blend files,
207 * better handle this gracefully than crashing. */
208 BLI_assert(preview_from_file->rect[preview_index] == nullptr &&
209 preview_from_file->w[preview_index] == 0 &&
210 preview_from_file->h[preview_index] == 0);
211 result->rect[preview_index] = nullptr;
212 result->w[preview_index] = result->h[preview_index] = 0;
213 }
214 BKE_previewimg_finish(result, preview_index);
215 }
216
217 return bhead;
218}
219
221 int ofblocktype,
222 const char *name)
223{
224 FileData *fd = (FileData *)bh;
225 bool looking = false;
226 const int sdna_preview_image = DNA_struct_find_with_alias(fd->filesdna, "PreviewImage");
227
228 for (BHead *bhead = blo_bhead_first(fd); bhead; bhead = blo_bhead_next(fd, bhead)) {
229 if (bhead->code == BLO_CODE_DATA) {
230 if (looking && bhead->SDNAnr == sdna_preview_image) {
231 PreviewImage *preview_from_file = static_cast<PreviewImage *>(
232 BLO_library_read_struct(fd, bhead, "PreviewImage"));
233
234 if (preview_from_file == nullptr) {
235 break;
236 }
237
238 PreviewImage *result = static_cast<PreviewImage *>(MEM_dupallocN(preview_from_file));
239 result->runtime = MEM_new<blender::bke::PreviewImageRuntime>(__func__);
240 bhead = blo_blendhandle_read_preview_rects(fd, bhead, result, preview_from_file);
241 MEM_freeN(preview_from_file);
242 return result;
243 }
244 }
245 else if (looking || bhead->code == BLO_CODE_ENDB) {
246 /* We were looking for a preview image, but didn't find any belonging to block. So it doesn't
247 * exist. */
248 break;
249 }
250 else if (bhead->code == ofblocktype) {
251 const char *idname = blo_bhead_id_name(fd, bhead);
252 if (idname && STREQ(&idname[2], name)) {
253 looking = true;
254 }
255 }
256 }
257
258 return nullptr;
259}
260
262{
263 FileData *fd = (FileData *)bh;
264 GSet *gathered = BLI_gset_ptr_new("linkable_groups gh");
265 LinkNode *names = nullptr;
266 BHead *bhead;
267
268 for (bhead = blo_bhead_first(fd); bhead; bhead = blo_bhead_next(fd, bhead)) {
269 if (bhead->code == BLO_CODE_ENDB) {
270 break;
271 }
272 if (BKE_idtype_idcode_is_valid(bhead->code)) {
274 const char *str = BKE_idtype_idcode_to_name(bhead->code);
275
276 if (BLI_gset_add(gathered, (void *)str)) {
278 }
279 }
280 }
281 }
282
283 BLI_gset_free(gathered, nullptr);
284
285 return names;
286}
287
288void BLO_blendhandle_close(BlendHandle *bh)
289{
290 FileData *fd = (FileData *)bh;
291
293}
294
295void BLO_read_invalidate_message(BlendHandle *bh, Main *bmain, const char *message)
296{
297 FileData *fd = reinterpret_cast<FileData *>(bh);
298
299 blo_readfile_invalidate(fd, bmain, message);
300}
301
302/**********/
303
304BlendFileData *BLO_read_from_file(const char *filepath,
305 eBLOReadSkip skip_flags,
307{
308 BLI_assert(!BLI_path_is_rel(filepath));
310
311 BlendFileData *bfd = nullptr;
312 FileData *fd;
313
314 fd = blo_filedata_from_file(filepath, reports);
315 if (fd) {
316 fd->skip_flags = skip_flags;
317 bfd = blo_read_file_internal(fd, filepath);
319 }
320
321 return bfd;
322}
323
325 int memsize,
326 eBLOReadSkip skip_flags,
328{
329 BlendFileData *bfd = nullptr;
330 FileData *fd;
331 BlendFileReadReport bf_reports{};
332 bf_reports.reports = reports;
333
334 fd = blo_filedata_from_memory(mem, memsize, &bf_reports);
335 if (fd) {
336 fd->skip_flags = skip_flags;
337 bfd = blo_read_file_internal(fd, "");
339 }
340
341 return bfd;
342}
343
345 const char *filepath,
346 MemFile *memfile,
349{
350 BlendFileData *bfd = nullptr;
351 FileData *fd;
352 ListBase old_mainlist;
353 BlendFileReadReport bf_reports{};
354 bf_reports.reports = reports;
355
356 fd = blo_filedata_from_memfile(memfile, params, &bf_reports);
357 if (fd) {
358 fd->skip_flags = eBLOReadSkip(params->skip_flags);
359 STRNCPY(fd->relabase, filepath);
360
361 /* Build old ID map for all old IDs. */
362 blo_make_old_idmap_from_main(fd, oldmain);
363
364 /* Separate linked data from old main. */
365 blo_split_main(&old_mainlist, oldmain);
366 fd->old_mainlist = &old_mainlist;
367
368 /* Removed packed data from this trick - it's internal data that needs saves. */
369
370 /* Store all existing ID caches pointers into a mapping, to allow restoring them into newly
371 * read IDs whenever possible.
372 *
373 * Note that this is only required for local data, since linked data are always re-used
374 * 'as-is'. */
375 blo_cache_storage_init(fd, oldmain);
376
377 bfd = blo_read_file_internal(fd, filepath);
378
379 /* Ensure relinked caches are not freed together with their old IDs. */
381
382 /* Still in-use libraries have already been moved from oldmain to new mainlist,
383 * but oldmain itself shall *never* be 'transferred' to new mainlist! */
384 BLI_assert(old_mainlist.first == oldmain);
385
386 /* That way, libraries (aka mains) we did not reuse in new undone/redone state
387 * will be cleared together with `oldmain`. */
388 blo_join_main(&old_mainlist);
389
391 }
392
393 return bfd;
394}
395
397{
398 if (bfd->main) {
399 BKE_main_free(bfd->main);
400 }
401
402 if (bfd->user) {
403 MEM_freeN(bfd->user);
404 }
405
406 MEM_delete(bfd);
407}
408
void BKE_asset_metadata_free(AssetMetaData **asset_data)
Definition asset.cc:38
const char * BKE_idtype_idcode_to_name(short idcode)
Definition idtype.cc:165
bool BKE_idtype_idcode_is_linkable(short idcode)
Definition idtype.cc:198
bool BKE_idtype_idcode_is_valid(short idcode)
Definition idtype.cc:193
void BKE_main_free(Main *bmain)
Definition main.cc:175
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:688
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:4819
@ 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.
ReportList * reports
Definition WM_types.hh:1025
BKE_main_namemap_clear * new_bmain
Definition blendfile.cc:603
#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
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)
BlendHandle * BLO_blendhandle_from_file(const char *filepath, BlendFileReadReport *reports)
BlendHandle * BLO_blendhandle_from_memory(const void *mem, int memsize, BlendFileReadReport *reports)
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)
const char * blo_bhead_id_name(FileData *fd, const BHead *bhead)
Definition readfile.cc:816
BHead * blo_bhead_next(FileData *fd, BHead *thisblock)
Definition readfile.cc:745
BHead * blo_bhead_first(FileData *fd)
Definition readfile.cc:717
AssetMetaData * blo_bhead_id_asset_data_address(const FileData *fd, const BHead *bhead)
Definition readfile.cc:829
BlendFileData * blo_read_file_internal(FileData *fd, const char *filepath)
Definition readfile.cc:3771
FileData * blo_filedata_from_memfile(MemFile *memfile, const BlendFileReadParams *params, BlendFileReadReport *reports)
Definition readfile.cc:1393
FileData * blo_filedata_from_file(const char *filepath, BlendFileReadReport *reports)
Definition readfile.cc:1331
FileData * blo_filedata_from_memory(const void *mem, const int memsize, BlendFileReadReport *reports)
Definition readfile.cc:1361
void blo_split_main(ListBase *mainlist, Main *main)
Definition readfile.cc:402
void blo_cache_storage_init(FileData *fd, Main *bmain)
Definition readfile.cc:1708
void blo_make_old_idmap_from_main(FileData *fd, Main *bmain)
Definition readfile.cc:1610
BHead * blo_read_asset_data_block(FileData *fd, BHead *bhead, AssetMetaData **r_asset_data)
Definition readfile.cc:3214
void blo_filedata_free(FileData *fd)
Definition readfile.cc:1410
BHead * blo_bhead_prev(FileData *, BHead *thisblock)
Definition readfile.cc:737
void blo_readfile_invalidate(FileData *fd, Main *bmain, const char *message)
Definition readfile.cc:586
void blo_cache_storage_old_bmain_clear(FileData *fd, Main *bmain_old)
Definition readfile.cc:1744
void blo_join_main(ListBase *mainlist)
Definition readfile.cc:355
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:120
ListBase * old_mainlist
Definition readfile.hh:149
char relabase[FILE_MAX]
Definition readfile.hh:100
SDNA * filesdna
Definition readfile.hh:103
void * first
unsigned int h[2]
Definition DNA_ID.h:566
unsigned int * rect[2]
Definition DNA_ID.h:569
unsigned int w[2]
Definition DNA_ID.h:565