Refactor BKE_bpath module.
The main goal of this refactor is to make BPath module use `IDTypeInfo`, and move each ID-specific part of the `foreach_path` looper into their own IDTypeInfo struct, using a new `foreach_path` callback. Additionally, following improvements/cleanups are included: * Attempt to get better, more consistent namings. ** In particular, move from `path_visitor` to more standard `foreach_path`. * Update and extend documentation. ** API doc was moved to header, according to recent discussions on this topic. * Remove `BKE_bpath_relocate_visitor` from API, this is specific callback that belongs in `lib_id.c` user code. NOTE: This commit is expected to be 100% non-behavioral-change. This implies that several potential further changes were only noted as comments (like using a more generic solution for `lib_id_library_local_paths`, addressing inconsistencies like path of packed libraries always being skipped, regardless of the `BKE_BPATH_FOREACH_PATH_SKIP_PACKED` `eBPathForeachFlag` flag value, etc.). NOTE: basic unittests were added to master already in rBdcc500e5a265093bc9cc. Reviewed By: brecht Differential Revision: https://developer.blender.org/D13381
This commit is contained in:
@@ -16,10 +16,14 @@
|
||||
|
||||
/** \file
|
||||
* \ingroup bke
|
||||
* \attention Based on ghash, difference is ghash is not a fixed size,
|
||||
* so for BPath we don't need to malloc
|
||||
*
|
||||
* \warning All paths manipulated by this API are assumed to be either constant char buffers of
|
||||
* `FILE_MAX` size, or allocated char buffers not bigger than `FILE_MAX`.
|
||||
*/
|
||||
|
||||
/* TODO: Make this module handle a bit more safely string length, instead of assuming buffers are
|
||||
* FILE_MAX len etc. */
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
@@ -31,66 +35,175 @@ struct ListBase;
|
||||
struct Main;
|
||||
struct ReportList;
|
||||
|
||||
/* Function that does something with an ID's file path. Should return 1 if the
|
||||
* path has changed, and in that case, should write the result to pathOut. */
|
||||
typedef bool (*BPathVisitor)(void *userdata, char *path_dst, const char *path_src);
|
||||
/* Executes 'visit' for each path associated with 'id'. */
|
||||
void BKE_bpath_traverse_id(struct Main *bmain,
|
||||
struct ID *id,
|
||||
BPathVisitor visit_cb,
|
||||
const int flag,
|
||||
void *bpath_user_data);
|
||||
void BKE_bpath_traverse_id_list(struct Main *bmain,
|
||||
struct ListBase *lb,
|
||||
BPathVisitor visit_cb,
|
||||
const int flag,
|
||||
void *bpath_user_data);
|
||||
void BKE_bpath_traverse_main(struct Main *bmain,
|
||||
BPathVisitor visit_cb,
|
||||
const int flag,
|
||||
void *bpath_user_data);
|
||||
bool BKE_bpath_relocate_visitor(void *oldbasepath, char *path_dst, const char *path_src);
|
||||
/** \name Core `foreach_path` API.
|
||||
* \{ */
|
||||
|
||||
/* Functions for temp backup/restore of paths, path count must NOT change */
|
||||
void *BKE_bpath_list_backup(struct Main *bmain, const int flag);
|
||||
void BKE_bpath_list_restore(struct Main *bmain, const int flag, void *ls_handle);
|
||||
void BKE_bpath_list_free(void *ls_handle);
|
||||
typedef enum eBPathForeachFlag {
|
||||
/** Flags controlling the behavior of the generic BPath API. */
|
||||
|
||||
enum {
|
||||
/* convert paths to absolute */
|
||||
BKE_BPATH_TRAVERSE_ABS = (1 << 0),
|
||||
/* skip library paths */
|
||||
BKE_BPATH_TRAVERSE_SKIP_LIBRARY = (1 << 1),
|
||||
/* skip packed data */
|
||||
BKE_BPATH_TRAVERSE_SKIP_PACKED = (1 << 2),
|
||||
/* skip paths where a single dir is used with an array of files, eg.
|
||||
* sequence strip images and pointcache. in this case only use the first
|
||||
* file, this is needed for directory manipulation functions which might
|
||||
* otherwise modify the same directory multiple times */
|
||||
BKE_BPATH_TRAVERSE_SKIP_MULTIFILE = (1 << 3),
|
||||
/* reload data (when the path is edited) */
|
||||
BKE_BPATH_TRAVERSE_RELOAD_EDITED = (1 << 4),
|
||||
};
|
||||
/** Ensures the `absolute_base_path` member of #BPathForeachPathData is initialized properly with
|
||||
* the path of the current .blend file. This can be used by the callbacks to convert relative
|
||||
* paths to absolute ones. */
|
||||
BKE_BPATH_FOREACH_PATH_ABSOLUTE = (1 << 0),
|
||||
/** Skip paths of linked IDs. */
|
||||
BKE_BPATH_FOREACH_PATH_SKIP_LINKED = (1 << 1),
|
||||
/** Skip paths when their matching data is packed. */
|
||||
BKE_BPATH_FOREACH_PATH_SKIP_PACKED = (1 << 2),
|
||||
|
||||
/* high level funcs */
|
||||
/** Flags not affecting the generic BPath API. Those may be used by specific IDTypeInfo
|
||||
* `foreach_path` implementations and/or callbacks to implement specific behaviors. */
|
||||
|
||||
/* creates a text file with missing files if there are any */
|
||||
/** Skip paths where a single dir is used with an array of files, eg. sequence strip images or
|
||||
* pointcaches. In this case only use the first file path is processed.
|
||||
*
|
||||
* This is needed for directory manipulation callbacks which might otherwise modify the same
|
||||
* directory multiple times. */
|
||||
BKE_BPATH_FOREACH_PATH_SKIP_MULTIFILE = (1 << 8),
|
||||
/** Reload data (when the path is edited).
|
||||
* \note Ony used by Image IDType currently. */
|
||||
BKE_BPATH_FOREACH_PATH_RELOAD_EDITED = (1 << 9),
|
||||
} eBPathForeachFlag;
|
||||
|
||||
struct BPathForeachPathData;
|
||||
|
||||
/** Callback used to iterate over an ID's file paths.
|
||||
*
|
||||
* \note `path`s parameters should be considered as having a maximal `FILE_MAX` string length.
|
||||
*
|
||||
* \return `true` if the path has been changed, and in that case, result should be written into
|
||||
* `r_path_dst`. */
|
||||
typedef bool (*BPathForeachPathFunctionCallback)(struct BPathForeachPathData *bpath_data,
|
||||
char *r_path_dst,
|
||||
const char *path_src);
|
||||
|
||||
/** Storage for common data needed accross the BPath 'foreach_path' code. */
|
||||
typedef struct BPathForeachPathData {
|
||||
struct Main *bmain;
|
||||
|
||||
BPathForeachPathFunctionCallback callback_function;
|
||||
eBPathForeachFlag flag;
|
||||
|
||||
void *user_data;
|
||||
|
||||
/* 'Private' data, caller don't need to set those. */
|
||||
|
||||
/** The root to use as base for relative paths. Only set if `BKE_BPATH_FOREACH_PATH_ABSOLUTE`
|
||||
* flag is set, NULL otherwise. */
|
||||
const char *absolute_base_path;
|
||||
} BPathForeachPathData;
|
||||
|
||||
/** Run `bpath_data.callback_function` on all paths contained in `id`. */
|
||||
void BKE_bpath_foreach_path_id(BPathForeachPathData *bpath_data, struct ID *id);
|
||||
|
||||
/** Run `bpath_data.callback_function` on all paths of all IDs in `bmain`. */
|
||||
void BKE_bpath_foreach_path_main(BPathForeachPathData *bpath_data);
|
||||
|
||||
/** \} */
|
||||
|
||||
/** \name Helpers to handle common cases from `IDTypeInfo`'s `foreach_path` functions.
|
||||
* \{ */
|
||||
|
||||
/* TODO: Investigate using macros around those calls to check a bit better about actual
|
||||
* strings/buffers length (e,g, with static asserts). */
|
||||
|
||||
/**
|
||||
* Run the callback on a path, replacing the content of the string as needed.
|
||||
*
|
||||
* \param path: A fixed, FILE_MAX-sized char buffer.
|
||||
*
|
||||
* \return true is \a path was modified, false otherwise.
|
||||
*/
|
||||
bool BKE_bpath_foreach_path_fixed_process(struct BPathForeachPathData *bpath_data, char *path);
|
||||
|
||||
/**
|
||||
* Run the callback on a (directory + file) path, replacing the content of the two strings as
|
||||
* needed.
|
||||
*
|
||||
* \param path_dir: A fixed, FILE_MAXDIR-sized char buffer.
|
||||
* \param path_file: A fixed, FILE_MAXFILE-sized char buffer.
|
||||
*
|
||||
* \return true is \a path_dir and/or \a path_file were modified, false otherwise.
|
||||
*/
|
||||
bool BKE_bpath_foreach_path_dirfile_fixed_process(struct BPathForeachPathData *bpath_data,
|
||||
char *path_dir,
|
||||
char *path_file);
|
||||
|
||||
/**
|
||||
* Run the callback on a path, replacing the content of the string as needed.
|
||||
*
|
||||
* \param path: A pointer to a MEM-allocated string. If modified, it will be freed and replaced by
|
||||
* a new allocated string.
|
||||
* \note path is expected to be FILE_MAX size or smaller.
|
||||
*
|
||||
* \return true is \a path was modified and re-allocated, false otherwise.
|
||||
*/
|
||||
bool BKE_bpath_foreach_path_allocated_process(struct BPathForeachPathData *bpath_data,
|
||||
char **path);
|
||||
|
||||
/** \} */
|
||||
|
||||
/** \name High level features.
|
||||
* \{ */
|
||||
|
||||
/** Check for missing files. */
|
||||
void BKE_bpath_missing_files_check(struct Main *bmain, struct ReportList *reports);
|
||||
|
||||
/** Recursively search into given search directory, for all file paths of all IDs in given \a
|
||||
* bmain, and replace existing paths as needed.
|
||||
*
|
||||
* \note The search will happen into the whole search directory tree recursively (with a limit of
|
||||
* MAX_DIR_RECURSE), if several files are found matching a searched filename, the biggest one will
|
||||
* be used. This is so that things like thumbnails don't get selected instead of the actual image
|
||||
* e.g.
|
||||
*
|
||||
* \param searchpath: The root directory in which the new filepaths should be searched for.
|
||||
* \param find_all: If `true`, also search for files which current path is still valid, if `false`
|
||||
* skip those still valid paths.
|
||||
* */
|
||||
void BKE_bpath_missing_files_find(struct Main *bmain,
|
||||
const char *searchpath,
|
||||
struct ReportList *reports,
|
||||
const bool find_all);
|
||||
|
||||
/** Rebase all relative file paths in given \a bmain from \a basedir_src to \a basedir_dst. */
|
||||
void BKE_bpath_relative_rebase(struct Main *bmain,
|
||||
const char *basedir_src,
|
||||
const char *basedir_dst,
|
||||
struct ReportList *reports);
|
||||
|
||||
/** Make all absolute file paths in given \a bmain relative to given \a basedir. */
|
||||
void BKE_bpath_relative_convert(struct Main *bmain,
|
||||
const char *basedir,
|
||||
struct ReportList *reports);
|
||||
|
||||
/** Make all relative file paths in given \a bmain absolute, using given \a basedir as root. */
|
||||
void BKE_bpath_absolute_convert(struct Main *bmain,
|
||||
const char *basedir,
|
||||
struct ReportList *reports);
|
||||
|
||||
/** Temp backup of paths from all IDs in given \a bmain.
|
||||
*
|
||||
* \return An opaque handle to pass to #BKE_bpath_list_restore and #BKE_bpath_list_free.
|
||||
*/
|
||||
void *BKE_bpath_list_backup(struct Main *bmain, const eBPathForeachFlag flag);
|
||||
|
||||
/** Restore the temp backup of paths from \a path_list_handle into all IDs in given \a bmain.
|
||||
*
|
||||
* \note This function assumes that the data in given Main did not change (no
|
||||
* addition/deletion/re-ordering of IDs, or their file paths) since the call to
|
||||
* #BKE_bpath_list_backup that generated the given \a path_list_handle. */
|
||||
void BKE_bpath_list_restore(struct Main *bmain,
|
||||
const eBPathForeachFlag flag,
|
||||
void *path_list_handle);
|
||||
|
||||
/** Free the temp backup of paths in \a path_list_handle.
|
||||
*
|
||||
* \note This function assumes that the path list has already been restored with a call to
|
||||
* #BKE_bpath_list_restore, and is therefore empty. */
|
||||
void BKE_bpath_list_free(void *path_list_handle);
|
||||
|
||||
/** \} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user