From fdaaea632863ca260ba751929049a164d3b26cb8 Mon Sep 17 00:00:00 2001 From: Michal Krupa Date: Thu, 19 Jun 2025 16:39:20 +0200 Subject: [PATCH] Core: Increase MAX_ID_NAME length from 66 to 258 (Blender 5.0) Change the maximum data-block name from 64 to 256 bytes by increasing MAX_ID_NAME value. Also increase a few related non-ID data name max size, essentially the action slots identifiers, as these are the primary key used to match an Action's slot to an ID by name. Other sub-data (bones, modifiers, etc.) lengths are not modified here, as these can be made actual dynamic strings in the future, while keeping (a reasonable level of) forward compatibility, during the course of Blender 5 release cycles. Implements #137608. Co-authored-by: Bastien Montagne Pull Request: https://projects.blender.org/blender/blender/pulls/137196 --- scripts/modules/blend_render_info.py | 7 ++ source/blender/animrig/intern/action_test.cc | 23 +++++-- .../blender/asset_system/AS_asset_library.hh | 2 +- .../asset_system/intern/asset_library.cc | 4 +- .../intern/asset_representation.cc | 2 +- .../blender/blenkernel/BKE_blender_version.h | 2 +- source/blender/blenkernel/BKE_lib_id.hh | 4 +- .../blender/blenkernel/intern/asset_edit.cc | 5 ++ .../blender/blenkernel/intern/lib_id_test.cc | 64 ++++++++++++++++--- source/blender/blenlib/intern/path_utils.cc | 6 ++ .../editors/include/UI_interface_types.hh | 4 +- .../editors/sculpt_paint/brush_asset_ops.cc | 6 ++ source/blender/editors/space_file/filelist.hh | 4 +- .../editors/space_view3d/view3d_draw.cc | 27 ++++---- source/blender/makesdna/DNA_ID.h | 16 +++-- source/blender/makesdna/DNA_action_types.h | 2 +- source/blender/makesdna/DNA_anim_types.h | 6 +- .../blender/makesdna/DNA_constraint_types.h | 2 +- source/blender/makesdna/DNA_space_types.h | 4 +- source/blender/render/intern/render_result.cc | 5 ++ .../files/io_tests/fbx/max2025-longnames.fbx | 4 +- .../fbx/reference/max2025-longnames.txt | 16 ++--- tests/files/io_tests/obj/invalid_syntax.obj | 4 +- .../io_tests/obj/reference/invalid_syntax.txt | 4 +- tests/python/bl_animation_action.py | 26 ++++++-- 25 files changed, 179 insertions(+), 70 deletions(-) diff --git a/scripts/modules/blend_render_info.py b/scripts/modules/blend_render_info.py index 0ba02ab17fc..1d2b60619b1 100755 --- a/scripts/modules/blend_render_info.py +++ b/scripts/modules/blend_render_info.py @@ -113,6 +113,13 @@ def _read_blend_rend_chunk_from_file(blendfile, filepath): scene_name = blendfile.read(64) sizeof_data_left -= 64 + if b'\0' not in scene_name: + if sizeof_data_left >= 192: + # Assume new, up to 256 bytes name. + scene_name += blendfile.read(192) + sizeof_data_left -= 192 + if b'\0' not in scene_name: + scene_name = scene_name[:-1] + b'\0' scene_name = scene_name[:scene_name.index(b'\0')] # It's possible old blend files are not UTF8 compliant, use `surrogateescape`. diff --git a/source/blender/animrig/intern/action_test.cc b/source/blender/animrig/intern/action_test.cc index e34c3f47f88..d42f7024959 100644 --- a/source/blender/animrig/intern/action_test.cc +++ b/source/blender/animrig/intern/action_test.cc @@ -1130,14 +1130,25 @@ TEST_F(ActionLayersTest, conversion_to_layered) ASSERT_TRUE(bag->fcurve_array[0]->modifiers.first == nullptr); ASSERT_TRUE(bag->fcurve_array[1]->modifiers.first != nullptr); - Action *long_name_action = BKE_id_new( - bmain, "name_for_an_action_that_is_exactly_64_chars_which_is_MAX_ID_NAME"); + constexpr char id_name_max[] = + "name_for_an_action_that_is_exactly_255_bytes_MAX_ID_NAME-3______" + "name_for_an_action_that_is_exactly_255_bytes_MAX_ID_NAME-3______" + "name_for_an_action_that_is_exactly_255_bytes_MAX_ID_NAME-3______" + "name_for_an_action_that_is_exactly_255_bytes_MAX_ID_NAME-3_____"; + BLI_STATIC_ASSERT(std::string::traits_type::length(id_name_max) == MAX_ID_NAME - 2 - 1, + "Wrong 'max length' name"); + Action *long_name_action = BKE_id_new(bmain, id_name_max); action_fcurve_ensure_legacy(bmain, long_name_action, "Long", nullptr, {"location", 0}); + /* The long name is shortened to make space for "_layered". */ + constexpr char id_name_max_converted[] = + "name_for_an_action_that_is_exactly_255_bytes_MAX_ID_NAME-3______" + "name_for_an_action_that_is_exactly_255_bytes_MAX_ID_NAME-3______" + "name_for_an_action_that_is_exactly_255_bytes_MAX_ID_NAME-3______" + "name_for_an_action_that_is_exactly_255_bytes_MAX_ID_NAM_layered"; + BLI_STATIC_ASSERT(std::string::traits_type::length(id_name_max_converted) == MAX_ID_NAME - 2 - 1, + "Wrong 'max length' name"); converted = convert_to_layered_action(*bmain, *long_name_action); - /* AC gets added automatically by Blender, the long name is shortened to make space for - * "_layered". */ - EXPECT_STREQ(converted->id.name, - "ACname_for_an_action_that_is_exactly_64_chars_which_is_MA_layered"); + EXPECT_STREQ(BKE_id_name(converted->id), id_name_max_converted); } TEST_F(ActionLayersTest, conversion_to_layered_action_groups) diff --git a/source/blender/asset_system/AS_asset_library.hh b/source/blender/asset_system/AS_asset_library.hh index 024da532e83..86be474b0cf 100644 --- a/source/blender/asset_system/AS_asset_library.hh +++ b/source/blender/asset_system/AS_asset_library.hh @@ -299,7 +299,7 @@ void AS_asset_library_remap_ids(const blender::bke::id::IDRemapper &mappings); * \param r_name: Returns the ID name on success. Optional (passing null is allowed). */ void AS_asset_full_path_explode_from_weak_ref(const AssetWeakReference *asset_reference, - char r_path_buffer[1090 /* FILE_MAX_LIBEXTRA */], + char r_path_buffer[1282 /* FILE_MAX_LIBEXTRA */], char **r_dir, char **r_group, char **r_name); diff --git a/source/blender/asset_system/intern/asset_library.cc b/source/blender/asset_system/intern/asset_library.cc index de6b2414598..1f73928651d 100644 --- a/source/blender/asset_system/intern/asset_library.cc +++ b/source/blender/asset_system/intern/asset_library.cc @@ -103,7 +103,7 @@ void AS_asset_library_remap_ids(const bke::id::IDRemapper &mappings) } void AS_asset_full_path_explode_from_weak_ref(const AssetWeakReference *asset_reference, - char r_path_buffer[1090 /* FILE_MAX_LIBEXTRA */], + char r_path_buffer[1282 /* FILE_MAX_LIBEXTRA */], char **r_dir, char **r_group, char **r_name) @@ -129,7 +129,7 @@ void AS_asset_full_path_explode_from_weak_ref(const AssetWeakReference *asset_re BLI_assert(!exploded->group_component.is_empty()); BLI_assert(!exploded->name_component.is_empty()); - BLI_strncpy(r_path_buffer, exploded->full_path->c_str(), 1090 /* #FILE_MAX_LIBEXTRA. */); + BLI_strncpy(r_path_buffer, exploded->full_path->c_str(), 1282 /* #FILE_MAX_LIBEXTRA. */); if (!exploded->dir_component.is_empty()) { r_path_buffer[exploded->dir_component.size()] = '\0'; diff --git a/source/blender/asset_system/intern/asset_representation.cc b/source/blender/asset_system/intern/asset_representation.cc index d130e856cbd..9e2f6d60014 100644 --- a/source/blender/asset_system/intern/asset_representation.cc +++ b/source/blender/asset_system/intern/asset_representation.cc @@ -132,7 +132,7 @@ std::string AssetRepresentation::full_library_path() const { std::string asset_path = full_path(); - char blend_path[/*FILE_MAX_LIBEXTRA*/ 1090]; + char blend_path[/*FILE_MAX_LIBEXTRA*/ 1282]; if (!BKE_blendfile_library_path_explode(asset_path.c_str(), blend_path, nullptr, nullptr)) { return {}; } diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h index aadaf8cc32c..340b90b7cdd 100644 --- a/source/blender/blenkernel/BKE_blender_version.h +++ b/source/blender/blenkernel/BKE_blender_version.h @@ -27,7 +27,7 @@ /* Blender file format version. */ #define BLENDER_FILE_VERSION BLENDER_VERSION -#define BLENDER_FILE_SUBVERSION 21 +#define BLENDER_FILE_SUBVERSION 22 /* Minimum Blender version that supports reading file written with the current * version. Older Blender versions will test this and cancel loading the file, showing a warning to diff --git a/source/blender/blenkernel/BKE_lib_id.hh b/source/blender/blenkernel/BKE_lib_id.hh index f6303f46d65..0fe6e22cec8 100644 --- a/source/blender/blenkernel/BKE_lib_id.hh +++ b/source/blender/blenkernel/BKE_lib_id.hh @@ -788,8 +788,8 @@ void BKE_main_lib_objects_recalc_all(Main *bmain); */ void BKE_main_id_repair_duplicate_names_listbase(Main *bmain, ListBase *lb); -#define MAX_ID_FULL_NAME (64 + 64 + 3 + 1) /* 64 is MAX_ID_NAME - 2 */ -#define MAX_ID_FULL_NAME_UI (MAX_ID_FULL_NAME + 3) /* Adds `keycode` two letters at beginning. */ +#define MAX_ID_FULL_NAME (256 + 256 + 3 + 1) /* 256 is MAX_ID_NAME - 2 */ +#define MAX_ID_FULL_NAME_UI (MAX_ID_FULL_NAME + 3) /* Adds 'keycode' two letters at beginning. */ /** * Generate full name of the data-block (without ID code, but with library if any). * diff --git a/source/blender/blenkernel/intern/asset_edit.cc b/source/blender/blenkernel/intern/asset_edit.cc index 001d7f9e6bb..90ad2c799a1 100644 --- a/source/blender/blenkernel/intern/asset_edit.cc +++ b/source/blender/blenkernel/intern/asset_edit.cc @@ -125,6 +125,11 @@ static std::string asset_blendfile_path_for_save(const bUserAssetLibrary &user_l std::min(sizeof(base_name_filesafe), size_t(base_name.size() + 1))); BLI_path_make_safe_filename(base_name_filesafe); + /* FIXME: MAX_ID_NAME & FILE_MAXFILE + * + * This already does not respect the FILE_MAXFILE max length of filenames for the final filepath + * it seems? + */ { const std::string filepath = root_path + SEP + base_name_filesafe + BLENDER_ASSET_FILE_SUFFIX; if (!BLI_is_file(filepath.c_str())) { diff --git a/source/blender/blenkernel/intern/lib_id_test.cc b/source/blender/blenkernel/intern/lib_id_test.cc index dd792c9b2ba..f139d64a06b 100644 --- a/source/blender/blenkernel/intern/lib_id_test.cc +++ b/source/blender/blenkernel/intern/lib_id_test.cc @@ -14,6 +14,8 @@ #include "DNA_ID.h" +#include + namespace blender::bke::tests { struct LibIDMainSortTestContext { @@ -163,13 +165,27 @@ TEST(lib_id_main_unique_name, local_ids_rename_existing_never) STRNCPY(future_name, "OB_BBBB"); EXPECT_FALSE(BKE_main_namemap_get_unique_name(*ctx.bmain, *id_c, future_name)); EXPECT_STREQ(future_name, "OB_BBBB"); + constexpr char long_name[] = + "OB_BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"; + BLI_STATIC_ASSERT(std::string::traits_type::length(long_name) == MAX_ID_NAME - 2 - 1, + "Wrong 'max length' name"); + constexpr char long_name_shorten[] = + "OB_BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"; + BLI_STATIC_ASSERT(std::string::traits_type::length(long_name_shorten) == MAX_ID_NAME - 2 - 2, + "Wrong 'max length' name"); /* Name too long, needs to be truncated. */ - STRNCPY(future_name, "OB_BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"); + STRNCPY(future_name, long_name); change_name(ctx.bmain, id_a, future_name, IDNewNameMode::RenameExistingNever); EXPECT_STREQ(id_a->name + 2, future_name); - EXPECT_STREQ(future_name, "OB_BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"); + EXPECT_STREQ(future_name, long_name); EXPECT_TRUE(BKE_main_namemap_get_unique_name(*ctx.bmain, *id_c, future_name)); - EXPECT_STREQ(future_name, "OB_BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"); + EXPECT_STREQ(future_name, long_name_shorten); } TEST(lib_id_main_unique_name, local_ids_rename_existing_always) @@ -303,7 +319,7 @@ TEST(lib_id_main_unique_name, linked_ids_1) static void change_name_global(Main *bmain, ID *id, const char *name) { BKE_main_namemap_remove_id(*bmain, *id); - BLI_strncpy(id->name + 2, name, MAX_NAME); + BLI_strncpy(id->name + 2, name, MAX_ID_NAME - 2); BKE_main_global_namemap_get_unique_name(*bmain, *id, id->name + 2); @@ -415,17 +431,45 @@ TEST(lib_id_main_unique_name, ids_sorted_by_default_with_libraries) TEST(lib_id_main_unique_name, name_too_long_handling) { LibIDMainSortTestContext ctx; - const char *name_a = "Long_Name_That_Does_Not_Fit_Into_Max_Name_Limit_And_Should_Get_Truncated"; - const char *name_b = "Another_Long_Name_That_Does_Not_Fit_And_Has_A_Number_Suffix.123456"; - const char *name_c = "Name_That_Has_Too_Long_Number_Suffix.1234567890"; + constexpr char name_a[] = + "Long_Name_That_Does_Not_Fit_Into_Max_Name_Limit_And_Should_Get_Truncated_" + "Long_Name_That_Does_Not_Fit_Into_Max_Name_Limit_And_Should_Get_Truncated_" + "Long_Name_That_Does_Not_Fit_Into_Max_Name_Limit_And_Should_Get_Truncated_" + "Long_Name_That_Does_Not_Fit_Into_Max_Name_Limit_And_Should_Get_Truncated"; + BLI_STATIC_ASSERT(std::string::traits_type::length(name_a) > MAX_ID_NAME - 2, + "Wrong 'max length' name"); + constexpr char name_a_shorten[] = + "Long_Name_That_Does_Not_Fit_Into_Max_Name_Limit_And_Should_Get_Truncated_" + "Long_Name_That_Does_Not_Fit_Into_Max_Name_Limit_And_Should_Get_Truncated_" + "Long_Name_That_Does_Not_Fit_Into_Max_Name_Limit_And_Should_Get_Truncated_" + "Long_Name_That_Does_Not_Fit_Into_Max"; + BLI_STATIC_ASSERT(std::string::traits_type::length(name_a_shorten) == MAX_ID_NAME - 2 - 1, + "Wrong 'max length' name"); + constexpr char name_b[] = + "Another_Long_Name_That_Does_Not_Fit_And_Has_A_Number_Suffix_____" + "Another_Long_Name_That_Does_Not_Fit_And_Has_A_Number_Suffix_____" + "Another_Long_Name_That_Does_Not_Fit_And_Has_A_Number_Suffix_____" + "Another_Long_Name_That_Does_Not_Fit_And_Has_A_Number_Suffix.123456"; + BLI_STATIC_ASSERT(std::string::traits_type::length(name_b) > MAX_ID_NAME - 2, + "Wrong 'max length' name"); + constexpr char name_b_shorten[] = + "Another_Long_Name_That_Does_Not_Fit_And_Has_A_Number_Suffix_____" + "Another_Long_Name_That_Does_Not_Fit_And_Has_A_Number_Suffix_____" + "Another_Long_Name_That_Does_Not_Fit_And_Has_A_Number_Suffix_____" + "Another_Long_Name_That_Does_Not_Fit_And_Has_A_Number_Suffix.123"; + BLI_STATIC_ASSERT(std::string::traits_type::length(name_b_shorten) == MAX_ID_NAME - 2 - 1, + "Wrong 'max length' name"); + constexpr char name_c[] = "Name_That_Has_Too_Long_Number_Suffix.1234567890"; + BLI_STATIC_ASSERT(std::string::traits_type::length(name_c) < MAX_ID_NAME - 2, + "Wrong 'max length' name"); ID *id_a = static_cast(BKE_id_new(ctx.bmain, ID_OB, name_a)); ID *id_b = static_cast(BKE_id_new(ctx.bmain, ID_OB, name_b)); ID *id_c = static_cast(BKE_id_new(ctx.bmain, ID_OB, name_c)); - EXPECT_STREQ(id_a->name + 2, "Long_Name_That_Does_Not_Fit_Into_Max_Name_Limit_And_Should_Get_"); - EXPECT_STREQ(id_b->name + 2, "Another_Long_Name_That_Does_Not_Fit_And_Has_A_Number_Suffix.123"); - EXPECT_STREQ(id_c->name + 2, "Name_That_Has_Too_Long_Number_Suffix.1234567890"); /* Unchanged */ + EXPECT_STREQ(BKE_id_name(*id_a), name_a_shorten); + EXPECT_STREQ(BKE_id_name(*id_b), name_b_shorten); + EXPECT_STREQ(BKE_id_name(*id_c), name_c); /* Unchanged */ EXPECT_TRUE(BKE_main_namemap_validate(*ctx.bmain)); diff --git a/source/blender/blenlib/intern/path_utils.cc b/source/blender/blenlib/intern/path_utils.cc index bcedf44c35b..bd5207e37af 100644 --- a/source/blender/blenlib/intern/path_utils.cc +++ b/source/blender/blenlib/intern/path_utils.cc @@ -133,6 +133,12 @@ void BLI_path_sequence_encode(char *path, { BLI_string_debug_size(path, path_maxncpy); + /* FIXME: MAX_ID_NAME & FILE_MAXFILE + * + * As this function directly works on a full file path (typically a FILE_MAX long char buffer), + * and does not perform any check on the filename part of the path, it can easily generate final + * paths containing a filename longer than the max supported length (FILE_MAXFILE). + */ BLI_snprintf(path, path_maxncpy, "%s%.*d%s", head, numlen, std::max(0, pic), tail); } diff --git a/source/blender/editors/include/UI_interface_types.hh b/source/blender/editors/include/UI_interface_types.hh index 9ce071e00b4..f7bac69f166 100644 --- a/source/blender/editors/include/UI_interface_types.hh +++ b/source/blender/editors/include/UI_interface_types.hh @@ -12,8 +12,8 @@ struct bContext; struct uiLayout; /* names */ -#define UI_MAX_DRAW_STR 400 -#define UI_MAX_NAME_STR 128 +#define UI_MAX_DRAW_STR 550 +#define UI_MAX_NAME_STR 256 #define UI_MAX_SHORTCUT_STR 64 /* Menu Callbacks */ diff --git a/source/blender/editors/sculpt_paint/brush_asset_ops.cc b/source/blender/editors/sculpt_paint/brush_asset_ops.cc index 7086a6a34d1..e9ba3db327e 100644 --- a/source/blender/editors/sculpt_paint/brush_asset_ops.cc +++ b/source/blender/editors/sculpt_paint/brush_asset_ops.cc @@ -153,6 +153,12 @@ static wmOperatorStatus brush_asset_save_as_exec(bContext *C, wmOperator *op) /* Determine file path to save to. */ PropertyRNA *name_prop = RNA_struct_find_property(op->ptr, "name"); + /* FIXME: MAX_ID_NAME & FILE_MAXFILE + * + * This `name` should be `MAX_ID_NAME - 2` long. + * + * This name might also be used as filename for the saved asset, thus hitting the size issue + * between ID names and file names (FILE_MAXFILE). */ char name[MAX_NAME] = ""; if (RNA_property_is_set(op->ptr, name_prop)) { RNA_property_string_get(op->ptr, name_prop, name); diff --git a/source/blender/editors/space_file/filelist.hh b/source/blender/editors/space_file/filelist.hh index 8f03d7f4239..b02b1ed2bfc 100644 --- a/source/blender/editors/space_file/filelist.hh +++ b/source/blender/editors/space_file/filelist.hh @@ -82,7 +82,7 @@ void filelist_init_icons(); void filelist_free_icons(); void filelist_file_get_full_path(const FileList *filelist, const FileDirEntry *file, - char r_filepath[/*FILE_MAX_LIBEXTRA*/ 1090]); + char r_filepath[/*FILE_MAX_LIBEXTRA*/ 1282]); bool filelist_file_is_preview_pending(const FileList *filelist, const FileDirEntry *file); /** * \return True if a new preview request was pushed, false otherwise (e.g. because the preview is @@ -121,7 +121,7 @@ bool filelist_is_dir(const FileList *filelist, const char *path); /** * May modify in place given `dirpath`, which is expected to be #FILE_MAX_LIBEXTRA length. */ -void filelist_setdir(FileList *filelist, char dirpath[/*FILE_MAX_LIBEXTRA*/ 1090]); +void filelist_setdir(FileList *filelist, char dirpath[/*FILE_MAX_LIBEXTRA*/ 1282]); /** * Limited version of full update done by space_file's file_refresh(), diff --git a/source/blender/editors/space_view3d/view3d_draw.cc b/source/blender/editors/space_view3d/view3d_draw.cc index f81f6dded59..8b70d7571e6 100644 --- a/source/blender/editors/space_view3d/view3d_draw.cc +++ b/source/blender/editors/space_view3d/view3d_draw.cc @@ -1364,6 +1364,17 @@ static void draw_selected_name( char frame[16]; } info_buffers; + /* Info can contain: + * - 1 frame number `(7 + 2)`. + * - 1 collection name `(MAX_ID_NAME - 2 + 3)`. + * - 1 object name `(MAX_ID_NAME - 2)`. + * - 1 object data name `(MAX_ID_NAME - 2)`. + * - 2 non-ID data names (bones, shapekeys...) `(MAX_NAME * 2)`. + * - 2 BREAD_CRUMB_SEPARATOR(s) `(6)`. + * - 1 SHAPE_KEY_PINNED marker and a trailing '\0' `(9+1)` - translated, so give some room! + * - 1 marker name `(MAX_NAME + 3)`. + */ + SNPRINTF(info_buffers.frame, "(%d)", cfra); info_array[i++] = info_buffers.frame; @@ -1377,15 +1388,6 @@ static void draw_selected_name( } } - /* Info can contain: - * - A frame `(7 + 2)`. - * - A collection name `(MAX_NAME + 3)`. - * - 3 object names `(MAX_NAME)`. - * - 2 BREAD_CRUMB_SEPARATOR(s) `(6)`. - * - A SHAPE_KEY_PINNED marker and a trailing '\0' `(9+1)` - translated, so give some room! - * - A marker name `(MAX_NAME + 3)`. - */ - /* get name of marker on current frame (if available) */ const char *markern = BKE_scene_find_marker_name(scene, cfra); @@ -1477,9 +1479,12 @@ static void draw_selected_name( } BLI_assert(i < int(ARRAY_SIZE(info_array))); - char info[300]; - /* It's expected there will be enough room for the buffer (if not, increase it). */ + + char info[MAX_ID_NAME * 4]; + /* It's expected there will be enough room for the whole string in the the buffer. If not, + * increase it. */ BLI_assert(BLI_string_len_array(info_array, i) < sizeof(info)); + BLI_string_join_array(info, sizeof(info), info_array, i); *yoffset -= VIEW3D_OVERLAY_LINEHEIGHT; diff --git a/source/blender/makesdna/DNA_ID.h b/source/blender/makesdna/DNA_ID.h index 2bd7af4709b..f5baf354d13 100644 --- a/source/blender/makesdna/DNA_ID.h +++ b/source/blender/makesdna/DNA_ID.h @@ -359,8 +359,8 @@ enum { * provides a common handle to place all data in double-linked lists. */ -/* 2 characters for ID code and 64 for actual name */ -#define MAX_ID_NAME 66 +/* 2 characters for ID code and 256 for actual name */ +#define MAX_ID_NAME 258 /** #ID_Runtime_Remap.status */ enum { @@ -412,7 +412,15 @@ typedef struct ID { /** If the ID is an asset, this pointer is set. Owning pointer. */ struct AssetMetaData *asset_data; - char name[/*MAX_ID_NAME*/ 66]; + /** + * Main identifier for this data-block. Must be unique within the ID name-space (defined by its + * type, and owning #Library). + * + * The first two bytes are always the #ID_Type code of the data-block's type. + * + * One critical usage is to reference external linked data. */ + char name[/*MAX_ID_NAME*/ 258]; + /** * ID_FLAG_... flags report on status of the data-block this ID belongs to * (persistent, saved to and read from .blend). @@ -531,7 +539,7 @@ typedef struct LibraryWeakReference { char library_filepath[/*FILE_MAX*/ 1024]; /** May be different from the current local ID name. */ - char library_id_name[/*MAX_ID_NAME*/ 66]; + char library_id_name[/*MAX_ID_NAME*/ 258]; char _pad[2]; } LibraryWeakReference; diff --git a/source/blender/makesdna/DNA_action_types.h b/source/blender/makesdna/DNA_action_types.h index 881ca18dd99..6ea580eb95c 100644 --- a/source/blender/makesdna/DNA_action_types.h +++ b/source/blender/makesdna/DNA_action_types.h @@ -1184,7 +1184,7 @@ typedef struct ActionSlot { * * \see #AnimData::slot_name */ - char identifier[/*MAX_ID_NAME*/ 66]; + char identifier[/*MAX_ID_NAME*/ 258]; /** * Type of ID-block that this slot is intended for. diff --git a/source/blender/makesdna/DNA_anim_types.h b/source/blender/makesdna/DNA_anim_types.h index 44a9e3c7727..85771d64254 100644 --- a/source/blender/makesdna/DNA_anim_types.h +++ b/source/blender/makesdna/DNA_anim_types.h @@ -441,7 +441,7 @@ typedef struct NlaStrip { * \note Most code should not write to this field directly, but use functions from * `blender::animrig::nla` instead, see ANIM_nla.hh. */ - char last_slot_identifier[66]; /* MAX_ID_NAME */ + char last_slot_identifier[/* MAX_ID_NAME */ 258]; char _pad0[2]; /** F-Curves for controlling this strip's influence and timing */ /* TODO: move out? */ @@ -677,7 +677,7 @@ typedef struct AnimData { * * \see #ActionSlot::name */ - char last_slot_identifier[66]; /* MAX_ID_NAME */ + char last_slot_identifier[/* MAX_ID_NAME */ 258]; uint8_t _pad0[2]; /** @@ -686,7 +686,7 @@ typedef struct AnimData { */ bAction *tmpact; int32_t tmp_slot_handle; - char tmp_last_slot_identifier[66]; /* MAX_ID_NAME */ + char tmp_last_slot_identifier[/* MAX_ID_NAME */ 258]; uint8_t _pad1[2]; /* nla-tracks */ diff --git a/source/blender/makesdna/DNA_constraint_types.h b/source/blender/makesdna/DNA_constraint_types.h index 2446df97652..907b0fdf7c8 100644 --- a/source/blender/makesdna/DNA_constraint_types.h +++ b/source/blender/makesdna/DNA_constraint_types.h @@ -303,7 +303,7 @@ typedef struct bActionConstraint { float eval_time; /* Only used when flag ACTCON_USE_EVAL_TIME is set. */ struct bAction *act; int32_t action_slot_handle; - char last_slot_identifier[/*MAX_ID_NAME*/ 66]; + char last_slot_identifier[/*MAX_ID_NAME*/ 258]; char _pad1[2]; char subtarget[/*MAX_NAME*/ 64]; } bActionConstraint; diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h index 5655a8f352e..67ab1fce395 100644 --- a/source/blender/makesdna/DNA_space_types.h +++ b/source/blender/makesdna/DNA_space_types.h @@ -396,10 +396,10 @@ typedef struct FileSelectParams { /** * Directory. * - * \note #FILE_MAX_LIBEXTRA == `1024 + 66`, this is for extreme case when 1023 length path + * \note #FILE_MAX_LIBEXTRA == `1024 + 258`, this is for extreme case when 1023 length path * needs to be linked in, where `foo.blend/Armature` need adding. */ - char dir[/*FILE_MAX_LIBEXTRA*/ 1090]; + char dir[/*FILE_MAX_LIBEXTRA*/ 1282]; char file[/*FILE_MAXFILE*/ 256]; char renamefile[/*FILE_MAXFILE*/ 256]; diff --git a/source/blender/render/intern/render_result.cc b/source/blender/render/intern/render_result.cc index 8f3651c489d..8e314cdd37b 100644 --- a/source/blender/render/intern/render_result.cc +++ b/source/blender/render/intern/render_result.cc @@ -1034,6 +1034,11 @@ static void render_result_exr_file_cache_path(Scene *sce, root = root_buf; } + /* FIXME: MAX_ID_NAME & FILE_MAXFILE + * + * If #filename is already long (it is initialized from the blend-file name itself), adding the + * scene name can cause the file name to be truncated. + */ SNPRINTF(filename_full, "cached_RR_%s_%s_%s.exr", filename, sce->id.name + 2, path_hexdigest); BLI_path_join(r_path, FILE_CACHE_MAX, root, filename_full); diff --git a/tests/files/io_tests/fbx/max2025-longnames.fbx b/tests/files/io_tests/fbx/max2025-longnames.fbx index 7e82c836dfc..d7930d34da4 100644 --- a/tests/files/io_tests/fbx/max2025-longnames.fbx +++ b/tests/files/io_tests/fbx/max2025-longnames.fbx @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8ac81b86b89910406e919dc51fe77d44cf27e0aa581695c8a3268f14b219caf0 -size 74896 +oid sha256:971ef1c87a73a6abceff2aff78731d75bc91b0e96cb9fe22f3925dcf0fb31975 +size 71452 diff --git a/tests/files/io_tests/fbx/reference/max2025-longnames.txt b/tests/files/io_tests/fbx/reference/max2025-longnames.txt index a9e0d7121ac..4b378f13b9f 100644 --- a/tests/files/io_tests/fbx/reference/max2025-longnames.txt +++ b/tests/files/io_tests/fbx/reference/max2025-longnames.txt @@ -135,7 +135,7 @@ -0.210 0.000 0.978 0.000 - props: int:MaxHandle=3 - anim act:Take 001 slot:OBArmature blend:REPLACE drivers:0 -- Obj 'Box_With_A_Long_Name_To_Test_Importer_Handling_Of_Names_That_A' MESH data:'Mesh.002' par:'Armature' +- Obj 'Box_With_A_Long_Name_To_Test_Importer_Handling_Of_Names_That_Are_Too_Long_To_Fit_Box_With_A_Long_Name_To_Test_Importer_Handling_Of_Names_That_Are_Too_Long_To_Fit_Box_With_A_Long_Name_To_Test_Importer_Handling_Of_Names_That_Are_Too_Long_To_Fit_Box_With_A_' MESH data:'Mesh.002' par:'Armature' - pos 0.679, 0.000, 15.811 - rot -1.571, 0.000, 0.000 (XYZ) - scl 1.000, 1.000, 1.000 @@ -144,7 +144,7 @@ - 1 modifiers - ARMATURE 'Armature' - props: int:MaxHandle=10 -- Obj 'Box_With_A_Long_Name_To_Test_Importer_Handling_Of_Names_That_Ar' MESH data:'Mesh' par:'Armature' +- Obj 'Box_With_A_Long_Name_To_Test_Importer_Handling_Of_Names_That_Are_Too_Long_To_Fit_Box_With_A_Long_Name_To_Test_Importer_Handling_Of_Names_That_Are_Too_Long_To_Fit_Box_With_A_Long_Name_To_Test_Importer_Handling_Of_Names_That_Are_Too_Long_To_Fit_Box_With_A_L' MESH data:'Mesh' par:'Armature' - pos 0.679, 0.000, -0.945 - rot -1.571, 0.000, 0.000 (XYZ) - scl 1.000, 1.000, 1.000 @@ -153,17 +153,17 @@ - 1 modifiers - ARMATURE 'Armature' - props: int:MaxHandle=2 -- Obj 'Box_Yellow_That_Is_Animated_And_Also_With_A_Long_Name_Let_Us_Se' MESH data:'Mesh.003' +- Obj 'Box_Yellow_That_Is_Animated_And_Also_With_A_Long_Name_Let_Us_See_What_Happens_Here_Box_Yellow_That_Is_Animated_And_Also_With_A_Long_Name_Let_Us_See_What_Happens_Here_Box_Yellow_That_Is_Animated_And_Also_With_A_Long_Name_Let_Us_See_What_Happens_Here_Box_Ye' MESH data:'Mesh.003' - pos -0.261, -0.829, 0.000 - rot 0.000, 0.000, 0.000 (XYZ) - scl 0.025, 0.025, 0.025 - - anim act:Take 001 slot:OBBox_Yellow_That_Is_Animated_And_Also_With_A_Long_Name_Let_Us_Se blend:REPLACE drivers:0 + - anim act:Take 001 slot:OBBox_Yellow_That_Is_Animated_And_Also_With_A_Long_Name_Let_Us_See_What_Happens_Here_Box_Yellow_That_Is_Animated_And_Also_With_A_Long_Name_Let_Us_See_What_Happens_Here_Box_Yellow_That_Is_Animated_And_Also_With_A_Long_Name_Let_Us_See_What_Happens_Here_Box_Ye blend:REPLACE drivers:0 - props: int:MaxHandle=14 -- Obj 'Point_Light_Object_Color_Blue_Light_Color_Animated_With_A_Long_' LIGHT data:'Light' +- Obj 'Point_Light_Object_Color_Blue_Light_Color_Animated_With_A_Long_Name_Here_Point_Light_Object_Color_Blue_Light_Color_Animated_With_A_Long_Name_Here_Point_Light_Object_Color_Blue_Light_Color_Animated_With_A_Long_Name_Here_Point_Light_Object_Color_Blue_Light_' LIGHT data:'Light' - pos 0.567, -0.741, 0.000 - rot 0.000, 0.000, 0.000 (XYZ) - scl 0.025, 0.025, 0.025 - - anim act:Take 001 slot:OBPoint_Light_Object_Color_Blue_Light_Color_Animated_With_A_Long_ blend:REPLACE drivers:0 + - anim act:Take 001 slot:OBPoint_Light_Object_Color_Blue_Light_Color_Animated_With_A_Long_Name_Here_Point_Light_Object_Color_Blue_Light_Color_Animated_With_A_Long_Name_Here_Point_Light_Object_Color_Blue_Light_Color_Animated_With_A_Long_Name_Here_Point_Light_Object_Color_Blue_Light_ blend:REPLACE drivers:0 - props: int:MaxHandle=15 - Obj 'Sphere_Parented_To_Bone' MESH data:'Mesh.001' par:'Armature' par_type:BONE par_bone:'Likewise_Here_Is_A_Bone_With_A_Long_Name_To_See_What_Happen.002' - pos 6.099, -21.143, 2.790 @@ -224,7 +224,7 @@ - fcu 'pose.bones["Likewise_Here_Is_A_Bone_With_A_Long_Name_To_See_What_Happen.003"].rotation_quaternion[1]' smooth:CONT_ACCEL extra:CONSTANT keyframes:2 grp:'Likewise_Here_Is_A_Bone_With_A_Long_Name_To_See_What_Happen.003' - (1.000, 0.000) lh:(-0.667, 0.000 AUTO_CLAMPED) rh:(2.667, 0.000 AUTO_CLAMPED) - (6.000, 0.000) lh:(4.333, 0.000 AUTO_CLAMPED) rh:(7.667, 0.000 AUTO_CLAMPED) - - Channelbag slot 'OBBox_Yellow_That_Is_Animated_And_Also_With_A_Long_Name_Let_Us_Se' curves:9 + - Channelbag slot 'OBBox_Yellow_That_Is_Animated_And_Also_With_A_Long_Name_Let_Us_See_What_Happens_Here_Box_Yellow_That_Is_Animated_And_Also_With_A_Long_Name_Let_Us_See_What_Happens_Here_Box_Yellow_That_Is_Animated_And_Also_With_A_Long_Name_Let_Us_See_What_Happens_Here_Box_Ye' curves:9 - fcu 'location[0]' smooth:CONT_ACCEL extra:CONSTANT keyframes:2 grp:'Box_Yellow_That_Is_Animated_And_Also_With_A_Long_Name_Let_Us_Se' - (1.000, -0.261) lh:(0.000, -0.261 AUTO_CLAMPED) rh:(2.000, -0.261 AUTO_CLAMPED) - (4.000, 0.211) lh:(3.000, 0.211 AUTO_CLAMPED) rh:(5.000, 0.211 AUTO_CLAMPED) @@ -252,7 +252,7 @@ - fcu 'scale[2]' smooth:CONT_ACCEL extra:CONSTANT keyframes:2 grp:'Box_Yellow_That_Is_Animated_And_Also_With_A_Long_Name_Let_Us_Se' - (1.000, 0.025) lh:(0.000, 0.025 AUTO_CLAMPED) rh:(2.000, 0.025 AUTO_CLAMPED) - (4.000, 0.025) lh:(3.000, 0.025 AUTO_CLAMPED) rh:(5.000, 0.025 AUTO_CLAMPED) - - Channelbag slot 'OBPoint_Light_Object_Color_Blue_Light_Color_Animated_With_A_Long_' curves:9 + - Channelbag slot 'OBPoint_Light_Object_Color_Blue_Light_Color_Animated_With_A_Long_Name_Here_Point_Light_Object_Color_Blue_Light_Color_Animated_With_A_Long_Name_Here_Point_Light_Object_Color_Blue_Light_Color_Animated_With_A_Long_Name_Here_Point_Light_Object_Color_Blue_Light_' curves:9 - fcu 'location[0]' smooth:CONT_ACCEL extra:CONSTANT keyframes:2 grp:'Point_Light_Object_Color_Blue_Light_Color_Animated_With_A_Long_' - (1.000, 0.567) lh:(-0.667, 0.567 AUTO_CLAMPED) rh:(2.667, 0.567 AUTO_CLAMPED) - (6.000, 1.148) lh:(4.333, 1.148 AUTO_CLAMPED) rh:(7.667, 1.148 AUTO_CLAMPED) diff --git a/tests/files/io_tests/obj/invalid_syntax.obj b/tests/files/io_tests/obj/invalid_syntax.obj index 8b70f6b5586..d6cdb2b89e0 100644 --- a/tests/files/io_tests/obj/invalid_syntax.obj +++ b/tests/files/io_tests/obj/invalid_syntax.obj @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:556b5e37a5e2f3c81e7ec846ab33a639d18cde361d21a16183188c1dd4f347fe -size 762 +oid sha256:37d58400e2e8259deeaa95dc0dad5c9f99bf3a01deeb705f362649bd9193ac33 +size 1020 diff --git a/tests/files/io_tests/obj/reference/invalid_syntax.txt b/tests/files/io_tests/obj/reference/invalid_syntax.txt index e8a114baa6c..e6c5dbc4303 100644 --- a/tests/files/io_tests/obj/reference/invalid_syntax.txt +++ b/tests/files/io_tests/obj/reference/invalid_syntax.txt @@ -1,5 +1,5 @@ ==== Meshes: 1 -- Mesh 'ObjectWithAReallyLongNameToCheckHowImportHandlesNamesThatAreLon' vtx:3 face:1 loop:3 edge:3 +- Mesh 'ObjectWithAReallyLongNameToCheckHowImportHandlesNamesThatAreLongerThanBlenderCanHandleObjectWithAReallyLongNameToCheckHowImportHandlesNamesThatAreLongerThanBlenderCanHandleObjectWithAReallyLongNameToCheckHowImportHandlesNamesThatAreLongerThanBlenderCanHan' vtx:3 face:1 loop:3 edge:3 - 0 1 2 - 0/2 0/1 1/2 - attr 'position' FLOAT_VECTOR POINT @@ -22,7 +22,7 @@ - (1.000, 0.750) ==== Objects: 1 -- Obj 'ObjectWithAReallyLongNameToCheckHowImportHandlesNamesThatAreLon' MESH data:'ObjectWithAReallyLongNameToCheckHowImportHandlesNamesThatAreLon' +- Obj 'ObjectWithAReallyLongNameToCheckHowImportHandlesNamesThatAreLongerThanBlenderCanHandleObjectWithAReallyLongNameToCheckHowImportHandlesNamesThatAreLongerThanBlenderCanHandleObjectWithAReallyLongNameToCheckHowImportHandlesNamesThatAreLongerThanBlenderCanHan' MESH data:'ObjectWithAReallyLongNameToCheckHowImportHandlesNamesThatAreLongerThanBlenderCanHandleObjectWithAReallyLongNameToCheckHowImportHandlesNamesThatAreLongerThanBlenderCanHandleObjectWithAReallyLongNameToCheckHowImportHandlesNamesThatAreLongerThanBlenderCanHan' - pos 0.000, 0.000, 0.000 - rot 1.571, 0.000, 0.000 (XYZ) - scl 1.000, 1.000, 1.000 diff --git a/tests/python/bl_animation_action.py b/tests/python/bl_animation_action.py index 04b583e057d..51adfa21e37 100644 --- a/tests/python/bl_animation_action.py +++ b/tests/python/bl_animation_action.py @@ -68,24 +68,36 @@ class ActionSlotCreationTest(unittest.TestCase): self.action.slots.new('UNSPECIFIED', "Bob") def test_long_identifier(self): - # Test a 65-character identifier, using a 63-character name. This is the - # maximum length allowed (the DNA field is MAX_ID_NAME=66 long, which + # Test a 257-character identifier, using a 255-character name. This is the + # maximum length allowed (the DNA field is MAX_ID_NAME=258 long, which # includes the trailing zero byte). - long_but_ok_name = "This name is so long! It might look long, but it is just right!" + long_but_ok_name = ( + "This name is so long! It might look long, but it is just right! " + "This name is so long! It might look long, but it is just right! " + "This name is so long! It might look long, but it is just right! " + "This name is so long! It might look long, but it is just right!" + ) + assert (len(long_but_ok_name) == 255) slot_ok = self.action.slots.new('OBJECT', long_but_ok_name) self.assertEqual(long_but_ok_name, slot_ok.name_display, "this name should fit") self.assertEqual('OB' + long_but_ok_name, slot_ok.identifier, "this identifier should fit") # Test one character more. - too_long_name = "This name is so long! It might look long, and that it is indeed." - too_long_name_truncated = too_long_name[:63] + too_long_name = ( + "This name is so long! It might look long, and that it is indeed." + "This name is so long! It might look long, and that it is indeed." + "This name is so long! It might look long, and that it is indeed." + "This name is so long! It might look long, and that it is indeed." + ) + assert (len(too_long_name) == 256) + too_long_name_truncated = too_long_name[:255] slot_long = self.action.slots.new('OBJECT', too_long_name) self.assertEqual(too_long_name_truncated, slot_long.name_display, "this name should be truncated") self.assertEqual('OB' + too_long_name_truncated, slot_long.identifier, "this identifier should be truncated") # Test with different trailing character. - other_long_name = "This name is so long! It might look long, and that it is indeed!" - truncated_and_unique = other_long_name[:59] + ".001" + other_long_name = too_long_name[:-1] + "!" + truncated_and_unique = other_long_name[:251] + ".001" slot_long2 = self.action.slots.new('OBJECT', too_long_name) self.assertEqual(truncated_and_unique, slot_long2.name_display, "this name should be truncated and made unique")