From 4b4a261787ee815fbde96adfe04f3871d88acc16 Mon Sep 17 00:00:00 2001 From: TheLegendTubaGuy <95944177+thelegendtubaguy@users.noreply.github.com> Date: Sun, 4 Oct 2026 16:23:40 -0500 Subject: [PATCH] Fix small binary STLs failing to load as ASCII (#16130) --- deps_src/admesh/stlinit.cpp | 13 +++++++++++++ tests/libslic3r/test_stl.cpp | 25 +++++++++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/deps_src/admesh/stlinit.cpp b/deps_src/admesh/stlinit.cpp index 9d44cdf266..3b8f59866a 100644 --- a/deps_src/admesh/stlinit.cpp +++ b/deps_src/admesh/stlinit.cpp @@ -75,6 +75,19 @@ static FILE *stl_open_count_facets(stl_file *stl, const char *file, unsigned int break; } } + // Zero normals and coordinates like 10 or 15 have no byte above 127, so the test above can miss a binary file. + // Its size still matches its facet count; text read as that count would need a file of gigabytes. + if (stl->stats.type == ascii) { + uint32_t header_num_facets; + fseek(fp, custom_header_length, SEEK_SET); + if (fread(&header_num_facets, sizeof(uint32_t), 1, fp) == 1) { +#if BOOST_ENDIAN_BIG_BYTE + stl_internal_reverse_quads((char*)&header_num_facets, 4); +#endif /* BOOST_ENDIAN_BIG_BYTE */ + if (header_size + uint64_t(header_num_facets) * SIZEOF_STL_FACET == file_size) + stl->stats.type = binary; + } + } rewind(fp); uint32_t num_facets = 0; diff --git a/tests/libslic3r/test_stl.cpp b/tests/libslic3r/test_stl.cpp index 0223392c3f..b121bfc122 100644 --- a/tests/libslic3r/test_stl.cpp +++ b/tests/libslic3r/test_stl.cpp @@ -1,10 +1,13 @@ #include +#include #include #include "libslic3r/Point.hpp" #include #include "libslic3r/Model.hpp" #include "libslic3r/Format/STL.hpp" +#include "test_utils.hpp" +#include using namespace Slic3r; @@ -58,3 +61,25 @@ SCENARIO("Reading an STL file", "[stl]") { } } } + +TEST_CASE("A binary STL whose facet bytes never exceed 127 is read as binary", "[stl]") +{ + const indexed_triangle_set cube = its_make_cube(10., 10., 10.); + std::string stl(80, '\0'); + const auto append = [&stl](const auto &value) { stl.append(reinterpret_cast(&value), sizeof(value)); }; + append(uint32_t(cube.indices.size())); + const stl_normal zero_normal = stl_normal::Zero(); + for (const stl_triangle_vertex_indices &facet : cube.indices) { + append(zero_normal); + for (int i = 0; i < 3; ++i) + append(cube.vertices[facet[i]]); + append(uint16_t(0)); + } + REQUIRE(std::none_of(stl.begin() + 84, stl.begin() + 84 + 128, [](unsigned char c) { return c > 127; })); + + ScopedTemporaryFile file(".stl"); + boost::nowide::ofstream(file.string(), std::ios::binary) << stl; + Model model; + REQUIRE(load_stl(file.string().c_str(), &model)); + REQUIRE(is_approx(model.objects.front()->volumes.front()->mesh().size(), Vec3d(10, 10, 10))); +}