diff --git a/qbsp/writebsp.cc b/qbsp/writebsp.cc index 91da6ea7..59c9ed25 100644 --- a/qbsp/writebsp.cc +++ b/qbsp/writebsp.cc @@ -80,7 +80,19 @@ size_t ExportMapTexinfo(size_t texinfonum) dest.flags = src.flags; dest.miptex = src.miptex; dest.vecs = src.vecs; - strcpy(dest.texture.data(), map.texinfoTextureName(texinfonum).c_str()); + + const std::string &src_name = map.texinfoTextureName(texinfonum); + if (src_name.size() > (dest.texture.size() - 1)) { + logging::print("WARNING: texture name '{}' exceeds maximum length {} and will be truncated\n", + src_name, dest.texture.size() - 1); + } + for (size_t i = 0; i < (dest.texture.size() - 1); ++i) { + if (i < src_name.size()) + dest.texture[i] = src_name[i]; + else + dest.texture[i] = '\0'; + } + dest.texture[dest.texture.size() - 1] = '\0'; dest.value = map.miptex[src.miptex].value; src.outputnum = i; diff --git a/testmaps/q2_long_texture_name.map b/testmaps/q2_long_texture_name.map new file mode 100644 index 00000000..7ba4cad4 --- /dev/null +++ b/testmaps/q2_long_texture_name.map @@ -0,0 +1,22 @@ +// Game: Quake 2 +// Format: Quake2 +// entity 0 +{ +"classname" "worldspawn" +"_tb_mod" "q2_wal_metadata" +"_tb_textures" "textures/long_folder_name_test" +// brush 0 +{ +( -64 -64 -16 ) ( -64 -63 -16 ) ( -64 -64 -15 ) long_folder_name_test/long_texture_name_test 0 0 0 1 1 +( -64 -64 -16 ) ( -64 -64 -15 ) ( -63 -64 -16 ) long_folder_name_test/long_texture_name_test 0 0 0 1 1 +( -64 -64 -16 ) ( -63 -64 -16 ) ( -64 -63 -16 ) long_folder_name_test/long_texture_name_test 0 0 0 1 1 +( 64 64 16 ) ( 64 65 16 ) ( 65 64 16 ) long_folder_name_test/long_texture_name_test 0 0 0 1 1 +( 64 64 16 ) ( 65 64 16 ) ( 64 64 17 ) long_folder_name_test/long_texture_name_test 0 0 0 1 1 +( 64 64 16 ) ( 64 64 17 ) ( 64 65 16 ) long_folder_name_test/long_texture_name_test 0 0 0 1 1 +} +} +// entity 1 +{ +"classname" "info_player_start" +"origin" "-32 0 40" +} diff --git a/testmaps/q2_wal_metadata/textures/long_folder_name_test/long_texture_name_test.wal b/testmaps/q2_wal_metadata/textures/long_folder_name_test/long_texture_name_test.wal new file mode 100644 index 00000000..9d4c88ab Binary files /dev/null and b/testmaps/q2_wal_metadata/textures/long_folder_name_test/long_texture_name_test.wal differ diff --git a/tests/test_qbsp_q2.cc b/tests/test_qbsp_q2.cc index d082ea95..350f05a2 100644 --- a/tests/test_qbsp_q2.cc +++ b/tests/test_qbsp_q2.cc @@ -268,9 +268,25 @@ TEST_CASE("nodraw_light" * doctest::test_suite("testmaps_q2")) CHECK(texinfo->flags.native == (Q2_SURF_LIGHT | Q2_SURF_NODRAW)); } -TEST_CASE("nodraw_detail_light" * doctest::test_suite("testmaps_q2")) +TEST_CASE("q2_long_texture_name" * doctest::test_suite("testmaps_q2")) { - const auto [bsp, bspx, prt] = LoadTestmapQ2("q2_nodraw_detail_light.map", {"-includeskip"}); + const auto [bsp, bspx, prt] = LoadTestmapQ2("q2_long_texture_name.map"); + + CHECK(GAME_QUAKE_II == bsp.loadversion->game->id); + + auto *topface = BSP_FindFaceAtPoint(&bsp, &bsp.dmodels[0], {0, 0, 16}, {0, 0, 1}); + REQUIRE(nullptr != topface); + + // this won't work in game, but we're mostly checking for lack of memory corruption + // (a warning is issued) + auto *texinfo = Face_Texinfo(&bsp, topface); + CHECK(std::string(texinfo->texture.data()) == "long_folder_name_test/long_text"); + CHECK(texinfo->nexttexinfo == -1); +} + +TEST_CASE("nodraw_light" * doctest::test_suite("testmaps_q2")) +{ + const auto [bsp, bspx, prt] = LoadTestmapQ2("q2_nodraw_light.map", {"-includeskip"}); CHECK(GAME_QUAKE_II == bsp.loadversion->game->id);