Files
test2/source/blender/blenloader/intern/readfile.h
Bastien Montagne ebb5643e59 Readfile: Refactor several parts of the process
This commit affects:
* Reading undo steps from memfile (aka 'Global Undo');
* Handling of UI IDs (WindowManager, Workspaces and Screens) when
  opening a .blend file.

While no major changes are expected from a user PoV, there may be some
unexpected changes in rare edge-cases. None has been identified so far.

Undo step loading should be marginally faster (`setup_app_data` itself
is 2-3 times faster, as it does not do remapping anymore, which makes the
whole 'read undo step' process about 20% faster - but the most
time-consuming step on undo is the depsgraph processing, which remains
unchanged here).

This commit also solves some bugs (crashes) in some relatively uncommon
cases, like e.g. if the WM had an IDProperty pointing at an object and
UI is not loaded when opening a new .blend file with the 'Load UI' option
enabled (as in previous code on file opening WM ID would never be
remapped).

From a more technical side, this commit aims mainly at cleaning things
up, in preparation for the introduction of new 'no undo, no readfile'
type of handling (as part of the Brush Assets project):
  - Prevent WM code from doing (too much) horrible ID 'management' on
    its WM when opening a new file. It used to remove current WM from
    the Main database, store it in a temporary own list, and then free
    it itself...
  - Trying to make the complex logic behind WM handling on file reading a
    bit more easy to follow, at least way more documented in code.
  - Keep the handling of 'IDs being re-used from old Main' in a single
    place, as much as possible:
    -- Readfile code itself in undo case (because it's more efficient,
       and undo case is in a way simpler than actual .blend file
       reading case). The whole `blo_lib_link_restore` block of code
       is also removed.
    -- (Mostly) setup_app_data code in actual file reading case.
  - Sanitize the usage of the 'libmap' in readfile code in undo case
    (waaaaay too many pointers were added there, which was hiding some
     other issues in the related code, and potentially causing (in
     rare cases) memory addresses collisions.

Pull Request: https://projects.blender.org/blender/blender/pulls/108016
2023-06-05 13:54:49 +02:00

262 lines
9.0 KiB
C

/* SPDX-FileCopyrightText: 2001-2002 NaN Holding BV. All rights reserved.
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup blenloader
* blenloader readfile private function prototypes.
*/
#pragma once
#include <stdio.h> /* Include header using off_t before poisoning it below. */
#ifdef WIN32
# include "BLI_winstuff.h"
#endif
#include "BLI_filereader.h"
#include "DNA_sdna_types.h"
#include "DNA_space_types.h"
#include "DNA_windowmanager_types.h" /* for eReportType */
#ifdef __cplusplus
extern "C" {
#endif
struct BLOCacheStorage;
struct IDNameLib_Map;
struct Key;
struct MemFile;
struct Object;
struct OldNewMap;
struct ReportList;
struct UserDef;
typedef struct IDNameLib_Map IDNameLib_Map;
enum eFileDataFlag {
FD_FLAGS_SWITCH_ENDIAN = 1 << 0,
FD_FLAGS_FILE_POINTSIZE_IS_4 = 1 << 1,
FD_FLAGS_POINTSIZE_DIFFERS = 1 << 2,
FD_FLAGS_FILE_OK = 1 << 3,
FD_FLAGS_IS_MEMFILE = 1 << 4,
/* XXX Unused in practice (checked once but never set). */
FD_FLAGS_NOT_MY_LIBMAP = 1 << 5,
};
ENUM_OPERATORS(eFileDataFlag, FD_FLAGS_NOT_MY_LIBMAP)
/* Disallow since it's 32bit on ms-windows. */
#ifdef __GNUC__
# pragma GCC poison off_t
#endif
typedef struct FileData {
/** Linked list of BHeadN's. */
ListBase bhead_list;
enum eFileDataFlag flags;
bool is_eof;
FileReader *file;
/** Whether we are undoing (< 0) or redoing (> 0), used to choose which 'unchanged' flag to use
* to detect unchanged data from memfile. */
int undo_direction; /* eUndoStepDir */
/** Now only in use for library appending. */
char relabase[FILE_MAX];
/** General reading variables. */
struct SDNA *filesdna;
const struct SDNA *memsdna;
/** Array of #eSDNA_StructCompare. */
const char *compflags;
struct DNA_ReconstructInfo *reconstruct_info;
int fileversion;
/** Used to retrieve ID names from (bhead+1). */
int id_name_offset;
/** Used to retrieve asset data from (bhead+1). NOTE: This may not be available in old files,
* will be -1 then! */
int id_asset_data_offset;
/** For do_versions patching. */
int globalf, fileflags;
/** Optionally skip some data-blocks when they're not needed. */
eBLOReadSkip skip_flags;
/**
* Tag to apply to all loaded ID data-blocks.
*
* \note This is initialized from #LibraryLink_Params.id_tag_extra since passing it as an
* argument would need an additional argument to be passed around when expanding library data.
*/
int id_tag_extra;
struct OldNewMap *datamap;
struct OldNewMap *globmap;
/**
* Store mapping from old ID pointers (the values they have in the .blend file) to new ones,
* typically from value in `bhead->old` to address in memory where the ID was read.
* Used during library-linking process (see #lib_link_all).
*/
struct OldNewMap *libmap;
struct OldNewMap *packedmap;
struct BLOCacheStorage *cache_storage;
struct BHeadSort *bheadmap;
int tot_bheadmap;
/** See: #USE_GHASH_BHEAD. */
struct GHash *bhead_idname_hash;
ListBase *mainlist;
/** Used for undo. */
ListBase *old_mainlist;
/**
* IDMap using UUID's as keys of all the old IDs in the old bmain. Used during undo to find a
* matching old data when reading a new ID. */
struct IDNameLib_Map *old_idmap_uuid;
/**
* IDMap using uuids as keys of the IDs read (or moved) in the new main(s).
*
* Used during undo to ensure that the ID pointers from the 'no undo' IDs remain valid (these
* IDs are re-used from old main even if their content is not the same as in the memfile undo
* step, so they could point e.g. to an ID that does not exist in the newly read undo step).
*
* Also used to find current valid pointers (or none) of these 'no undo' IDs existing in
* read memfile. */
struct IDNameLib_Map *new_idmap_uuid;
struct BlendFileReadReport *reports;
} FileData;
#define SIZEOFBLENDERHEADER 12
/***/
struct Main;
void blo_join_main(ListBase *mainlist);
void blo_split_main(ListBase *mainlist, struct Main *main);
struct BlendFileData *blo_read_file_internal(FileData *fd, const char *filepath);
/**
* On each new library added, it now checks for the current #FileData and expands relativeness
*
* cannot be called with relative paths anymore!
*/
FileData *blo_filedata_from_file(const char *filepath, struct BlendFileReadReport *reports);
FileData *blo_filedata_from_memory(const void *mem,
int memsize,
struct BlendFileReadReport *reports);
FileData *blo_filedata_from_memfile(struct MemFile *memfile,
const struct BlendFileReadParams *params,
struct BlendFileReadReport *reports);
void blo_make_packed_pointer_map(FileData *fd, struct Main *oldmain);
/**
* Set old main packed data to zero if it has been restored
* this works because freeing old main only happens after this call.
*/
void blo_end_packed_pointer_map(FileData *fd, struct Main *oldmain);
/**
* Build a #GSet of old main (we only care about local data here,
* so we can do that after #blo_split_main() call.
*/
void blo_make_old_idmap_from_main(FileData *fd, struct Main *bmain);
BHead *blo_read_asset_data_block(FileData *fd, BHead *bhead, struct AssetMetaData **r_asset_data);
void blo_cache_storage_init(FileData *fd, struct Main *bmain);
void blo_cache_storage_old_bmain_clear(FileData *fd, struct Main *bmain_old);
void blo_cache_storage_end(FileData *fd);
void blo_filedata_free(FileData *fd);
BHead *blo_bhead_first(FileData *fd);
BHead *blo_bhead_next(FileData *fd, BHead *thisblock);
BHead *blo_bhead_prev(FileData *fd, BHead *thisblock);
/**
* Warning! Caller's responsibility to ensure given bhead **is** an ID one!
*/
const char *blo_bhead_id_name(const FileData *fd, const BHead *bhead);
/**
* Warning! Caller's responsibility to ensure given bhead **is** an ID one!
*/
struct AssetMetaData *blo_bhead_id_asset_data_address(const FileData *fd, const BHead *bhead);
/* do versions stuff */
/**
* Manipulates SDNA before calling #DNA_struct_get_compareflags,
* allowing us to rename structs and struct members.
*
* - This means older versions of Blender won't have access to this data **USE WITH CARE**.
* - These changes are applied on file load (run-time), similar to versioning for compatibility.
*
* \attention ONLY USE THIS KIND OF VERSIONING WHEN `dna_rename_defs.h` ISN'T SUFFICIENT.
*/
void blo_do_versions_dna(struct SDNA *sdna, int versionfile, int subversionfile);
void blo_do_versions_oldnewmap_insert(struct OldNewMap *onm,
const void *oldaddr,
void *newaddr,
int nr);
/**
* Only library data.
*/
void *blo_do_versions_newlibadr(struct FileData *fd,
ID *self_id,
const bool is_linked_only,
const void *adr);
/**
* \note this version patch is intended for versions < 2.52.2,
* but was initially introduced in 2.27 already.
*/
void blo_do_version_old_trackto_to_constraints(struct Object *ob);
void blo_do_versions_key_uidgen(struct Key *key);
/**
* Patching #UserDef struct and Themes.
*/
void blo_do_versions_userdef(struct UserDef *userdef);
void blo_do_versions_pre250(struct FileData *fd, struct Library *lib, struct Main *bmain);
void blo_do_versions_250(struct FileData *fd, struct Library *lib, struct Main *bmain);
void blo_do_versions_260(struct FileData *fd, struct Library *lib, struct Main *bmain);
void blo_do_versions_270(struct FileData *fd, struct Library *lib, struct Main *bmain);
void blo_do_versions_280(struct FileData *fd, struct Library *lib, struct Main *bmain);
void blo_do_versions_290(struct FileData *fd, struct Library *lib, struct Main *bmain);
void blo_do_versions_300(struct FileData *fd, struct Library *lib, struct Main *bmain);
void blo_do_versions_400(struct FileData *fd, struct Library *lib, struct Main *bmain);
void blo_do_versions_cycles(struct FileData *fd, struct Library *lib, struct Main *bmain);
void do_versions_after_linking_250(struct Main *bmain);
void do_versions_after_linking_260(struct Main *bmain);
void do_versions_after_linking_270(struct Main *bmain);
void do_versions_after_linking_280(struct FileData *fd, struct Main *bmain);
void do_versions_after_linking_290(struct FileData *fd, struct Main *bmain);
void do_versions_after_linking_300(struct FileData *fd, struct Main *bmain);
void do_versions_after_linking_400(struct FileData *fd, struct Main *bmain);
void do_versions_after_linking_cycles(struct Main *bmain);
/**
* Direct data-blocks with global linking.
*
* \note This is rather unfortunate to have to expose this here,
* but better use that nasty hack in do_version than readfile itself.
*/
void *blo_read_get_new_globaldata_address(struct FileData *fd, const void *adr);
/* Mark the Main data as invalid (.blend file reading should be aborted ASAP, and the already read
* data should be discarded). Also add an error report to `fd` including given `message`. */
void blo_readfile_invalidate(struct FileData *fd, struct Main *bmain, const char *message);
#ifdef __cplusplus
}
#endif