diff --git a/src/libslic3r/TriangleMeshSlicer.cpp b/src/libslic3r/TriangleMeshSlicer.cpp index ea9eb5ff2..a3123ea76 100644 --- a/src/libslic3r/TriangleMeshSlicer.cpp +++ b/src/libslic3r/TriangleMeshSlicer.cpp @@ -23,6 +23,8 @@ #endif #include +#include +#include #if defined(SLIC3R_DEBUG) || defined(SLIC3R_DEBUG_SLICE_PROCESSING) #include "SVG.hpp" diff --git a/src/miniz/miniz.c b/src/miniz/miniz.c index 08126f441..cff9aa5d3 100644 --- a/src/miniz/miniz.c +++ b/src/miniz/miniz.c @@ -5953,17 +5953,16 @@ static mz_uint32 mz_zip_writer_create_zip64_extra_data(mz_uint8 *pBuf, mz_uint64 static mz_bool mz_zip_writer_create_local_dir_header(mz_zip_archive *pZip, mz_uint8 *pDst, mz_uint16 filename_size, mz_uint16 extra_size, mz_uint64 uncomp_size, mz_uint64 comp_size, mz_uint32 uncomp_crc32, mz_uint16 method, mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date) { - (void)pZip; memset(pDst, 0, MZ_ZIP_LOCAL_DIR_HEADER_SIZE); MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_SIG_OFS, MZ_ZIP_LOCAL_DIR_HEADER_SIG); - MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_VERSION_NEEDED_OFS, method ? 20 : 0); + MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_VERSION_NEEDED_OFS, (pZip->m_pState->m_zip64) ? 0x002D : (method ? 0x0014 : 0x0000)); MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_BIT_FLAG_OFS, bit_flags); MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_METHOD_OFS, method); MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILE_TIME_OFS, dos_time); MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILE_DATE_OFS, dos_date); MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_CRC32_OFS, uncomp_crc32); - MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_COMPRESSED_SIZE_OFS, MZ_MIN(comp_size, MZ_UINT32_MAX)); - MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS, MZ_MIN(uncomp_size, MZ_UINT32_MAX)); + MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_COMPRESSED_SIZE_OFS, (pZip->m_pState->m_zip64 || comp_size > MZ_UINT32_MAX) ? MZ_UINT32_MAX : comp_size); + MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS, (pZip->m_pState->m_zip64 || uncomp_size > MZ_UINT32_MAX) ? MZ_UINT32_MAX : uncomp_size); MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILENAME_LEN_OFS, filename_size); MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_EXTRA_LEN_OFS, extra_size); return MZ_TRUE; @@ -5975,10 +5974,12 @@ static mz_bool mz_zip_writer_create_central_dir_header(mz_zip_archive *pZip, mz_ mz_uint16 method, mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date, mz_uint64 local_header_ofs, mz_uint32 ext_attributes) { - (void)pZip; + mz_zip_internal_state *pState = pZip->m_pState; + mz_bool is_zip64_needed = uncomp_size >= MZ_UINT32_MAX || comp_size >= MZ_UINT32_MAX; memset(pDst, 0, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE); MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_SIG_OFS, MZ_ZIP_CENTRAL_DIR_HEADER_SIG); - MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_VERSION_NEEDED_OFS, method ? 20 : 0); + MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_VERSION_MADE_BY_OFS, is_zip64_needed ? 0x002D : (method ? 0x0014 : 0x0000)); + MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_VERSION_NEEDED_OFS, is_zip64_needed ? 0x002D : (method ? 0x0014 : 0x0000)); MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_BIT_FLAG_OFS, bit_flags); MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_METHOD_OFS, method); MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILE_TIME_OFS, dos_time); @@ -6675,6 +6676,15 @@ mz_bool mz_zip_writer_add_read_buf_callback(mz_zip_archive *pZip, const char *pA return MZ_TRUE; } +static mz_uint32 mz_zip_writer_preallocate_extra_data(mz_uint8 *pBuf, mz_uint32 extra_data_size) +{ + mz_uint8 *pDst = pBuf; + MZ_WRITE_LE16(pDst + 0, 0x9999); + MZ_WRITE_LE16(pDst + 2, extra_data_size); + memset(pDst + 4, 0, extra_data_size); + return 2 * sizeof(mz_uint16) + extra_data_size; +} + mz_bool mz_zip_writer_add_staged_open(mz_zip_archive* pZip, mz_zip_writer_staged_context* pContext, const char* pArchive_name, mz_uint64 max_size, const MZ_TIME_T* pFile_time, const void* pComment, mz_uint16 comment_size, mz_uint level_and_flags, const char* user_extra_data, mz_uint user_extra_data_len, const char* user_extra_data_central, mz_uint user_extra_data_central_len) { @@ -6708,13 +6718,6 @@ mz_bool mz_zip_writer_add_staged_open(mz_zip_archive* pZip, mz_zip_writer_staged pState = pZip->m_pState; - if ((!pState->m_zip64) && (max_size > MZ_UINT32_MAX)) - { - /* Source file is too large for non-zip64 */ - /*return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); */ - pState->m_zip64 = MZ_TRUE; - } - /* We could support this, but why? */ if (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); @@ -6778,55 +6781,45 @@ mz_bool mz_zip_writer_add_staged_open(mz_zip_archive* pZip, mz_zip_writer_staged MZ_ASSERT((pContext->cur_archive_file_ofs & (pZip->m_file_offset_alignment - 1)) == 0); } + if (!pState->m_zip64 && (pContext->local_dir_header_ofs >= MZ_UINT32_MAX)) { + pState->m_zip64 = MZ_TRUE; + /*return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); */ + } + MZ_CLEAR_OBJ(local_dir_header); if (pState->m_zip64) { - if (max_size >= MZ_UINT32_MAX || pContext->local_dir_header_ofs >= MZ_UINT32_MAX) - { - pContext->pExtra_data = pContext->extra_data; - pContext->extra_size = mz_zip_writer_create_zip64_extra_data(pContext->extra_data, (max_size >= MZ_UINT32_MAX) ? &pContext->uncomp_size : NULL, - (max_size >= MZ_UINT32_MAX) ? &pContext->comp_size : NULL, (pContext->local_dir_header_ofs >= MZ_UINT32_MAX) ? &pContext->local_dir_header_ofs : NULL); - } + pContext->pExtra_data = pContext->extra_data; + pContext->extra_size = mz_zip_writer_create_zip64_extra_data(pContext->extra_data, &pContext->uncomp_size, &pContext->comp_size, + (pContext->local_dir_header_ofs >= MZ_UINT32_MAX) ? &pContext->local_dir_header_ofs : NULL); + } + else if (!pState->m_zip64 && max_size > MZ_UINT32_MAX) + { + pContext->pExtra_data = pContext->extra_data; + pContext->extra_size = mz_zip_writer_preallocate_extra_data(pContext->extra_data, 2 * sizeof(mz_uint64)); + } - if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)pContext->archive_name_size, (mz_uint16)(pContext->extra_size + user_extra_data_len), 0, 0, 0, pContext->method, pContext->gen_flags, pContext->dos_time, pContext->dos_date)) - return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); + if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)pContext->archive_name_size, (mz_uint16)(pContext->extra_size + user_extra_data_len), 0, 0, 0, pContext->method, pContext->gen_flags, pContext->dos_time, pContext->dos_date)) + return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); - if (pZip->m_pWrite(pZip->m_pIO_opaque, pContext->cur_archive_file_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header)) - return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + if (pZip->m_pWrite(pZip->m_pIO_opaque, pContext->cur_archive_file_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header)) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); - pContext->cur_archive_file_ofs += sizeof(local_dir_header); + pContext->cur_archive_file_ofs += sizeof(local_dir_header); - if (pZip->m_pWrite(pZip->m_pIO_opaque, pContext->cur_archive_file_ofs, pArchive_name, pContext->archive_name_size) != pContext->archive_name_size) - { - return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); - } + if (pZip->m_pWrite(pZip->m_pIO_opaque, pContext->cur_archive_file_ofs, pArchive_name, pContext->archive_name_size) != pContext->archive_name_size) + { + return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + } - pContext->cur_archive_file_ofs += pContext->archive_name_size; + pContext->cur_archive_file_ofs += pContext->archive_name_size; + if (pState->m_zip64 || max_size >= MZ_UINT32_MAX) { if (pZip->m_pWrite(pZip->m_pIO_opaque, pContext->cur_archive_file_ofs, pContext->extra_data, pContext->extra_size) != pContext->extra_size) return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); pContext->cur_archive_file_ofs += pContext->extra_size; } - else - { - if ((pContext->comp_size > MZ_UINT32_MAX) || (pContext->cur_archive_file_ofs > MZ_UINT32_MAX)) - return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); - if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)pContext->archive_name_size, (mz_uint16)user_extra_data_len, 0, 0, 0, pContext->method, pContext->gen_flags, pContext->dos_time, pContext->dos_date)) - return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); - - if (pZip->m_pWrite(pZip->m_pIO_opaque, pContext->cur_archive_file_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header)) - return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); - - pContext->cur_archive_file_ofs += sizeof(local_dir_header); - - if (pZip->m_pWrite(pZip->m_pIO_opaque, pContext->cur_archive_file_ofs, pArchive_name, pContext->archive_name_size) != pContext->archive_name_size) - { - return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); - } - - pContext->cur_archive_file_ofs += pContext->archive_name_size; - } if (user_extra_data_len > 0) { @@ -6898,17 +6891,40 @@ mz_bool mz_zip_writer_add_staged_finish(mz_zip_writer_staged_context *pContext) pContext->pZip->m_pFree(pContext->pZip->m_pAlloc_opaque, pContext->pCompressor); pContext->pCompressor = NULL; + // Rewrite preallocated phony custom block in local dir header by ZIP64 extension. Also, other values are adjusted in the header. + if (pContext->file_ofs >= MZ_UINT32_MAX || pContext->add_state.m_comp_size >= MZ_UINT32_MAX) { + mz_uint64 local_dir_header_ofs = pContext->local_dir_header_ofs; + pContext->pExtra_data = pContext->extra_data; + pContext->extra_size = mz_zip_writer_create_zip64_extra_data(pContext->extra_data, &pContext->uncomp_size, &pContext->comp_size, (pContext->local_dir_header_ofs >= MZ_UINT32_MAX) ? &pContext->local_dir_header_ofs : NULL); + + mz_uint8 min_version[2] = {0x2D, 0x00}; + mz_uint8 comp_uncomp_size[4] = {0xFF, 0xFF, 0xFF, 0xFF}; + if (pContext->pZip->m_pWrite(pContext->pZip->m_pIO_opaque, local_dir_header_ofs + MZ_ZIP_LDH_VERSION_NEEDED_OFS, min_version, sizeof(min_version)) != sizeof(min_version)) + return mz_zip_set_error(pContext->pZip, MZ_ZIP_FILE_WRITE_FAILED); + if (pContext->pZip->m_pWrite(pContext->pZip->m_pIO_opaque, local_dir_header_ofs + MZ_ZIP_LDH_COMPRESSED_SIZE_OFS, comp_uncomp_size, sizeof(comp_uncomp_size)) != sizeof(comp_uncomp_size)) + return mz_zip_set_error(pContext->pZip, MZ_ZIP_FILE_WRITE_FAILED); + if (pContext->pZip->m_pWrite(pContext->pZip->m_pIO_opaque, local_dir_header_ofs + MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS, comp_uncomp_size, sizeof(comp_uncomp_size)) != sizeof(comp_uncomp_size)) + return mz_zip_set_error(pContext->pZip, MZ_ZIP_FILE_WRITE_FAILED); + if (pContext->pZip->m_pWrite(pContext->pZip->m_pIO_opaque, local_dir_header_ofs + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + pContext->archive_name_size, pContext->extra_data, pContext->extra_size) != pContext->extra_size) + return mz_zip_set_error(pContext->pZip, MZ_ZIP_FILE_WRITE_FAILED); + } + pContext->uncomp_size = pContext->file_ofs; pContext->comp_size = pContext->add_state.m_comp_size; pContext->cur_archive_file_ofs = pContext->add_state.m_cur_archive_file_ofs; + // Clean pContext->pExtra_data, pContext->extra_data and pContext->extra_size after calling mz_zip_writer_add_staged_open + pContext->pExtra_data = NULL; + pContext->extra_size = 0; + memset(pContext->extra_data, 0, sizeof(mz_uint8) * MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE); + { mz_uint8 local_dir_footer[MZ_ZIP_DATA_DESCRIPTER_SIZE64]; mz_uint32 local_dir_footer_size = MZ_ZIP_DATA_DESCRIPTER_SIZE32; MZ_WRITE_LE32(local_dir_footer + 0, MZ_ZIP_DATA_DESCRIPTOR_ID); MZ_WRITE_LE32(local_dir_footer + 4, pContext->uncomp_crc32); - if (pContext->pExtra_data == NULL) + if (pContext->uncomp_size < MZ_UINT32_MAX && pContext->comp_size < MZ_UINT32_MAX) { if (pContext->comp_size > MZ_UINT32_MAX) return mz_zip_set_error(pContext->pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); @@ -6929,10 +6945,11 @@ mz_bool mz_zip_writer_add_staged_finish(mz_zip_writer_staged_context *pContext) pContext->cur_archive_file_ofs += local_dir_footer_size; } - if (pContext->pExtra_data != NULL) + if (pContext->file_ofs >= MZ_UINT32_MAX || pContext->add_state.m_comp_size >= MZ_UINT32_MAX) { + pContext->pExtra_data = pContext->extra_data; pContext->extra_size = mz_zip_writer_create_zip64_extra_data(pContext->extra_data, (pContext->uncomp_size >= MZ_UINT32_MAX) ? &pContext->uncomp_size : NULL, - (pContext->uncomp_size >= MZ_UINT32_MAX) ? &pContext->comp_size : NULL, (pContext->local_dir_header_ofs >= MZ_UINT32_MAX) ? &pContext->local_dir_header_ofs : NULL); + (pContext->comp_size >= MZ_UINT32_MAX) ? &pContext->comp_size : NULL, (pContext->local_dir_header_ofs >= MZ_UINT32_MAX) ? &pContext->local_dir_header_ofs : NULL); } if (!mz_zip_writer_add_to_central_dir(pContext->pZip, pContext->pArchive_name, (mz_uint16)pContext->archive_name_size, pContext->pExtra_data, (mz_uint16)pContext->extra_size, pContext->pComment, pContext->comment_size, diff --git a/tests/libslic3r/test_3mf.cpp b/tests/libslic3r/test_3mf.cpp index d6d3686d9..e865b1d78 100644 --- a/tests/libslic3r/test_3mf.cpp +++ b/tests/libslic3r/test_3mf.cpp @@ -30,23 +30,23 @@ SCENARIO("Export+Import geometry to/from 3mf file cycle", "[3mf]") { load_stl(src_file.c_str(), &src_model); src_model.add_default_instances(); - ModelObject* src_object = src_model.objects[0]; + ModelObject* src_object = src_model.objects.front(); // apply generic transformation to the 1st volume Geometry::Transformation src_volume_transform; - src_volume_transform.set_offset(Vec3d(10.0, 20.0, 0.0)); - src_volume_transform.set_rotation(Vec3d(Geometry::deg2rad(25.0), Geometry::deg2rad(35.0), Geometry::deg2rad(45.0))); - src_volume_transform.set_scaling_factor(Vec3d(1.1, 1.2, 1.3)); - src_volume_transform.set_mirror(Vec3d(-1.0, 1.0, -1.0)); - src_object->volumes[0]->set_transformation(src_volume_transform); + src_volume_transform.set_offset({ 10.0, 20.0, 0.0 }); + src_volume_transform.set_rotation({ Geometry::deg2rad(25.0), Geometry::deg2rad(35.0), Geometry::deg2rad(45.0) }); + src_volume_transform.set_scaling_factor({ 1.1, 1.2, 1.3 }); + src_volume_transform.set_mirror({ -1.0, 1.0, -1.0 }); + src_object->volumes.front()->set_transformation(src_volume_transform); // apply generic transformation to the 1st instance Geometry::Transformation src_instance_transform; - src_instance_transform.set_offset(Vec3d(5.0, 10.0, 0.0)); - src_instance_transform.set_rotation(Vec3d(Geometry::deg2rad(12.0), Geometry::deg2rad(13.0), Geometry::deg2rad(14.0))); - src_instance_transform.set_scaling_factor(Vec3d(0.9, 0.8, 0.7)); - src_instance_transform.set_mirror(Vec3d(1.0, -1.0, -1.0)); - src_object->instances[0]->set_transformation(src_instance_transform); + src_instance_transform.set_offset({ 5.0, 10.0, 0.0 }); + src_instance_transform.set_rotation({ Geometry::deg2rad(12.0), Geometry::deg2rad(13.0), Geometry::deg2rad(14.0) }); + src_instance_transform.set_scaling_factor({ 0.9, 0.8, 0.7 }); + src_instance_transform.set_mirror({ 1.0, -1.0, -1.0 }); + src_object->instances.front()->set_transformation(src_instance_transform); WHEN("model is saved+loaded to/from 3mf file") { // save the model to 3mf file @@ -67,16 +67,9 @@ SCENARIO("Export+Import geometry to/from 3mf file cycle", "[3mf]") { dst_mesh.repair(); bool res = src_mesh.its.vertices.size() == dst_mesh.its.vertices.size(); - if (res) - { - for (size_t i = 0; i < dst_mesh.its.vertices.size(); ++i) - { + if (res) { + for (size_t i = 0; i < dst_mesh.its.vertices.size(); ++i) { res &= dst_mesh.its.vertices[i].isApprox(src_mesh.its.vertices[i]); - if (!res) - { - Vec3f diff = dst_mesh.its.vertices[i] - src_mesh.its.vertices[i]; - std::cout << i << ": diff " << to_string((Vec3d)diff.cast()) << "\n"; - } } } THEN("world vertices coordinates after load match") { @@ -95,11 +88,11 @@ SCENARIO("2D convex hull of sinking object", "[3mf]") { model.add_default_instances(); WHEN("model is rotated, scaled and set as sinking") { - ModelObject* object = model.objects[0]; + ModelObject* object = model.objects.front(); object->center_around_origin(false); // set instance's attitude so that it is rotated, scaled and sinking - ModelInstance* instance = object->instances[0]; + ModelInstance* instance = object->instances.front(); instance->set_rotation(Y, -M_PI / 4.0); instance->set_offset(Vec3d::Zero()); instance->set_scaling_factor({ 2.0, 2.0, 2.0 }); @@ -116,8 +109,15 @@ SCENARIO("2D convex hull of sinking object", "[3mf]") { { -4244, 19502998 }, { -4242640, -8537523 } }; + bool res = hull_2d.points == result; + std::cout << "hull_2d vertices count: " << hull_2d.points.size() << "\n"; + std::cout << "hull_2d vertices:\n"; + for (size_t i = 0; i < hull_2d.points.size(); ++i) { + std::cout << hull_2d.points[i].x() << ", " << hull_2d.points[i].y() << "\n"; + } + THEN("2D convex hull should match with reference") { REQUIRE(res); }