diff options
Diffstat (limited to 'source/blender/windowmanager/intern/wm_files.c')
-rw-r--r-- | source/blender/windowmanager/intern/wm_files.c | 264 |
1 files changed, 167 insertions, 97 deletions
diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c index 06aaf95f232..f83511e76f0 100644 --- a/source/blender/windowmanager/intern/wm_files.c +++ b/source/blender/windowmanager/intern/wm_files.c @@ -28,11 +28,10 @@ * winsock stuff. */ #include <errno.h> +#include <fcntl.h> /* for open flags (O_BINARY, O_RDONLY). */ #include <stddef.h> #include <string.h> -#include "zlib.h" /* wm_read_exotic() */ - #ifdef WIN32 /* Need to include windows.h so _WIN32_IE is defined. */ # include <windows.h> @@ -51,6 +50,7 @@ #include "BLI_blenlib.h" #include "BLI_fileops_types.h" +#include "BLI_filereader.h" #include "BLI_linklist.h" #include "BLI_math.h" #include "BLI_system.h" @@ -481,53 +481,64 @@ static void wm_init_userdef(Main *bmain) /* intended to check for non-blender formats but for now it only reads blends */ static int wm_read_exotic(const char *name) { - int len; - gzFile gzfile; + /* make sure we're not trying to read a directory.... */ + + int namelen = strlen(name); + if (namelen > 0 && ELEM(name[namelen - 1], '/', '\\')) { + return BKE_READ_EXOTIC_FAIL_PATH; + } + + /* open the file. */ + const int filedes = BLI_open(name, O_BINARY | O_RDONLY, 0); + if (filedes == -1) { + return BKE_READ_EXOTIC_FAIL_OPEN; + } + + FileReader *rawfile = BLI_filereader_new_file(filedes); + if (rawfile == NULL) { + return BKE_READ_EXOTIC_FAIL_OPEN; + } + + /* read the header (7 bytes are enough to identify all known types). */ char header[7]; - int retval; + if (rawfile->read(rawfile, header, sizeof(header)) != sizeof(header)) { + rawfile->close(rawfile); + return BKE_READ_EXOTIC_FAIL_FORMAT; + } + rawfile->seek(rawfile, 0, SEEK_SET); - /* make sure we're not trying to read a directory.... */ + /* check for uncompressed .blend */ + if (STREQLEN(header, "BLENDER", 7)) { + rawfile->close(rawfile); + return BKE_READ_EXOTIC_OK_BLEND; + } - len = strlen(name); - if (len > 0 && ELEM(name[len - 1], '/', '\\')) { - retval = BKE_READ_EXOTIC_FAIL_PATH; + /* check for compressed .blend */ + FileReader *compressed_file = NULL; + if (BLI_file_magic_is_gzip(header)) { + /* In earlier versions of Blender (before 3.0), compressed files used Gzip instead of Zstd. + * While these files will no longer be written, there still needs to be reading support. */ + compressed_file = BLI_filereader_new_gzip(rawfile); + } + else if (BLI_file_magic_is_zstd(header)) { + compressed_file = BLI_filereader_new_zstd(rawfile); } - else { - gzfile = BLI_gzopen(name, "rb"); - if (gzfile == NULL) { - retval = BKE_READ_EXOTIC_FAIL_OPEN; - } - else { - len = gzread(gzfile, header, sizeof(header)); - gzclose(gzfile); - if (len == sizeof(header) && STREQLEN(header, "BLENDER", 7)) { - retval = BKE_READ_EXOTIC_OK_BLEND; - } - else { - /* We may want to support loading other file formats - * from their header bytes or file extension. - * This used to be supported in the code below and may be added - * back at some point. */ -#if 0 - WM_cursor_wait(true); - if (is_foo_format(name)) { - read_foo(name); - retval = BKE_READ_EXOTIC_OK_OTHER; - } - else -#endif - { - retval = BKE_READ_EXOTIC_FAIL_FORMAT; - } -#if 0 - WM_cursor_wait(false); -#endif - } + /* If a compression signature matches, try decompressing the start and check if it's a .blend */ + if (compressed_file != NULL) { + size_t len = compressed_file->read(compressed_file, header, sizeof(header)); + compressed_file->close(compressed_file); + if (len == sizeof(header) && STREQLEN(header, "BLENDER", 7)) { + return BKE_READ_EXOTIC_OK_BLEND; } } + else { + rawfile->close(rawfile); + } - return retval; + /* Add check for future file formats here. */ + + return BKE_READ_EXOTIC_FAIL_FORMAT; } /** \} */ @@ -596,19 +607,33 @@ static void wm_file_read_pre(bContext *C, bool use_data, bool UNUSED(use_userdef } /** + * Parameters for #wm_file_read_post, also used for deferred initialization. + */ +struct wmFileReadPost_Params { + uint use_data : 1; + uint use_userdef : 1; + + uint is_startup_file : 1; + uint is_factory_startup : 1; + uint reset_app_template : 1; +}; + +/** * Logic shared between #WM_file_read & #wm_homefile_read, * updates to make after reading a file. */ -static void wm_file_read_post(bContext *C, - const bool is_startup_file, - const bool is_factory_startup, - const bool use_data, - const bool use_userdef, - const bool reset_app_template) +static void wm_file_read_post(bContext *C, const struct wmFileReadPost_Params *params) { - bool addons_loaded = false; wmWindowManager *wm = CTX_wm_manager(C); + const bool use_data = params->use_data; + const bool use_userdef = params->use_userdef; + const bool is_startup_file = params->is_startup_file; + const bool is_factory_startup = params->is_factory_startup; + const bool reset_app_template = params->reset_app_template; + + bool addons_loaded = false; + if (use_data) { if (!G.background) { /* remove windows which failed to be added via WM_check */ @@ -797,22 +822,31 @@ static void file_read_reports_finalize(BlendFileReadReport *bf_reports) bf_reports->count.resynced_lib_overrides, duration_lib_override_recursive_resync_minutes, duration_lib_override_recursive_resync_seconds); + if (bf_reports->resynced_lib_overrides_libraries_count != 0) { for (LinkNode *node_lib = bf_reports->resynced_lib_overrides_libraries; node_lib != NULL; node_lib = node_lib->next) { Library *library = node_lib->link; BKE_reportf( - bf_reports->reports, RPT_INFO, "Library %s needs overrides resync.", library->filepath); + bf_reports->reports, RPT_INFO, "Library %s needs overrides resync", library->filepath); } } + if (bf_reports->count.missing_libraries != 0 || bf_reports->count.missing_linked_id != 0) { BKE_reportf(bf_reports->reports, RPT_WARNING, - "%d libraries and %d linked data-blocks are missing, please check the " - "Info and Outliner editors for details", + "%d libraries and %d linked data-blocks are missing (including %d ObjectData and " + "%d Proxies), please check the Info and Outliner editors for details", bf_reports->count.missing_libraries, - bf_reports->count.missing_linked_id); + bf_reports->count.missing_linked_id, + bf_reports->count.missing_obdata, + bf_reports->count.missing_obproxies); } + else { + BLI_assert(bf_reports->count.missing_obdata == 0); + BLI_assert(bf_reports->count.missing_obproxies == 0); + } + if (bf_reports->resynced_lib_overrides_libraries_count != 0) { BKE_reportf(bf_reports->reports, RPT_WARNING, @@ -901,7 +935,14 @@ bool WM_file_read(bContext *C, const char *filepath, ReportList *reports) wm_history_file_update(); } - wm_file_read_post(C, false, false, use_data, use_userdef, false); + wm_file_read_post(C, + &(const struct wmFileReadPost_Params){ + .use_data = use_data, + .use_userdef = use_userdef, + .is_startup_file = false, + .is_factory_startup = false, + .reset_app_template = false, + }); bf_reports.duration.whole = PIL_check_seconds_timer() - bf_reports.duration.whole; file_read_reports_finalize(&bf_reports); @@ -984,31 +1025,18 @@ const char *WM_init_state_app_template_get(void) /** * Called on startup, (context entirely filled with NULLs) - * or called for 'New File' both startup.blend and userpref.blend are checked. - * - * \param use_factory_settings: - * Ignore on-disk startup file, use bundled `datatoc_startup_blend` instead. - * Used for "Restore Factory Settings". + * or called for 'New File' both `startup.blend` and `userpref.blend` are checked. * - * \param use_userdef: Load factory settings as well as startup file. - * Disabled for "File New" we don't want to reload preferences. - * - * \param filepath_startup_override: - * Optional path pointing to an alternative blend file (may be NULL). - * - * \param app_template_override: - * Template to use instead of the template defined in user-preferences. - * When not-null, this is written into the user preferences. + * \param r_params_file_read_post: Support postponed initialization, + * needed for initial startup when only some sub-systems have been initialized. + * When non-null, #wm_file_read_post doesn't run, instead it's arguments are stored + * in this return argument. + * The caller is responsible for calling #wm_homefile_read_post with this return argument. */ -void wm_homefile_read(bContext *C, - ReportList *reports, - bool use_factory_settings, - bool use_empty_data, - bool use_data, - bool use_userdef, - const char *filepath_startup_override, - const char *app_template_override, - bool *r_is_factory_startup) +void wm_homefile_read_ex(bContext *C, + const struct wmHomeFileRead_Params *params_homefile, + ReportList *reports, + struct wmFileReadPost_Params **r_params_file_read_post) { #if 0 /* UNUSED, keep as this may be needed later & the comment below isn't self evident. */ /* Context does not always have valid main pointer here. */ @@ -1017,6 +1045,14 @@ void wm_homefile_read(bContext *C, ListBase wmbase; bool success = false; + /* May be enabled, when the user configuration doesn't exist. */ + const bool use_data = params_homefile->use_data; + const bool use_userdef = params_homefile->use_userdef; + bool use_factory_settings = params_homefile->use_factory_settings; + const bool use_empty_data = params_homefile->use_empty_data; + const char *filepath_startup_override = params_homefile->filepath_startup_override; + const char *app_template_override = params_homefile->app_template_override; + bool filepath_startup_is_factory = true; char filepath_startup[FILE_MAX]; char filepath_userdef[FILE_MAX]; @@ -1304,13 +1340,45 @@ void wm_homefile_read(bContext *C, G.save_over = 0; } - wm_file_read_post(C, true, is_factory_startup, use_data, use_userdef, reset_app_template); + { + const struct wmFileReadPost_Params params_file_read_post = { + .use_data = use_data, + .use_userdef = use_userdef, + .is_startup_file = true, + .is_factory_startup = is_factory_startup, + .reset_app_template = reset_app_template, + }; + if (r_params_file_read_post == NULL) { + wm_file_read_post(C, ¶ms_file_read_post); + } + else { + *r_params_file_read_post = MEM_mallocN(sizeof(struct wmFileReadPost_Params), __func__); + **r_params_file_read_post = params_file_read_post; - if (r_is_factory_startup) { - *r_is_factory_startup = is_factory_startup; + /* Match #wm_file_read_post which leaves the window cleared too. */ + CTX_wm_window_set(C, NULL); + } } } +void wm_homefile_read(bContext *C, + const struct wmHomeFileRead_Params *params_homefile, + ReportList *reports) +{ + wm_homefile_read_ex(C, params_homefile, reports, NULL); +} + +/** + * Special case, support deferred execution of #wm_file_read_post, + * Needed when loading for the first time to workaround order of initialization bug, see T89046. + */ +void wm_homefile_read_post(struct bContext *C, + const struct wmFileReadPost_Params *params_file_read_post) +{ + wm_file_read_post(C, params_file_read_post); + MEM_freeN((void *)params_file_read_post); +} + /* -------------------------------------------------------------------- */ /** \name Blend-File History API * \{ */ @@ -2078,14 +2146,15 @@ static int wm_userpref_read_exec(bContext *C, wmOperator *op) UserDef U_backup = U; wm_homefile_read(C, - op->reports, - use_factory_settings, - false, - use_data, - use_userdef, - NULL, - WM_init_state_app_template_get(), - NULL); + &(const struct wmHomeFileRead_Params){ + .use_data = use_data, + .use_userdef = use_userdef, + .use_factory_settings = use_factory_settings, + .use_empty_data = false, + .filepath_startup_override = NULL, + .app_template_override = WM_init_state_app_template_get(), + }, + op->reports); wm_userpref_read_exceptions(&U, &U_backup); SET_FLAG_FROM_TEST(G.f, use_factory_settings, G_FLAG_USERPREF_NO_SAVE_ON_EXIT); @@ -2224,16 +2293,17 @@ static int wm_homefile_read_exec(bContext *C, wmOperator *op) app_template = WM_init_state_app_template_get(); } - bool use_data = true; wm_homefile_read(C, - op->reports, - use_factory_settings, - use_empty_data, - use_data, - use_userdef, - filepath, - app_template, - NULL); + &(const struct wmHomeFileRead_Params){ + .use_data = true, + .use_userdef = use_userdef, + .use_factory_settings = use_factory_settings, + .use_empty_data = use_empty_data, + .filepath_startup_override = filepath, + .app_template_override = app_template, + }, + op->reports); + if (use_splash) { WM_init_splash(C); } @@ -3434,7 +3504,7 @@ static uiBlock *block_create__close_file_dialog(struct bContext *C, BLI_split_file_part(blendfile_pathpath, filename, sizeof(filename)); } else { - STRNCPY(filename, IFACE_("untitled.blend")); + STRNCPY(filename, "untitled.blend"); } uiItemL(layout, filename, ICON_NONE); |