react-native-nitro-xlsx 0.2.5 → 0.2.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/NitroXlsx.podspec +26 -27
- package/Package.swift +31 -10
- package/README.md +21 -9
- package/android/CMakeLists.txt +20 -27
- package/cpp/HybridNitroXlsx.cpp +25 -1
- package/cpp/HybridXlsxCellFormat.cpp +46 -146
- package/cpp/HybridXlsxCellFormat.hpp +9 -41
- package/cpp/HybridXlsxConditionalFormat.cpp +4 -1
- package/cpp/HybridXlsxConditionalFormats.cpp +5 -1
- package/cpp/HybridXlsxWorkbook.cpp +38 -8
- package/cpp/HybridXlsxWorkbook.hpp +10 -1
- package/cpp/HybridXlsxWorksheet.cpp +422 -141
- package/cpp/HybridXlsxWorksheet.hpp +4 -1
- package/cpp/XlsxCacheDir.cpp +25 -2
- package/cpp/XlsxCacheDir.hpp +3 -1
- package/cpp/XlsxCellStyle.hpp +360 -0
- package/cpp/XlsxJson.cpp +29 -8
- package/package.json +2 -2
- package/scripts/run-cpp-tests.sh +1 -1
- package/scripts/sync-openxlsx-headers.sh +34 -0
- package/src/__mocks__/react-native-nitro-modules.ts +523 -20
- package/src/__tests__/index.test.ts +124 -16
- package/src/index.ts +13 -13
- package/thirdparty/OpenXLSX/.clang-format +118 -0
- package/thirdparty/OpenXLSX/.clang-tidy +28 -0
- package/thirdparty/OpenXLSX/.gitignore +130 -0
- package/thirdparty/OpenXLSX/Benchmarks/2024-07-29-benchmarks_before_XMLNode_wrappers +46 -0
- package/thirdparty/OpenXLSX/Benchmarks/2024-07-29-benchmarks_with_XMLNode_wrappers_and_namespace_and_stripping +49 -0
- package/thirdparty/OpenXLSX/Benchmarks/2024-07-29-benchmarks_with_XMLNode_wrappers_and_namespace_char_support +49 -0
- package/thirdparty/OpenXLSX/Benchmarks/2024-07-29-benchmarks_with_XMLNode_wrappers_and_namespace_support +49 -0
- package/thirdparty/OpenXLSX/Benchmarks/2024-07-29-benchmarks_with_XMLNode_wrappers_and_namespaced_name_disabled +49 -0
- package/thirdparty/OpenXLSX/Benchmarks/2024-08-11-benchmarks_post-XLCellIterator-Rework +46 -0
- package/thirdparty/OpenXLSX/Benchmarks/2024-08-14-benchmarks_post-default-row-column-style-support +46 -0
- package/thirdparty/OpenXLSX/Benchmarks/2024-09-02-benchmarks +46 -0
- package/thirdparty/OpenXLSX/Benchmarks/2024-12-19-benchmarks +46 -0
- package/thirdparty/OpenXLSX/Benchmarks/2024-12-30-benchmarks-post-XLSharedStrings-by-ref +46 -0
- package/thirdparty/OpenXLSX/Benchmarks/2025-01-09-benchmarks-post-conditionalFormatsAndSheetProtection +46 -0
- package/thirdparty/OpenXLSX/Benchmarks/2025-01-10-benchmarks-post-XLCellValue-bugfix +46 -0
- package/thirdparty/OpenXLSX/Benchmarks/2025-01-31-benchmarks-post-XLComments-implementation +46 -0
- package/thirdparty/OpenXLSX/Benchmarks/2025-02-02-benchmarks-post-XLRowIterator-Rework +46 -0
- package/thirdparty/OpenXLSX/Benchmarks/2025-07-20-benchmarks-after-hiding-pugixml-internals +46 -0
- package/thirdparty/OpenXLSX/Benchmarks/2025-08-29-benchmarks-after-code-review-with-libzip +46 -0
- package/thirdparty/OpenXLSX/Benchmarks/Benchmark.cpp +249 -0
- package/thirdparty/OpenXLSX/Benchmarks/CMakeLists.txt +19 -0
- package/thirdparty/OpenXLSX/CMakeLists.txt +466 -0
- package/thirdparty/OpenXLSX/Documentation/CMakeLists.txt +31 -0
- package/thirdparty/OpenXLSX/Documentation/Doxyfile.in +2471 -0
- package/thirdparty/OpenXLSX/Documentation/DoxygenLayout.xml +194 -0
- package/thirdparty/OpenXLSX/Documentation/customdoxygen.css +1355 -0
- package/thirdparty/OpenXLSX/Examples/CMakeLists.txt +103 -0
- package/thirdparty/OpenXLSX/Examples/Demo1.cpp +279 -0
- package/thirdparty/OpenXLSX/Examples/Demo10.cpp +545 -0
- package/thirdparty/OpenXLSX/Examples/Demo1A.cpp +137 -0
- package/thirdparty/OpenXLSX/Examples/Demo2.cpp +65 -0
- package/thirdparty/OpenXLSX/Examples/Demo3.cpp +89 -0
- package/thirdparty/OpenXLSX/Examples/Demo4.cpp +86 -0
- package/thirdparty/OpenXLSX/Examples/Demo5.cpp +77 -0
- package/thirdparty/OpenXLSX/Examples/Demo6.cpp +103 -0
- package/thirdparty/OpenXLSX/Examples/Demo7.cpp +79 -0
- package/thirdparty/OpenXLSX/Examples/Demo8.cpp +117 -0
- package/thirdparty/OpenXLSX/Examples/Demo9.cpp +363 -0
- package/thirdparty/OpenXLSX/Examples/cmake/FindLIBZIP.cmake +61 -0
- package/thirdparty/OpenXLSX/Examples/external/CustomZip/CustomZip.hpp +256 -0
- package/thirdparty/OpenXLSX/LICENSE.md +29 -0
- package/thirdparty/OpenXLSX/Makefile.GNU +530 -0
- package/thirdparty/OpenXLSX/Notes/TBDs.txt +16 -0
- package/thirdparty/OpenXLSX/Notes/confirmed-TBCs.txt +8 -0
- package/thirdparty/OpenXLSX/Notes/styles-missing-support.xml +12 -0
- package/thirdparty/OpenXLSX/Notes/todo-list.txt +108 -0
- package/thirdparty/OpenXLSX/OpenXLSX/CMakeLists.txt +631 -0
- package/thirdparty/OpenXLSX/OpenXLSX/OpenXLSX.hpp +63 -0
- package/thirdparty/OpenXLSX/OpenXLSX/OpenXLSXConfig.cmake +11 -0
- package/thirdparty/OpenXLSX/OpenXLSX/cmake/bundle_static_library.cmake +198 -0
- package/thirdparty/OpenXLSX/OpenXLSX/cmake/patch_pkg_config.cmake +69 -0
- package/thirdparty/OpenXLSX/OpenXLSX/headers/IZipArchive.hpp +361 -0
- package/thirdparty/OpenXLSX/OpenXLSX/headers/OpenXLSX/IZipArchive.hpp +361 -0
- package/thirdparty/OpenXLSX/OpenXLSX/headers/OpenXLSX/OpenXLSX-Exports.hpp +12 -0
- package/thirdparty/OpenXLSX/OpenXLSX/headers/OpenXLSX/XLCell.hpp +367 -0
- package/thirdparty/OpenXLSX/OpenXLSX/headers/OpenXLSX/XLCellIterator.hpp +252 -0
- package/thirdparty/OpenXLSX/OpenXLSX/headers/OpenXLSX/XLCellRange.hpp +223 -0
- package/thirdparty/OpenXLSX/OpenXLSX/headers/OpenXLSX/XLCellReference.hpp +317 -0
- package/thirdparty/OpenXLSX/OpenXLSX/headers/OpenXLSX/XLCellValue.hpp +793 -0
- package/thirdparty/OpenXLSX/OpenXLSX/headers/OpenXLSX/XLColor.hpp +232 -0
- package/thirdparty/OpenXLSX/OpenXLSX/headers/OpenXLSX/XLColumn.hpp +159 -0
- package/thirdparty/OpenXLSX/OpenXLSX/headers/OpenXLSX/XLCommandQuery.hpp +228 -0
- package/thirdparty/OpenXLSX/OpenXLSX/headers/OpenXLSX/XLComments.hpp +270 -0
- package/thirdparty/OpenXLSX/OpenXLSX/headers/OpenXLSX/XLConstants.hpp +18 -0
- package/thirdparty/OpenXLSX/OpenXLSX/headers/OpenXLSX/XLContentTypes.hpp +264 -0
- package/thirdparty/OpenXLSX/OpenXLSX/headers/OpenXLSX/XLDateTime.hpp +175 -0
- package/thirdparty/OpenXLSX/OpenXLSX/headers/OpenXLSX/XLDocument.hpp +505 -0
- package/thirdparty/OpenXLSX/OpenXLSX/headers/OpenXLSX/XLDrawing.hpp +452 -0
- package/thirdparty/OpenXLSX/OpenXLSX/headers/OpenXLSX/XLException.hpp +161 -0
- package/thirdparty/OpenXLSX/OpenXLSX/headers/OpenXLSX/XLFormula.hpp +375 -0
- package/thirdparty/OpenXLSX/OpenXLSX/headers/OpenXLSX/XLIterator.hpp +40 -0
- package/thirdparty/OpenXLSX/OpenXLSX/headers/OpenXLSX/XLMergeCells.hpp +216 -0
- package/thirdparty/OpenXLSX/OpenXLSX/headers/OpenXLSX/XLProperties.hpp +348 -0
- package/thirdparty/OpenXLSX/OpenXLSX/headers/OpenXLSX/XLRelationships.hpp +348 -0
- package/thirdparty/OpenXLSX/OpenXLSX/headers/OpenXLSX/XLRow.hpp +721 -0
- package/thirdparty/OpenXLSX/OpenXLSX/headers/OpenXLSX/XLRowData.hpp +488 -0
- package/thirdparty/OpenXLSX/OpenXLSX/headers/OpenXLSX/XLSharedStrings.hpp +204 -0
- package/thirdparty/OpenXLSX/OpenXLSX/headers/OpenXLSX/XLSheet.hpp +1640 -0
- package/thirdparty/OpenXLSX/OpenXLSX/headers/OpenXLSX/XLStyles.hpp +2390 -0
- package/thirdparty/OpenXLSX/OpenXLSX/headers/OpenXLSX/XLTables.hpp +132 -0
- package/thirdparty/OpenXLSX/OpenXLSX/headers/OpenXLSX/XLWorkbook.hpp +404 -0
- package/thirdparty/OpenXLSX/OpenXLSX/headers/OpenXLSX/XLXmlData.hpp +283 -0
- package/thirdparty/OpenXLSX/OpenXLSX/headers/OpenXLSX/XLXmlFile.hpp +194 -0
- package/thirdparty/OpenXLSX/OpenXLSX/headers/OpenXLSX/XLXmlParser.hpp +282 -0
- package/thirdparty/OpenXLSX/OpenXLSX/headers/OpenXLSX/XLXmlParserForwardDeclarations.hpp +85 -0
- package/thirdparty/OpenXLSX/OpenXLSX/headers/OpenXLSX/XLZipArchive.hpp +232 -0
- package/thirdparty/OpenXLSX/OpenXLSX/headers/OpenXLSX/detail/LibZip.hpp +447 -0
- package/thirdparty/OpenXLSX/OpenXLSX/headers/OpenXLSX/detail/OpenXLSXFileSystemTools.hpp +207 -0
- package/thirdparty/OpenXLSX/OpenXLSX/headers/OpenXLSX/detail/Zippy.hpp +1375 -0
- package/thirdparty/OpenXLSX/OpenXLSX/headers/OpenXLSX-Exports.hpp +12 -0
- package/thirdparty/OpenXLSX/OpenXLSX/headers/XLCell.hpp +367 -0
- package/thirdparty/OpenXLSX/OpenXLSX/headers/XLCellIterator.hpp +252 -0
- package/thirdparty/OpenXLSX/OpenXLSX/headers/XLCellRange.hpp +223 -0
- package/thirdparty/OpenXLSX/OpenXLSX/headers/XLCellReference.hpp +317 -0
- package/thirdparty/OpenXLSX/OpenXLSX/headers/XLCellValue.hpp +793 -0
- package/thirdparty/OpenXLSX/OpenXLSX/headers/XLColor.hpp +232 -0
- package/thirdparty/OpenXLSX/OpenXLSX/headers/XLColumn.hpp +159 -0
- package/thirdparty/OpenXLSX/OpenXLSX/headers/XLCommandQuery.hpp +228 -0
- package/thirdparty/OpenXLSX/OpenXLSX/headers/XLComments.hpp +270 -0
- package/thirdparty/OpenXLSX/OpenXLSX/headers/XLConstants.hpp +18 -0
- package/thirdparty/OpenXLSX/OpenXLSX/headers/XLContentTypes.hpp +264 -0
- package/thirdparty/OpenXLSX/OpenXLSX/headers/XLDateTime.hpp +175 -0
- package/thirdparty/OpenXLSX/OpenXLSX/headers/XLDocument.hpp +505 -0
- package/thirdparty/OpenXLSX/OpenXLSX/headers/XLDrawing.hpp +452 -0
- package/thirdparty/OpenXLSX/OpenXLSX/headers/XLException.hpp +161 -0
- package/thirdparty/OpenXLSX/OpenXLSX/headers/XLFormula.hpp +375 -0
- package/thirdparty/OpenXLSX/OpenXLSX/headers/XLIterator.hpp +40 -0
- package/thirdparty/OpenXLSX/OpenXLSX/headers/XLMergeCells.hpp +216 -0
- package/thirdparty/OpenXLSX/OpenXLSX/headers/XLProperties.hpp +348 -0
- package/thirdparty/OpenXLSX/OpenXLSX/headers/XLRelationships.hpp +348 -0
- package/thirdparty/OpenXLSX/OpenXLSX/headers/XLRow.hpp +721 -0
- package/thirdparty/OpenXLSX/OpenXLSX/headers/XLRowData.hpp +488 -0
- package/thirdparty/OpenXLSX/OpenXLSX/headers/XLSharedStrings.hpp +204 -0
- package/thirdparty/OpenXLSX/OpenXLSX/headers/XLSheet.hpp +1640 -0
- package/thirdparty/OpenXLSX/OpenXLSX/headers/XLStyles.hpp +2390 -0
- package/thirdparty/OpenXLSX/OpenXLSX/headers/XLTables.hpp +132 -0
- package/thirdparty/OpenXLSX/OpenXLSX/headers/XLWorkbook.hpp +404 -0
- package/thirdparty/OpenXLSX/OpenXLSX/headers/XLXmlData.hpp +283 -0
- package/thirdparty/OpenXLSX/OpenXLSX/headers/XLXmlFile.hpp +194 -0
- package/thirdparty/OpenXLSX/OpenXLSX/headers/XLXmlParser.hpp +282 -0
- package/thirdparty/OpenXLSX/OpenXLSX/headers/XLXmlParserForwardDeclarations.hpp +85 -0
- package/thirdparty/OpenXLSX/OpenXLSX/headers/XLZipArchive.hpp +232 -0
- package/thirdparty/OpenXLSX/OpenXLSX/headers/detail/LibZip.hpp +447 -0
- package/thirdparty/OpenXLSX/OpenXLSX/headers/detail/OpenXLSXFileSystemTools.hpp +207 -0
- package/thirdparty/OpenXLSX/OpenXLSX/headers/detail/Zippy.hpp +1375 -0
- package/thirdparty/OpenXLSX/OpenXLSX/sources/XLCell.cpp +340 -0
- package/thirdparty/OpenXLSX/OpenXLSX/sources/XLCellIterator.cpp +427 -0
- package/thirdparty/OpenXLSX/OpenXLSX/sources/XLCellRange.cpp +221 -0
- package/thirdparty/OpenXLSX/OpenXLSX/sources/XLCellReference.cpp +408 -0
- package/thirdparty/OpenXLSX/OpenXLSX/sources/XLCellValue.cpp +519 -0
- package/thirdparty/OpenXLSX/OpenXLSX/sources/XLColor.cpp +202 -0
- package/thirdparty/OpenXLSX/OpenXLSX/sources/XLColumn.cpp +141 -0
- package/thirdparty/OpenXLSX/OpenXLSX/sources/XLComments.cpp +637 -0
- package/thirdparty/OpenXLSX/OpenXLSX/sources/XLContentTypes.cpp +329 -0
- package/thirdparty/OpenXLSX/OpenXLSX/sources/XLDateTime.cpp +269 -0
- package/thirdparty/OpenXLSX/OpenXLSX/sources/XLDocument.cpp +1678 -0
- package/thirdparty/OpenXLSX/OpenXLSX/sources/XLDrawing.cpp +784 -0
- package/thirdparty/OpenXLSX/OpenXLSX/sources/XLFormula.cpp +201 -0
- package/thirdparty/OpenXLSX/OpenXLSX/sources/XLMergeCells.cpp +357 -0
- package/thirdparty/OpenXLSX/OpenXLSX/sources/XLProperties.cpp +810 -0
- package/thirdparty/OpenXLSX/OpenXLSX/sources/XLRelationships.cpp +529 -0
- package/thirdparty/OpenXLSX/OpenXLSX/sources/XLRow.cpp +918 -0
- package/thirdparty/OpenXLSX/OpenXLSX/sources/XLRowData.cpp +508 -0
- package/thirdparty/OpenXLSX/OpenXLSX/sources/XLSharedStrings.cpp +220 -0
- package/thirdparty/OpenXLSX/OpenXLSX/sources/XLSheet.cpp +1970 -0
- package/thirdparty/OpenXLSX/OpenXLSX/sources/XLStyles.cpp +3014 -0
- package/thirdparty/OpenXLSX/OpenXLSX/sources/XLTables.cpp +125 -0
- package/thirdparty/OpenXLSX/OpenXLSX/sources/XLWorkbook.cpp +784 -0
- package/thirdparty/OpenXLSX/OpenXLSX/sources/XLXmlData.cpp +247 -0
- package/thirdparty/OpenXLSX/OpenXLSX/sources/XLXmlFile.cpp +160 -0
- package/thirdparty/OpenXLSX/OpenXLSX/sources/XLXmlParser.cpp +261 -0
- package/thirdparty/OpenXLSX/OpenXLSX/sources/XLZipArchive.cpp +266 -0
- package/thirdparty/OpenXLSX/OpenXLSX/sources/utilities/XLUtilities.hpp +478 -0
- package/thirdparty/OpenXLSX/README.md +1279 -0
- package/thirdparty/OpenXLSX/Scripts/cmake-cleanup.sh +102 -0
- package/thirdparty/OpenXLSX/Scripts/compile.sh +23 -0
- package/thirdparty/OpenXLSX/Scripts/demos-cleanup.sh +25 -0
- package/thirdparty/OpenXLSX/Scripts/demos-run-all.sh +60 -0
- package/thirdparty/OpenXLSX/Scripts/guarded-xml-format.sh +47 -0
- package/thirdparty/OpenXLSX/Scripts/make-gnu.sh +11 -0
- package/thirdparty/OpenXLSX/Scripts/uninstall-manifest.sh +48 -0
- package/thirdparty/OpenXLSX/Scripts/xml-format-all.sh +19 -0
- package/thirdparty/OpenXLSX/Scripts/xml-format.sh +38 -0
- package/thirdparty/OpenXLSX/Tests/CMakeLists.txt +37 -0
- package/thirdparty/OpenXLSX/Tests/catch/catch.hpp +17799 -0
- package/thirdparty/OpenXLSX/Tests/catch/catch_reporter_automake.hpp +68 -0
- package/thirdparty/OpenXLSX/Tests/catch/catch_reporter_sonarqube.hpp +182 -0
- package/thirdparty/OpenXLSX/Tests/catch/catch_reporter_tap.hpp +278 -0
- package/thirdparty/OpenXLSX/Tests/catch/catch_reporter_teamcity.hpp +212 -0
- package/thirdparty/OpenXLSX/Tests/main.cpp +55 -0
- package/thirdparty/OpenXLSX/Tests/testXLCell.cpp +176 -0
- package/thirdparty/OpenXLSX/Tests/testXLCellRange.cpp +180 -0
- package/thirdparty/OpenXLSX/Tests/testXLCellReference.cpp +160 -0
- package/thirdparty/OpenXLSX/Tests/testXLCellValue.cpp +366 -0
- package/thirdparty/OpenXLSX/Tests/testXLCellValueProxy.cpp +255 -0
- package/thirdparty/OpenXLSX/Tests/testXLColor.cpp +75 -0
- package/thirdparty/OpenXLSX/Tests/testXLDateTime.cpp +229 -0
- package/thirdparty/OpenXLSX/Tests/testXLDocument.cpp +197 -0
- package/thirdparty/OpenXLSX/Tests/testXLFormula.cpp +131 -0
- package/thirdparty/OpenXLSX/Tests/testXLRow.cpp +597 -0
- package/thirdparty/OpenXLSX/Tests/testXLSheet.cpp +77 -0
- package/thirdparty/OpenXLSX/Tests/ziptest-with-libs.cpp +88 -0
- package/thirdparty/OpenXLSX/Tests/ziptest.cpp +735 -0
- package/thirdparty/OpenXLSX/cmake/get-git-HEAD-ID.cmake +45 -0
- package/thirdparty/OpenXLSX/cmake/libopenxlsxCPackOptions.cmake.in +20 -0
- package/thirdparty/OpenXLSX/cmake/manage_dependency.cmake +813 -0
- package/thirdparty/OpenXLSX/cmake/recursive_library_type_test.cmake +52 -0
- package/thirdparty/OpenXLSX/gnu-make-crutch/OpenXLSX-Exports-shared.hpp +42 -0
- package/thirdparty/OpenXLSX/gnu-make-crutch/OpenXLSX-Exports-static.hpp +42 -0
- package/thirdparty/OpenXLSX/vcpkg.json +24 -0
- package/thirdparty/README.md +46 -0
- package/thirdparty/miniz/.clang-format +47 -0
- package/thirdparty/miniz/.travis.yml +2 -0
- package/thirdparty/miniz/CMakeLists.txt +333 -0
- package/thirdparty/miniz/CMakePresets.json +31 -0
- package/thirdparty/miniz/ChangeLog.md +272 -0
- package/thirdparty/miniz/Config.cmake.in +1 -0
- package/thirdparty/miniz/LICENSE +22 -0
- package/thirdparty/miniz/amalgamate.sh +57 -0
- package/thirdparty/miniz/examples/example1.c +105 -0
- package/thirdparty/miniz/examples/example2.c +164 -0
- package/thirdparty/miniz/examples/example3.c +269 -0
- package/thirdparty/miniz/examples/example4.c +102 -0
- package/thirdparty/miniz/examples/example5.c +327 -0
- package/thirdparty/miniz/examples/example6.c +189 -0
- package/thirdparty/miniz/meson.build +21 -0
- package/thirdparty/miniz/miniz.c +646 -0
- package/thirdparty/miniz/miniz.h +615 -0
- package/thirdparty/miniz/miniz.pc.in +13 -0
- package/thirdparty/miniz/miniz_common.h +89 -0
- package/thirdparty/miniz/miniz_export.h +20 -0
- package/thirdparty/miniz/miniz_tdef.c +1602 -0
- package/thirdparty/miniz/miniz_tdef.h +199 -0
- package/thirdparty/miniz/miniz_tinfl.c +778 -0
- package/thirdparty/miniz/miniz_tinfl.h +150 -0
- package/thirdparty/miniz/miniz_zip.c +4895 -0
- package/thirdparty/miniz/miniz_zip.h +454 -0
- package/thirdparty/miniz/readme.md +46 -0
- package/thirdparty/miniz/test.sh +36 -0
- package/thirdparty/miniz/tests/add_in_place_fuzzer.c +87 -0
- package/thirdparty/miniz/tests/catch_amalgamated.cpp +10795 -0
- package/thirdparty/miniz/tests/catch_amalgamated.hpp +13143 -0
- package/thirdparty/miniz/tests/checksum_fuzzer.c +26 -0
- package/thirdparty/miniz/tests/compress_fuzzer.c +91 -0
- package/thirdparty/miniz/tests/flush_fuzzer.c +88 -0
- package/thirdparty/miniz/tests/fuzz_main.c +55 -0
- package/thirdparty/miniz/tests/large_fuzzer.c +133 -0
- package/thirdparty/miniz/tests/main.cpp +185 -0
- package/thirdparty/miniz/tests/miniz_tdefl_fuzzer.cc +115 -0
- package/thirdparty/miniz/tests/miniz_tester.cpp +1881 -0
- package/thirdparty/miniz/tests/miniz_zip_validate_fuzzer.cc +71 -0
- package/thirdparty/miniz/tests/miniz_zip_writer_fuzzer.cc +96 -0
- package/thirdparty/miniz/tests/ossfuzz.sh +48 -0
- package/thirdparty/miniz/tests/small_fuzzer.c +126 -0
- package/thirdparty/miniz/tests/timer.cpp +152 -0
- package/thirdparty/miniz/tests/timer.h +40 -0
- package/thirdparty/miniz/tests/uncompress2_fuzzer.c +21 -0
- package/thirdparty/miniz/tests/uncompress_fuzzer.c +30 -0
- package/thirdparty/miniz/tests/zip.dict +9 -0
- package/thirdparty/miniz/tests/zip_fuzzer.c +63 -0
- package/thirdparty/pugixml/.codecov.yml +7 -0
- package/thirdparty/pugixml/.gitattributes +1 -0
- package/thirdparty/pugixml/CMakeLists.txt +330 -0
- package/thirdparty/pugixml/LICENSE.md +24 -0
- package/thirdparty/pugixml/Makefile +98 -0
- package/thirdparty/pugixml/README.md +81 -0
- package/thirdparty/pugixml/SECURITY.md +9 -0
- package/thirdparty/pugixml/appveyor.yml +50 -0
- package/thirdparty/pugixml/docs/config.adoc +7 -0
- package/thirdparty/pugixml/docs/images/dom_tree.png +0 -0
- package/thirdparty/pugixml/docs/images/vs2005_link1.png +0 -0
- package/thirdparty/pugixml/docs/images/vs2005_link2.png +0 -0
- package/thirdparty/pugixml/docs/images/vs2005_pch1.png +0 -0
- package/thirdparty/pugixml/docs/images/vs2005_pch2.png +0 -0
- package/thirdparty/pugixml/docs/images/vs2005_pch3.png +0 -0
- package/thirdparty/pugixml/docs/images/vs2005_pch4.png +0 -0
- package/thirdparty/pugixml/docs/images/vs2010_link1.png +0 -0
- package/thirdparty/pugixml/docs/images/vs2010_link2.png +0 -0
- package/thirdparty/pugixml/docs/manual.adoc +3326 -0
- package/thirdparty/pugixml/docs/manual.html +6395 -0
- package/thirdparty/pugixml/docs/quickstart.adoc +287 -0
- package/thirdparty/pugixml/docs/quickstart.html +1107 -0
- package/thirdparty/pugixml/docs/samples/character.xml +8 -0
- package/thirdparty/pugixml/docs/samples/custom_memory_management.cpp +27 -0
- package/thirdparty/pugixml/docs/samples/include.cpp +64 -0
- package/thirdparty/pugixml/docs/samples/load_error_handling.cpp +33 -0
- package/thirdparty/pugixml/docs/samples/load_file.cpp +16 -0
- package/thirdparty/pugixml/docs/samples/load_memory.cpp +66 -0
- package/thirdparty/pugixml/docs/samples/load_options.cpp +30 -0
- package/thirdparty/pugixml/docs/samples/load_stream.cpp +97 -0
- package/thirdparty/pugixml/docs/samples/modify_add.cpp +29 -0
- package/thirdparty/pugixml/docs/samples/modify_base.cpp +43 -0
- package/thirdparty/pugixml/docs/samples/modify_remove.cpp +27 -0
- package/thirdparty/pugixml/docs/samples/save_custom_writer.cpp +116 -0
- package/thirdparty/pugixml/docs/samples/save_declaration.cpp +27 -0
- package/thirdparty/pugixml/docs/samples/save_file.cpp +17 -0
- package/thirdparty/pugixml/docs/samples/save_options.cpp +48 -0
- package/thirdparty/pugixml/docs/samples/save_stream.cpp +18 -0
- package/thirdparty/pugixml/docs/samples/save_subtree.cpp +26 -0
- package/thirdparty/pugixml/docs/samples/text.cpp +35 -0
- package/thirdparty/pugixml/docs/samples/transitions.xml +7 -0
- package/thirdparty/pugixml/docs/samples/traverse_base.cpp +51 -0
- package/thirdparty/pugixml/docs/samples/traverse_iter.cpp +27 -0
- package/thirdparty/pugixml/docs/samples/traverse_predicate.cpp +48 -0
- package/thirdparty/pugixml/docs/samples/traverse_rangefor.cpp +32 -0
- package/thirdparty/pugixml/docs/samples/traverse_walker.cpp +35 -0
- package/thirdparty/pugixml/docs/samples/tree.xml +12 -0
- package/thirdparty/pugixml/docs/samples/weekly-shift_jis.xml +78 -0
- package/thirdparty/pugixml/docs/samples/weekly-utf-16.xml +0 -0
- package/thirdparty/pugixml/docs/samples/weekly-utf-8.xml +78 -0
- package/thirdparty/pugixml/docs/samples/xgconsole.xml +12 -0
- package/thirdparty/pugixml/docs/samples/xpath_error.cpp +43 -0
- package/thirdparty/pugixml/docs/samples/xpath_query.cpp +36 -0
- package/thirdparty/pugixml/docs/samples/xpath_select.cpp +28 -0
- package/thirdparty/pugixml/docs/samples/xpath_variables.cpp +38 -0
- package/thirdparty/pugixml/readme.txt +50 -0
- package/thirdparty/pugixml/scripts/archive.py +54 -0
- package/thirdparty/pugixml/scripts/cocoapods_push.sh +4 -0
- package/thirdparty/pugixml/scripts/natvis/pugixml.natvis +77 -0
- package/thirdparty/pugixml/scripts/natvis/pugixml_compact.natvis +506 -0
- package/thirdparty/pugixml/scripts/nuget/build/native/pugixml-propertiesui.xml +17 -0
- package/thirdparty/pugixml/scripts/nuget/build/native/pugixml.targets +28 -0
- package/thirdparty/pugixml/scripts/nuget/pugixml.nuspec +20 -0
- package/thirdparty/pugixml/scripts/nuget_build.ps1 +60 -0
- package/thirdparty/pugixml/scripts/premake4.lua +92 -0
- package/thirdparty/pugixml/scripts/pugixml-config.cmake.in +12 -0
- package/thirdparty/pugixml/scripts/pugixml.pc.in +11 -0
- package/thirdparty/pugixml/scripts/pugixml.podspec +14 -0
- package/thirdparty/pugixml/scripts/pugixml.xcodeproj/project.pbxproj +212 -0
- package/thirdparty/pugixml/scripts/pugixml_airplay.mkf +13 -0
- package/thirdparty/pugixml/scripts/pugixml_codeblocks.cbp +44 -0
- package/thirdparty/pugixml/scripts/pugixml_codelite.project +56 -0
- package/thirdparty/pugixml/scripts/pugixml_dll.rc +45 -0
- package/thirdparty/pugixml/scripts/pugixml_vs2005.vcproj +343 -0
- package/thirdparty/pugixml/scripts/pugixml_vs2005_static.vcproj +343 -0
- package/thirdparty/pugixml/scripts/pugixml_vs2008.vcproj +339 -0
- package/thirdparty/pugixml/scripts/pugixml_vs2008_static.vcproj +339 -0
- package/thirdparty/pugixml/scripts/pugixml_vs2010.vcxproj +191 -0
- package/thirdparty/pugixml/scripts/pugixml_vs2010_static.vcxproj +191 -0
- package/thirdparty/pugixml/scripts/pugixml_vs2013.vcxproj +199 -0
- package/thirdparty/pugixml/scripts/pugixml_vs2013_static.vcxproj +199 -0
- package/thirdparty/pugixml/scripts/pugixml_vs2015.vcxproj +172 -0
- package/thirdparty/pugixml/scripts/pugixml_vs2015_static.vcxproj +176 -0
- package/thirdparty/pugixml/scripts/pugixml_vs2017.vcxproj +172 -0
- package/thirdparty/pugixml/scripts/pugixml_vs2017_static.vcxproj +176 -0
- package/thirdparty/pugixml/scripts/pugixml_vs2019.vcxproj +176 -0
- package/thirdparty/pugixml/scripts/pugixml_vs2019_static.vcxproj +180 -0
- package/thirdparty/pugixml/scripts/pugixml_vs2022.vcxproj +176 -0
- package/thirdparty/pugixml/scripts/pugixml_vs2022_static.vcxproj +180 -0
- package/thirdparty/pugixml/scripts/pugixml_vs2026.vcxproj +176 -0
- package/thirdparty/pugixml/scripts/pugixml_vs2026_static.vcxproj +180 -0
- package/thirdparty/pugixml/scripts/sbom.cdx.json +47 -0
- package/thirdparty/pugixml/src/pugiconfig.hpp +81 -0
- package/thirdparty/pugixml/src/pugixml.cpp +13776 -0
- package/thirdparty/pugixml/src/pugixml.hpp +1604 -0
- package/thirdparty/pugixml/tests/allocator.cpp +175 -0
- package/thirdparty/pugixml/tests/allocator.hpp +10 -0
- package/thirdparty/pugixml/tests/autotest-appveyor.ps1 +93 -0
- package/thirdparty/pugixml/tests/cmake-appveyor.ps1 +57 -0
- package/thirdparty/pugixml/tests/data/empty.xml +0 -0
- package/thirdparty/pugixml/tests/data/large.xml +1 -0
- package/thirdparty/pugixml/tests/data/latintest_latin1.xml +1 -0
- package/thirdparty/pugixml/tests/data/latintest_utf8.xml +1 -0
- package/thirdparty/pugixml/tests/data/multiline.xml +3 -0
- package/thirdparty/pugixml/tests/data/small.xml +1 -0
- package/thirdparty/pugixml/tests/data/truncation.xml +19 -0
- package/thirdparty/pugixml/tests/data/utftest_utf16_be.xml +0 -0
- package/thirdparty/pugixml/tests/data/utftest_utf16_be_bom.xml +0 -0
- package/thirdparty/pugixml/tests/data/utftest_utf16_be_clean.xml +0 -0
- package/thirdparty/pugixml/tests/data/utftest_utf16_be_nodecl.xml +0 -0
- package/thirdparty/pugixml/tests/data/utftest_utf16_le.xml +0 -0
- package/thirdparty/pugixml/tests/data/utftest_utf16_le_bom.xml +0 -0
- package/thirdparty/pugixml/tests/data/utftest_utf16_le_clean.xml +0 -0
- package/thirdparty/pugixml/tests/data/utftest_utf16_le_nodecl.xml +0 -0
- package/thirdparty/pugixml/tests/data/utftest_utf32_be.xml +0 -0
- package/thirdparty/pugixml/tests/data/utftest_utf32_be_bom.xml +0 -0
- package/thirdparty/pugixml/tests/data/utftest_utf32_be_clean.xml +0 -0
- package/thirdparty/pugixml/tests/data/utftest_utf32_be_nodecl.xml +0 -0
- package/thirdparty/pugixml/tests/data/utftest_utf32_le.xml +0 -0
- package/thirdparty/pugixml/tests/data/utftest_utf32_le_bom.xml +0 -0
- package/thirdparty/pugixml/tests/data/utftest_utf32_le_clean.xml +0 -0
- package/thirdparty/pugixml/tests/data/utftest_utf32_le_nodecl.xml +0 -0
- package/thirdparty/pugixml/tests/data/utftest_utf8.xml +87 -0
- package/thirdparty/pugixml/tests/data/utftest_utf8_bom.xml +87 -0
- package/thirdparty/pugixml/tests/data/utftest_utf8_clean.xml +84 -0
- package/thirdparty/pugixml/tests/data/utftest_utf8_nodecl.xml +86 -0
- package/thirdparty/pugixml/tests/data//321/202/320/265/321/201/321/202.xml +1 -0
- package/thirdparty/pugixml/tests/data_fuzz_parse/basic.xml +1 -0
- package/thirdparty/pugixml/tests/data_fuzz_parse/doctype.xml +1 -0
- package/thirdparty/pugixml/tests/data_fuzz_parse/refs.xml +1 -0
- package/thirdparty/pugixml/tests/data_fuzz_parse/types.xml +1 -0
- package/thirdparty/pugixml/tests/data_fuzz_parse/utf16.xml +0 -0
- package/thirdparty/pugixml/tests/data_fuzz_parse/utf32.xml +0 -0
- package/thirdparty/pugixml/tests/data_fuzz_xpath/basic.xpath +1 -0
- package/thirdparty/pugixml/tests/data_fuzz_xpath/functions.xpath +1 -0
- package/thirdparty/pugixml/tests/data_fuzz_xpath/math.xpath +1 -0
- package/thirdparty/pugixml/tests/data_fuzz_xpath/path.xpath +1 -0
- package/thirdparty/pugixml/tests/data_fuzz_xpath/predicate.xpath +1 -0
- package/thirdparty/pugixml/tests/fuzz_parse.cpp +14 -0
- package/thirdparty/pugixml/tests/fuzz_parse.dict +72 -0
- package/thirdparty/pugixml/tests/fuzz_setup.sh +11 -0
- package/thirdparty/pugixml/tests/fuzz_xpath.cpp +46 -0
- package/thirdparty/pugixml/tests/fuzz_xpath.dict +72 -0
- package/thirdparty/pugixml/tests/helpers.hpp +114 -0
- package/thirdparty/pugixml/tests/main.cpp +218 -0
- package/thirdparty/pugixml/tests/test.cpp +220 -0
- package/thirdparty/pugixml/tests/test.hpp +175 -0
- package/thirdparty/pugixml/tests/test_compact.cpp +150 -0
- package/thirdparty/pugixml/tests/test_deprecated.cpp +25 -0
- package/thirdparty/pugixml/tests/test_document.cpp +1910 -0
- package/thirdparty/pugixml/tests/test_dom_modify.cpp +2122 -0
- package/thirdparty/pugixml/tests/test_dom_text.cpp +601 -0
- package/thirdparty/pugixml/tests/test_dom_traverse.cpp +1481 -0
- package/thirdparty/pugixml/tests/test_header_guard.cpp +3 -0
- package/thirdparty/pugixml/tests/test_header_iosfwd_1.cpp +3 -0
- package/thirdparty/pugixml/tests/test_header_iosfwd_2.cpp +3 -0
- package/thirdparty/pugixml/tests/test_header_iostream_1.cpp +3 -0
- package/thirdparty/pugixml/tests/test_header_iostream_2.cpp +3 -0
- package/thirdparty/pugixml/tests/test_header_only_1.cpp +21 -0
- package/thirdparty/pugixml/tests/test_header_only_2.cpp +21 -0
- package/thirdparty/pugixml/tests/test_header_string_1.cpp +3 -0
- package/thirdparty/pugixml/tests/test_header_string_2.cpp +3 -0
- package/thirdparty/pugixml/tests/test_header_string_iostream.cpp +5 -0
- package/thirdparty/pugixml/tests/test_memory.cpp +303 -0
- package/thirdparty/pugixml/tests/test_parse.cpp +1463 -0
- package/thirdparty/pugixml/tests/test_parse_doctype.cpp +366 -0
- package/thirdparty/pugixml/tests/test_unicode.cpp +152 -0
- package/thirdparty/pugixml/tests/test_version.cpp +5 -0
- package/thirdparty/pugixml/tests/test_write.cpp +757 -0
- package/thirdparty/pugixml/tests/test_xpath.cpp +833 -0
- package/thirdparty/pugixml/tests/test_xpath_api.cpp +646 -0
- package/thirdparty/pugixml/tests/test_xpath_functions.cpp +844 -0
- package/thirdparty/pugixml/tests/test_xpath_operators.cpp +566 -0
- package/thirdparty/pugixml/tests/test_xpath_parse.cpp +428 -0
- package/thirdparty/pugixml/tests/test_xpath_paths.cpp +787 -0
- package/thirdparty/pugixml/tests/test_xpath_paths_abbrev_w3c.cpp +219 -0
- package/thirdparty/pugixml/tests/test_xpath_paths_w3c.cpp +312 -0
- package/thirdparty/pugixml/tests/test_xpath_variables.cpp +683 -0
- package/thirdparty/pugixml/tests/test_xpath_xalan_1.cpp +411 -0
- package/thirdparty/pugixml/tests/test_xpath_xalan_2.cpp +417 -0
- package/thirdparty/pugixml/tests/test_xpath_xalan_3.cpp +321 -0
- package/thirdparty/pugixml/tests/test_xpath_xalan_4.cpp +300 -0
- package/thirdparty/pugixml/tests/test_xpath_xalan_5.cpp +295 -0
- package/thirdparty/pugixml/tests/writer_string.cpp +79 -0
- package/thirdparty/pugixml/tests/writer_string.hpp +27 -0
- package/scripts/prepare-openxlsx.js +0 -126
|
@@ -0,0 +1,1375 @@
|
|
|
1
|
+
#ifndef ZIPPY2_LIBRARY_H
|
|
2
|
+
#define ZIPPY2_LIBRARY_H
|
|
3
|
+
|
|
4
|
+
#include <algorithm>
|
|
5
|
+
#include <ctime>
|
|
6
|
+
#include <fstream>
|
|
7
|
+
#include <miniz.h>
|
|
8
|
+
#include <miniz_zip.h>
|
|
9
|
+
#include <random>
|
|
10
|
+
#include <stdexcept>
|
|
11
|
+
#include <sys/stat.h>
|
|
12
|
+
|
|
13
|
+
#ifdef _WIN32
|
|
14
|
+
#include <direct.h>
|
|
15
|
+
#endif
|
|
16
|
+
|
|
17
|
+
#include "detail/OpenXLSXFileSystemTools.hpp" // OpenXLSX::GenerateRandomNameInSamePath, OpenXLSX::remove, OpenXLSX::rename
|
|
18
|
+
|
|
19
|
+
// 2024-09-15: moved Zippy exceptions to top of module to be able to use them earlier - forward declaration didn't seem
|
|
20
|
+
// to work
|
|
21
|
+
namespace Zippy
|
|
22
|
+
{
|
|
23
|
+
/**
|
|
24
|
+
* @brief provide a (const) library name to the caller
|
|
25
|
+
* @details
|
|
26
|
+
*/
|
|
27
|
+
constexpr const char *ZipLibraryName() { return "miniz"; };
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* @brief get the library version from miniz
|
|
31
|
+
* @details provide a pass-through function to mz_version
|
|
32
|
+
*/
|
|
33
|
+
const char *ZipLibraryVersion() { return mz_version(); }
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* @brief The ZipRuntimeError class is a custom exception class derived from the std::runtime_error class.
|
|
37
|
+
* @details In case of an error in the Zippy library, an ZipRuntimeError object will be thrown, with a message
|
|
38
|
+
* describing the details of the error.
|
|
39
|
+
*/
|
|
40
|
+
class ZipRuntimeError : public std::runtime_error
|
|
41
|
+
{
|
|
42
|
+
public:
|
|
43
|
+
/**
|
|
44
|
+
* @brief Constructor.
|
|
45
|
+
* @param err A string with a description of the error.
|
|
46
|
+
*/
|
|
47
|
+
inline explicit ZipRuntimeError(const std::string& err) : runtime_error(err) {}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* @brief Destructor.
|
|
51
|
+
*/
|
|
52
|
+
inline ~ZipRuntimeError() override = default;
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* @brief
|
|
57
|
+
*/
|
|
58
|
+
class ZipLogicError : public std::logic_error
|
|
59
|
+
{
|
|
60
|
+
public:
|
|
61
|
+
/**
|
|
62
|
+
* @brief
|
|
63
|
+
* @param err
|
|
64
|
+
*/
|
|
65
|
+
inline explicit ZipLogicError(const std::string& err) : logic_error(err) {}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* @brief
|
|
69
|
+
*/
|
|
70
|
+
inline ~ZipLogicError() override = default;
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
} // namespace Zippy
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
namespace Zippy
|
|
77
|
+
{
|
|
78
|
+
// using namespace ns_miniz;
|
|
79
|
+
|
|
80
|
+
class ZipArchive;
|
|
81
|
+
|
|
82
|
+
class ZipEntry;
|
|
83
|
+
|
|
84
|
+
// ===== Alias Declarations
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* @brief The ZipEntryInfo entity is an alias of the mz_zip_archive_file_stat from the miniz library.
|
|
88
|
+
* @details The ZipEntryInfo/mz_zip_archive_file_stat struct holds various meta data related to a particular
|
|
89
|
+
* entry (or item) in a zip archive, such as: comments, file size, date stamp etc.
|
|
90
|
+
* @note A new ZipEntryInfo should not be created manually.
|
|
91
|
+
*/
|
|
92
|
+
using ZipEntryInfo = mz_zip_archive_file_stat;
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* @brief The ZipEntryData entity is an alias for a std::vector of std::bytes.
|
|
96
|
+
* @details This is used as a generic container of file data of any kind, both character strings and binary.
|
|
97
|
+
* A vector of char or an array of char can also be used, but a vector of bytes makes it clearer that it can
|
|
98
|
+
* also be used for non-text data.
|
|
99
|
+
*/
|
|
100
|
+
using ZipEntryData = std::vector<unsigned char>;
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* @brief The ZipEntryMetaData is essentially a wrapper around the ZipEntryInfo scruct, which is an alias for a
|
|
104
|
+
* miniz struct.
|
|
105
|
+
*/
|
|
106
|
+
struct ZipEntryMetaData
|
|
107
|
+
{
|
|
108
|
+
/**
|
|
109
|
+
* @brief Constructor.
|
|
110
|
+
* @param info A reference to a ZipEntryInfo object.
|
|
111
|
+
*/
|
|
112
|
+
explicit ZipEntryMetaData(const ZipEntryInfo& info)
|
|
113
|
+
: Index(info.m_file_index),
|
|
114
|
+
CompressedSize(info.m_comp_size),
|
|
115
|
+
UncompressedSize(info.m_uncomp_size),
|
|
116
|
+
IsDirectory(info.m_is_directory),
|
|
117
|
+
IsEncrypted(info.m_is_encrypted),
|
|
118
|
+
IsSupported(info.m_is_supported),
|
|
119
|
+
Filename(info.m_filename),
|
|
120
|
+
Comment(info.m_comment),
|
|
121
|
+
Time(info.m_time)
|
|
122
|
+
{}
|
|
123
|
+
|
|
124
|
+
uint32_t Index; /**< */
|
|
125
|
+
uint64_t CompressedSize; /**< */
|
|
126
|
+
uint64_t UncompressedSize; /**< */
|
|
127
|
+
bool IsDirectory; /**< */
|
|
128
|
+
bool IsEncrypted; /**< */
|
|
129
|
+
bool IsSupported; /**< */
|
|
130
|
+
std::string Filename; /**< */
|
|
131
|
+
std::string Comment; /**< */
|
|
132
|
+
const time_t Time; /**< */
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
namespace Impl
|
|
136
|
+
{
|
|
137
|
+
/**
|
|
138
|
+
* @brief The Impl::ZipEntry class implements the functionality required for manipulating entries in a zip archive.
|
|
139
|
+
* @details This is the implementation class. The ZipEntry class in the Zippy namespace implements the public interface.
|
|
140
|
+
* The reason for having a separate implementation class, is that it enables easy copy and move operations of
|
|
141
|
+
* ZipEntry objects, without duplicating the underlying implementation objects.
|
|
142
|
+
*/
|
|
143
|
+
class ZipEntry
|
|
144
|
+
{
|
|
145
|
+
friend class Zippy::ZipArchive;
|
|
146
|
+
|
|
147
|
+
friend class Zippy::ZipEntry;
|
|
148
|
+
|
|
149
|
+
public:
|
|
150
|
+
// ===== Constructors, Destructor and Operators
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* @brief Constructor. Creates a new ZipEntry with the given ZipEntryInfo parameter. This is only used for creating
|
|
154
|
+
* a ZipEntry for an entry already present in the ZipArchive, when opening an existing archive.
|
|
155
|
+
* @param info A reference to a ZipEntryInfo object with the entry info.
|
|
156
|
+
*/
|
|
157
|
+
explicit ZipEntry(const ZipEntryInfo& info) : m_EntryInfo(info)
|
|
158
|
+
{
|
|
159
|
+
// ===== Call GetNewIndex to update the index counter with the getValue in the ZipEntryInfo object.
|
|
160
|
+
GetNewIndex(info.m_file_index); // The return getValue is deliberately not used.
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* @brief Constructor. Creates a new ZipEntry with the given name and binary data. This should only be used for creating
|
|
165
|
+
* new entries, not already present in the ZipArchive
|
|
166
|
+
* @param name The name of the new entry to add to the zip archive.
|
|
167
|
+
* @param data A reference to a ZipEntryData object with the file data to add.
|
|
168
|
+
*/
|
|
169
|
+
ZipEntry(const std::string& name, const ZipEntryData& data)
|
|
170
|
+
{
|
|
171
|
+
// ===== Create new ZipEntryData object
|
|
172
|
+
m_EntryInfo = CreateInfo(name);
|
|
173
|
+
|
|
174
|
+
// ===== Assign the input data to the m_EntryData variable and set the m_IsModified flag to true.
|
|
175
|
+
m_EntryData = data;
|
|
176
|
+
m_IsModified = true;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* @brief Constructor. Creates a new ZipEntry with the given name and string data. This should only be used for creating
|
|
181
|
+
* new entries, not already present in the ZipArchive
|
|
182
|
+
* @param name The name of the new entry to add to the zip archive.
|
|
183
|
+
* @param data A string with the text data to add to the zip archive.
|
|
184
|
+
*/
|
|
185
|
+
ZipEntry(const std::string& name, const std::string& data)
|
|
186
|
+
{
|
|
187
|
+
// ===== Create new ZipEntryData object
|
|
188
|
+
m_EntryInfo = CreateInfo(name);
|
|
189
|
+
|
|
190
|
+
// ===== Copy the string data to the m_EntryData member and set the m_IsModified flag to true.
|
|
191
|
+
m_EntryData.reserve(data.size());
|
|
192
|
+
for (const auto& ch : data) {
|
|
193
|
+
m_EntryData.emplace_back(ch);
|
|
194
|
+
}
|
|
195
|
+
m_IsModified = true;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* @brief Copy Constructor (Deleted)
|
|
200
|
+
* @param other The object to copy.
|
|
201
|
+
* @note The copy constructor has been deleted, because it is not obvious what should happen to the
|
|
202
|
+
* underlying file when copying the entry object.
|
|
203
|
+
*/
|
|
204
|
+
ZipEntry(const ZipEntry& other) = delete;
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* @brief Move Constructor.
|
|
208
|
+
* @param other The object to be moved.
|
|
209
|
+
*/
|
|
210
|
+
ZipEntry(ZipEntry&& other) noexcept = default;
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* @brief Destructor.
|
|
214
|
+
*/
|
|
215
|
+
virtual ~ZipEntry() = default;
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* @brief Copy Assignment Operator (deleted)
|
|
219
|
+
* @param other The object to be copied.
|
|
220
|
+
* @return A reference to the copied-to object.
|
|
221
|
+
* @note The copy assignment operator has been deleted, because it is not obvious what should happen to the
|
|
222
|
+
* underlying file when copying the entry object.
|
|
223
|
+
*/
|
|
224
|
+
ZipEntry& operator=(const ZipEntry& other) = delete;
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* @brief Move Assignment Operator.
|
|
228
|
+
* @param other The object to be moved.
|
|
229
|
+
* @return A reference to the moved-to object.
|
|
230
|
+
*/
|
|
231
|
+
ZipEntry& operator=(ZipEntry&& other) noexcept = default;
|
|
232
|
+
|
|
233
|
+
// ===== Data Access and Manipulation
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* @brief Get data from entry.
|
|
237
|
+
* @return Returns a ZipEntryData (alias for std::vector<std::byte>) object with the fil data.
|
|
238
|
+
*/
|
|
239
|
+
ZipEntryData GetData() const
|
|
240
|
+
{
|
|
241
|
+
return m_EntryData;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* @brief Get entry data as a std::string.
|
|
246
|
+
* @return Returns a std::string with the file data.
|
|
247
|
+
*/
|
|
248
|
+
std::string GetDataAsString() const
|
|
249
|
+
{
|
|
250
|
+
std::string result;
|
|
251
|
+
for (const auto& ch : m_EntryData) {
|
|
252
|
+
result += static_cast<char>(ch);
|
|
253
|
+
} // TODO: Should this use reinterpret_cast instead?
|
|
254
|
+
|
|
255
|
+
return result;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* @brief Set the data for the entry.
|
|
260
|
+
* @param data A std::string with the file data.
|
|
261
|
+
*/
|
|
262
|
+
void SetData(const std::string& data)
|
|
263
|
+
{
|
|
264
|
+
ZipEntryData result;
|
|
265
|
+
|
|
266
|
+
for (const auto& ch : data) {
|
|
267
|
+
result.push_back(ch);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
m_EntryData = result;
|
|
271
|
+
m_IsModified = true;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
/**
|
|
275
|
+
* @brief Set the data for the entry.
|
|
276
|
+
* @param data A ZipEntryData (alias for std::vector<std::byte>) object with the file data.
|
|
277
|
+
*/
|
|
278
|
+
void SetData(const ZipEntryData& data)
|
|
279
|
+
{
|
|
280
|
+
m_EntryData = data;
|
|
281
|
+
m_IsModified = true;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* @brief Get the name of the entry.
|
|
286
|
+
* @return Returns a std::string with the entry name.
|
|
287
|
+
*/
|
|
288
|
+
std::string GetName() const
|
|
289
|
+
{
|
|
290
|
+
return m_EntryInfo.m_filename;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
/**
|
|
294
|
+
* @brief Set the name of the entry.
|
|
295
|
+
* @param name A std::string with the new name of the entry.
|
|
296
|
+
*/
|
|
297
|
+
void SetName(const std::string& name)
|
|
298
|
+
{
|
|
299
|
+
#if _MSC_VER // On MSVC, use the safe version of strcpy
|
|
300
|
+
strcpy_s(m_EntryInfo.m_filename, sizeof m_EntryInfo.m_filename, name.c_str());
|
|
301
|
+
#else // Otherwise, use the unsafe version as fallback :(
|
|
302
|
+
strncpy(m_EntryInfo.m_filename, name.c_str(), sizeof m_EntryInfo.m_filename);
|
|
303
|
+
#endif
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
// ===== Metadata Access
|
|
307
|
+
|
|
308
|
+
/**
|
|
309
|
+
* @brief Get the entry's index in the zip archive.
|
|
310
|
+
* @return Returns a uint32_t with the entry index.
|
|
311
|
+
*/
|
|
312
|
+
uint32_t Index() const
|
|
313
|
+
{
|
|
314
|
+
return m_EntryInfo.m_file_index;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
/**
|
|
318
|
+
* @brief Get the uncompressed size of the entry (in bytes)
|
|
319
|
+
* @return A uint64_t with the uncompressed size.
|
|
320
|
+
*/
|
|
321
|
+
uint64_t CompressedSize() const
|
|
322
|
+
{
|
|
323
|
+
return m_EntryInfo.m_comp_size;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
/**
|
|
327
|
+
* @brief Get the compressed size of the entry (in bytes)
|
|
328
|
+
* @return A uint64_t with the compressed size.
|
|
329
|
+
*/
|
|
330
|
+
uint64_t UncompressedSize() const
|
|
331
|
+
{
|
|
332
|
+
return m_EntryInfo.m_uncomp_size;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
/**
|
|
336
|
+
* @brief Is the zip entry a directory?
|
|
337
|
+
* @return Returns true if the entry is a directory; otherwise false.
|
|
338
|
+
*/
|
|
339
|
+
bool IsDirectory() const
|
|
340
|
+
{
|
|
341
|
+
return m_EntryInfo.m_is_directory;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
/**
|
|
345
|
+
* @brief
|
|
346
|
+
* @return Returns true if the entry is encrypted; otherwise false.
|
|
347
|
+
*/
|
|
348
|
+
bool IsEncrypted() const
|
|
349
|
+
{
|
|
350
|
+
return m_EntryInfo.m_is_encrypted;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
/**
|
|
354
|
+
* @brief Is the zip entry encryption supported?
|
|
355
|
+
* @return Returns true if the entry encryption (if any) is supported by the library; otherwise false.
|
|
356
|
+
*/
|
|
357
|
+
bool IsSupported() const
|
|
358
|
+
{
|
|
359
|
+
return m_EntryInfo.m_is_supported;
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
/**
|
|
363
|
+
* @brief Get the zip entry comments.
|
|
364
|
+
* @return Returns a std::string with the comments.
|
|
365
|
+
*/
|
|
366
|
+
std::string Comment() const
|
|
367
|
+
{
|
|
368
|
+
return m_EntryInfo.m_comment;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
/**
|
|
372
|
+
* @brief Get the zip entry time stamp.
|
|
373
|
+
* @return Returns a time_t object with the time stamp.
|
|
374
|
+
*/
|
|
375
|
+
const time_t& Time() const
|
|
376
|
+
{
|
|
377
|
+
return m_EntryInfo.m_time;
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
private:
|
|
381
|
+
ZipEntryInfo m_EntryInfo = ZipEntryInfo(); /**< The zip entry metadata. */
|
|
382
|
+
ZipEntryData m_EntryData = ZipEntryData(); /**< The zip entry data. */
|
|
383
|
+
|
|
384
|
+
bool m_IsModified = false; /**< Boolean flag indicating if the file has been modified since opening. */
|
|
385
|
+
|
|
386
|
+
/**
|
|
387
|
+
* @brief Has the zip entry been modified?
|
|
388
|
+
* @return Returns true if the entry is has been modified; otherwise false.
|
|
389
|
+
*/
|
|
390
|
+
bool IsModified() const
|
|
391
|
+
{
|
|
392
|
+
return m_IsModified;
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
/**
|
|
396
|
+
* @brief Generate a new file index.
|
|
397
|
+
* @details The file index in existing zip archives may not be incrementing trivially. When opening existing
|
|
398
|
+
* zip archives, this function is simply used to update the index. When adding new entries to an existing
|
|
399
|
+
* archive, this function is guaranteed to provide a unique index.
|
|
400
|
+
* @return Returns a uint32_t (32 bit unsigned int) with the new index.
|
|
401
|
+
*/
|
|
402
|
+
static uint32_t GetNewIndex(uint32_t latestIndex = 0)
|
|
403
|
+
{
|
|
404
|
+
// ===== Set up a static index counter (set to zero the first time the function is executed)
|
|
405
|
+
static uint32_t index { 0 };
|
|
406
|
+
|
|
407
|
+
// ===== If the input value is larger than the current index getValue, set the index equal to the input.
|
|
408
|
+
if (latestIndex > index) {
|
|
409
|
+
index = latestIndex;
|
|
410
|
+
return index;
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
// ===== Increment the index and return the getValue.
|
|
414
|
+
return ++index;
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
/**
|
|
418
|
+
* @brief Create a new ZipEntryInfo structure.
|
|
419
|
+
* @details This function will create a new ZipEntryInfo structure, based on the input file name. The
|
|
420
|
+
* structure values will mostly be dummy values, except for the file index, the time stamp, the file name
|
|
421
|
+
* and the is_directory flag.
|
|
422
|
+
* @param name The file name for the new ZipEntryInfo.
|
|
423
|
+
* @return The newly created ZipEntryInfo structure is returned
|
|
424
|
+
*/
|
|
425
|
+
static ZipEntryInfo CreateInfo(const std::string& name)
|
|
426
|
+
{
|
|
427
|
+
ZipEntryInfo info;
|
|
428
|
+
|
|
429
|
+
info.m_file_index = GetNewIndex(0);
|
|
430
|
+
info.m_central_dir_ofs = 0;
|
|
431
|
+
info.m_version_made_by = 0;
|
|
432
|
+
info.m_version_needed = 0;
|
|
433
|
+
info.m_bit_flag = 0;
|
|
434
|
+
info.m_method = 0;
|
|
435
|
+
info.m_time = time(nullptr);
|
|
436
|
+
info.m_crc32 = 0;
|
|
437
|
+
info.m_comp_size = 0;
|
|
438
|
+
info.m_uncomp_size = 0;
|
|
439
|
+
info.m_internal_attr = 0;
|
|
440
|
+
info.m_external_attr = 0;
|
|
441
|
+
info.m_local_header_ofs = 0;
|
|
442
|
+
info.m_comment_size = 0;
|
|
443
|
+
info.m_is_directory = (name.back() == '/');
|
|
444
|
+
info.m_is_encrypted = false;
|
|
445
|
+
info.m_is_supported = true;
|
|
446
|
+
|
|
447
|
+
#if _MSC_VER // On MSVC, use the safe version of strcpy
|
|
448
|
+
strcpy_s(info.m_filename, sizeof info.m_filename, name.c_str());
|
|
449
|
+
strcpy_s(info.m_comment, sizeof info.m_comment, "");
|
|
450
|
+
#else // Otherwise, use the unsafe version as fallback :(
|
|
451
|
+
strncpy(info.m_filename, name.c_str(), sizeof info.m_filename);
|
|
452
|
+
strncpy(info.m_comment, "", sizeof info.m_comment);
|
|
453
|
+
#endif
|
|
454
|
+
|
|
455
|
+
return info;
|
|
456
|
+
}
|
|
457
|
+
};
|
|
458
|
+
} // namespace Impl
|
|
459
|
+
|
|
460
|
+
/**
|
|
461
|
+
* @brief The ZipEntry class implements the interface required for manipulating entries in a zip archive.
|
|
462
|
+
* @details This is the interface class. The ZipEntry class in the Zippy::Impl namespace implements the private implementation.
|
|
463
|
+
* The reason for having a separate implementation class, is that it enables easy copy and move operations of
|
|
464
|
+
* ZipEntry objects, without duplicating the underlying implementation objects.
|
|
465
|
+
*/
|
|
466
|
+
class ZipEntry
|
|
467
|
+
{
|
|
468
|
+
friend class ZipArchive;
|
|
469
|
+
|
|
470
|
+
public:
|
|
471
|
+
// ===== Constructors, Destructor and Operators
|
|
472
|
+
|
|
473
|
+
/**
|
|
474
|
+
* @brief Constructor. Creates a new ZipEntry.
|
|
475
|
+
* @param entry A raw (non-owning) pointer to the existing Impl::ZipEntry object.
|
|
476
|
+
* @todo Can this be made private?
|
|
477
|
+
*/
|
|
478
|
+
explicit ZipEntry(Impl::ZipEntry* entry) : m_ZipEntry(entry) {}
|
|
479
|
+
|
|
480
|
+
/**
|
|
481
|
+
* @brief Copy Constructor.
|
|
482
|
+
* @param other The object to be copied.
|
|
483
|
+
*/
|
|
484
|
+
ZipEntry(const ZipEntry& other) = default;
|
|
485
|
+
|
|
486
|
+
/**
|
|
487
|
+
* @brief Move Constructor.
|
|
488
|
+
* @param other The object to be moved.
|
|
489
|
+
*/
|
|
490
|
+
ZipEntry(ZipEntry&& other) noexcept = default;
|
|
491
|
+
|
|
492
|
+
/**
|
|
493
|
+
* @brief Destructor
|
|
494
|
+
*/
|
|
495
|
+
virtual ~ZipEntry() = default;
|
|
496
|
+
|
|
497
|
+
/**
|
|
498
|
+
* @brief Copy Assignment Operator.
|
|
499
|
+
* @param other The object to be copied.
|
|
500
|
+
* @return A reference to the copied-to object.
|
|
501
|
+
*/
|
|
502
|
+
ZipEntry& operator=(const ZipEntry& other) = default;
|
|
503
|
+
|
|
504
|
+
/**
|
|
505
|
+
* @brief Move Assignment Operator.
|
|
506
|
+
* @param other The object to be moved.
|
|
507
|
+
* @return A reference to the moved-to object.
|
|
508
|
+
*/
|
|
509
|
+
ZipEntry& operator=(ZipEntry&& other) noexcept = default;
|
|
510
|
+
|
|
511
|
+
// ===== Data Access and Manipulation
|
|
512
|
+
|
|
513
|
+
/**
|
|
514
|
+
* @brief Get data from entry.
|
|
515
|
+
* @return Returns a ZipEntryData (alias for std::vector<std::byte>) object with the file data.
|
|
516
|
+
*/
|
|
517
|
+
ZipEntryData GetData() const
|
|
518
|
+
{
|
|
519
|
+
return m_ZipEntry->GetData();
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
/**
|
|
523
|
+
* @brief Get entry data as a std::string.
|
|
524
|
+
* @return Returns a std::string with the file data.
|
|
525
|
+
*/
|
|
526
|
+
std::string GetDataAsString() const
|
|
527
|
+
{
|
|
528
|
+
return m_ZipEntry->GetDataAsString();
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
/**
|
|
532
|
+
* @brief Set the data for the entry.
|
|
533
|
+
* @param data A std::string with the file data.
|
|
534
|
+
*/
|
|
535
|
+
void SetData(const std::string& data)
|
|
536
|
+
{
|
|
537
|
+
m_ZipEntry->SetData(data);
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
/**
|
|
541
|
+
* @brief Set the data for the entry.
|
|
542
|
+
* @param data A ZipEntryData (alias for std::vector<std::byte>) object with the file data.
|
|
543
|
+
*/
|
|
544
|
+
void SetData(const ZipEntryData& data)
|
|
545
|
+
{
|
|
546
|
+
m_ZipEntry->SetData(data);
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
// ===== Metadata Access
|
|
550
|
+
|
|
551
|
+
/**
|
|
552
|
+
* @brief Get the entry's index in the zip archive.
|
|
553
|
+
* @return Returns a uint32_t with the entry index.
|
|
554
|
+
*/
|
|
555
|
+
uint32_t Index() const
|
|
556
|
+
{
|
|
557
|
+
return m_ZipEntry->Index();
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
/**
|
|
561
|
+
* @brief Get the uncompressed size of the entry (in bytes)
|
|
562
|
+
* @return A uint64_t with the uncompressed size.
|
|
563
|
+
*/
|
|
564
|
+
uint64_t CompressedSize() const
|
|
565
|
+
{
|
|
566
|
+
return m_ZipEntry->CompressedSize();
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
/**
|
|
570
|
+
* @brief Get the compressed size of the entry (in bytes)
|
|
571
|
+
* @return A uint64_t with the compressed size.
|
|
572
|
+
*/
|
|
573
|
+
uint64_t UncompressedSize() const
|
|
574
|
+
{
|
|
575
|
+
return m_ZipEntry->UncompressedSize();
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
/**
|
|
579
|
+
* @brief Is the entry a directory?
|
|
580
|
+
* @return Returns true if the entry is a directory; otherwise false.
|
|
581
|
+
*/
|
|
582
|
+
bool IsDirectory() const
|
|
583
|
+
{
|
|
584
|
+
return m_ZipEntry->IsDirectory();
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
/**
|
|
588
|
+
* @brief Is the zip entry supported?
|
|
589
|
+
* @return Returns true if the entry is encrypted; otherwise false.
|
|
590
|
+
*/
|
|
591
|
+
bool IsEncrypted() const
|
|
592
|
+
{
|
|
593
|
+
return m_ZipEntry->IsEncrypted();
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
/**
|
|
597
|
+
* @brief Is the zip entry encryption supported?
|
|
598
|
+
* @return Returns true if the entry encryption (if any) is supported; otherwise false.
|
|
599
|
+
*/
|
|
600
|
+
bool IsSupported() const
|
|
601
|
+
{
|
|
602
|
+
return m_ZipEntry->IsSupported();
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
/**
|
|
606
|
+
* @brief Get the entry filename.
|
|
607
|
+
* @return Returns a std::string with the filename.
|
|
608
|
+
* @todo Consider renaming to GetName and add a SetName member function.
|
|
609
|
+
*/
|
|
610
|
+
std::string Filename() const
|
|
611
|
+
{
|
|
612
|
+
return m_ZipEntry->GetName();
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
/**
|
|
616
|
+
* @brief Get the zip entry comments.
|
|
617
|
+
* @return Returns a std::string with the comments.
|
|
618
|
+
*/
|
|
619
|
+
std::string Comment() const
|
|
620
|
+
{
|
|
621
|
+
return m_ZipEntry->Comment();
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
/**
|
|
625
|
+
* @brief Get the entry time stamp.
|
|
626
|
+
* @return Returns a time_t object with the time stamp.
|
|
627
|
+
*/
|
|
628
|
+
const time_t& Time() const
|
|
629
|
+
{
|
|
630
|
+
return m_ZipEntry->Time();
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
private:
|
|
634
|
+
/**
|
|
635
|
+
* @brief Has the file been modified?
|
|
636
|
+
* @return Returns true if the entry has been modified; otherwise false.
|
|
637
|
+
*/
|
|
638
|
+
bool IsModified() const
|
|
639
|
+
{
|
|
640
|
+
return m_ZipEntry->IsModified();
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
Impl::ZipEntry* m_ZipEntry; /**< A raw (non-owning) pointer to the implementation object. */
|
|
644
|
+
};
|
|
645
|
+
} // namespace Zippy
|
|
646
|
+
|
|
647
|
+
namespace Zippy
|
|
648
|
+
{
|
|
649
|
+
/**
|
|
650
|
+
* @brief The ZipArchive class represents the zip archive file as a whole. It consists of the individual zip entries, which
|
|
651
|
+
* can be both files and folders. It is the main access point into a .zip archive on disk and can be
|
|
652
|
+
* used to create new archives and to open and modify existing archives.
|
|
653
|
+
* @details
|
|
654
|
+
* #### Implementation and usage details
|
|
655
|
+
* Using the ZipArchive class, it is possible to create new .zip archive files, as well as open and modify existing ones.
|
|
656
|
+
*
|
|
657
|
+
* A ZipArchive object holds a mz_zip_archive object (a miniz struct representing a .zip archive) as well as a std::vector
|
|
658
|
+
* with ZipEntry objects representing each file (entry) in the archive. The actual entry data is lazy-instantiated, so that
|
|
659
|
+
* the data is only loaded from the .zip archive when it is actually needed.
|
|
660
|
+
*
|
|
661
|
+
* The following example shows how a new .zip archive can be created and new entries added.
|
|
662
|
+
* ```cpp
|
|
663
|
+
* int main() {
|
|
664
|
+
*
|
|
665
|
+
* // ===== Creating empty archive
|
|
666
|
+
* Zippy::ZipArchive arch;
|
|
667
|
+
* arch.Create("./TestArchive.zip");
|
|
668
|
+
*
|
|
669
|
+
* // ===== Adding 10 entries to the archive
|
|
670
|
+
* for (int i = 0; i <= 9; ++i)
|
|
671
|
+
* arch.AddEntry(to_string(i) + ".txt", "this is test " + to_string(i));
|
|
672
|
+
*
|
|
673
|
+
* // ===== Delete the first entry
|
|
674
|
+
* arch.DeleteEntry("0.txt");
|
|
675
|
+
*
|
|
676
|
+
* // ===== Save and close the archive
|
|
677
|
+
* arch.Save();
|
|
678
|
+
* arch.Close();
|
|
679
|
+
*
|
|
680
|
+
* // ===== Reopen and check contents
|
|
681
|
+
* arch.Open("./TestArchive.zip");
|
|
682
|
+
* cout << "Number of entries in archive: " << arch.GetNumEntries() << endl;
|
|
683
|
+
* cout << "Content of \"9.txt\": " << endl << arch.GetEntry("9.txt").GetDataAsString();
|
|
684
|
+
*
|
|
685
|
+
* return 0;
|
|
686
|
+
* }
|
|
687
|
+
* ```
|
|
688
|
+
*
|
|
689
|
+
* For further information, please refer to the full API documentation below.
|
|
690
|
+
*
|
|
691
|
+
* Note that the actual files in the .zip archive can be retrieved via the ZipEntry interface, not the ZipArchive interface.
|
|
692
|
+
*/
|
|
693
|
+
class ZipArchive
|
|
694
|
+
{
|
|
695
|
+
public:
|
|
696
|
+
/**
|
|
697
|
+
* @brief Constructor. Constructs a null-archive, which can be used for creating a new .zip file
|
|
698
|
+
* or opening an existing one.
|
|
699
|
+
* @warning Before using an archive object that has been default constructed, a call to either Open() or Create() must be
|
|
700
|
+
* performed. Otherwise, the object will be in a null-state and calls to member functions will be undefined.
|
|
701
|
+
*/
|
|
702
|
+
explicit ZipArchive()
|
|
703
|
+
: m_zipData(nullptr), m_zipSize(0) {}
|
|
704
|
+
|
|
705
|
+
/**
|
|
706
|
+
* @brief Constructor. Constructs an archive object, using the fileName input parameter. If the file already exists,
|
|
707
|
+
* it will be opened. Otherwise, a new object will be created.
|
|
708
|
+
* @details
|
|
709
|
+
* #### Implementation details
|
|
710
|
+
* The constructors tries to open an std::ifstream. If it is valid, it means that a file already exists
|
|
711
|
+
* and will be opened. Otherwise, the file does not exist and will be created.
|
|
712
|
+
* @param fileName The name of the file to open or create.
|
|
713
|
+
*/
|
|
714
|
+
explicit ZipArchive(const std::string& fileName) : m_ArchivePath(fileName)
|
|
715
|
+
{
|
|
716
|
+
// ===== Open file stream
|
|
717
|
+
std::ifstream f(fileName.c_str());
|
|
718
|
+
|
|
719
|
+
// ===== If successful, continue to open the file.
|
|
720
|
+
if (f.good()) {
|
|
721
|
+
f.close();
|
|
722
|
+
Open(fileName);
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
// ===== If unsuccessful, create the archive file and continue.
|
|
726
|
+
else {
|
|
727
|
+
f.close();
|
|
728
|
+
Create(fileName);
|
|
729
|
+
}
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
/**
|
|
733
|
+
* @brief Copy Constructor (deleted).
|
|
734
|
+
* @param other The object to copy.
|
|
735
|
+
* @note The copy constructor has been deleted, because it is not obvious what should happen to the underlying .zip file
|
|
736
|
+
* when copying the archive object. Instead, if sharing of the resource is required, a std::shared_ptr can be used.
|
|
737
|
+
*/
|
|
738
|
+
ZipArchive(const ZipArchive& other) = delete;
|
|
739
|
+
|
|
740
|
+
/**
|
|
741
|
+
* @brief Move Constructor.
|
|
742
|
+
* @param other The object to be moved.
|
|
743
|
+
*/
|
|
744
|
+
ZipArchive(ZipArchive&& other) = default;
|
|
745
|
+
|
|
746
|
+
/**
|
|
747
|
+
* @brief Destructor.
|
|
748
|
+
* @note The destructor will call the Close() member function. If the archive has been modified but not saved,
|
|
749
|
+
* all changes will be discarded.
|
|
750
|
+
*/
|
|
751
|
+
virtual ~ZipArchive()
|
|
752
|
+
{
|
|
753
|
+
Close();
|
|
754
|
+
}
|
|
755
|
+
|
|
756
|
+
/**
|
|
757
|
+
* @brief Copy Assignment Operator (deleted)
|
|
758
|
+
* @param other The object to be copied.
|
|
759
|
+
* @return A reference to the copied-to object.
|
|
760
|
+
* @note The copy assignment operator has been deleted, because it is not obvious what should happen to the underlying
|
|
761
|
+
* .zip file when copying the archive object. Instead, if sharing of the resource is required,
|
|
762
|
+
* a std::shared_ptr can be used.
|
|
763
|
+
*/
|
|
764
|
+
ZipArchive& operator=(const ZipArchive& other) = delete;
|
|
765
|
+
|
|
766
|
+
/**
|
|
767
|
+
* @brief Move Assignment Operator.
|
|
768
|
+
* @param other The object to be moved.
|
|
769
|
+
* @return A reference to the moved-to object.
|
|
770
|
+
*/
|
|
771
|
+
ZipArchive& operator=(ZipArchive&& other) = default;
|
|
772
|
+
|
|
773
|
+
/**
|
|
774
|
+
* @brief Creates a new (empty) archive file with the given filename.
|
|
775
|
+
* @details
|
|
776
|
+
* #### Implementation details
|
|
777
|
+
* A new archive file is created and initialized and thereafter closed, creating an empty archive file.
|
|
778
|
+
* After ensuring that the file is valid (i.e. not somehow corrupted), it is opened using the Open() member function.
|
|
779
|
+
* @param fileName The filename for the new archive.
|
|
780
|
+
*/
|
|
781
|
+
void Create(const std::string& fileName)
|
|
782
|
+
{
|
|
783
|
+
// ===== Prepare an archive file;
|
|
784
|
+
mz_zip_archive archive = mz_zip_archive();
|
|
785
|
+
mz_zip_writer_init_file(&archive, fileName.c_str(), 0);
|
|
786
|
+
|
|
787
|
+
// ===== Finalize and close the temporary archive
|
|
788
|
+
mz_zip_writer_finalize_archive(&archive);
|
|
789
|
+
mz_zip_writer_end(&archive);
|
|
790
|
+
|
|
791
|
+
// ===== Validate the temporary file
|
|
792
|
+
mz_zip_error errordata;
|
|
793
|
+
if (!mz_zip_validate_file_archive(fileName.c_str(), 0, &errordata)) {
|
|
794
|
+
// throw ZipRuntimeError(mz_zip_get_error_string(errordata));
|
|
795
|
+
throw ZipRuntimeError(std::string(mz_zip_get_error_string(errordata)) + " (m_ArchivePath: " + m_ArchivePath + ")");
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
// ===== If everything is OK, open the newly created archive.
|
|
799
|
+
Open(fileName);
|
|
800
|
+
}
|
|
801
|
+
|
|
802
|
+
/**
|
|
803
|
+
* @brief load data from filename into this->m_zipData
|
|
804
|
+
* @param filename load a file from here
|
|
805
|
+
* @return 0 on success, -1 on failure
|
|
806
|
+
* @note 2026-06-01 this function is identical to the one defined in LibZip.hpp
|
|
807
|
+
*/
|
|
808
|
+
int loadArchiveData(std::string filename)
|
|
809
|
+
{
|
|
810
|
+
m_zipSize = 0; // init in case of failure
|
|
811
|
+
|
|
812
|
+
off_t archiveSizeCompressed = OpenXLSX::fileSize( filename );
|
|
813
|
+
if (archiveSizeCompressed < 0) {
|
|
814
|
+
fprintf(stderr, "ZipArchive::loadArchiveData: can't obtain info about %s (errno %d: %s)\n", filename.c_str(), errno, strerror(errno));
|
|
815
|
+
m_zipData = nullptr;
|
|
816
|
+
return -1;
|
|
817
|
+
}
|
|
818
|
+
|
|
819
|
+
if ((m_zipData = malloc(static_cast<size_t>(archiveSizeCompressed))) == nullptr) {
|
|
820
|
+
fprintf(stderr, "ZipArchive::loadArchiveData: can't allocate buffer\n");
|
|
821
|
+
return -1;
|
|
822
|
+
}
|
|
823
|
+
|
|
824
|
+
FILE *fp = OpenXLSX::fopen(filename.c_str(), "rb");
|
|
825
|
+
if (fp == nullptr) {
|
|
826
|
+
free(m_zipData);
|
|
827
|
+
m_zipData = nullptr;
|
|
828
|
+
fprintf(stderr, "ZipArchive::loadArchiveData: can't open %s: %s\n", filename.c_str(), strerror(errno));
|
|
829
|
+
return -1;
|
|
830
|
+
}
|
|
831
|
+
|
|
832
|
+
if (fread(m_zipData, 1, static_cast<size_t>(archiveSizeCompressed), fp) < static_cast<size_t>(archiveSizeCompressed)) {
|
|
833
|
+
free(m_zipData);
|
|
834
|
+
m_zipData = nullptr;
|
|
835
|
+
fprintf(stderr, "ZipArchive::loadArchiveData: can't read %s: %s\n", filename.c_str(), strerror(errno));
|
|
836
|
+
fclose(fp);
|
|
837
|
+
return -1;
|
|
838
|
+
}
|
|
839
|
+
|
|
840
|
+
fclose(fp);
|
|
841
|
+
|
|
842
|
+
m_zipSize = static_cast<size_t>(archiveSizeCompressed);
|
|
843
|
+
return 0;
|
|
844
|
+
}
|
|
845
|
+
|
|
846
|
+
/**
|
|
847
|
+
* @warning unicode filename support on Windows to be tested!
|
|
848
|
+
* @brief Open an existing archive file with the given filename.
|
|
849
|
+
* @details
|
|
850
|
+
* ##### Implementation details
|
|
851
|
+
* The archive file is opened and meta data for all the entries in the archive is loaded into memory.
|
|
852
|
+
* @param fileName The filename of the archive to open.
|
|
853
|
+
* @note If more than one entry with the same name exists in the archive, only the newest one will be loaded.
|
|
854
|
+
* When saving the archive, only the loaded entries will be kept; other entries with the same name will be deleted.
|
|
855
|
+
*/
|
|
856
|
+
void Open(const std::string& fileName)
|
|
857
|
+
{
|
|
858
|
+
// ===== Open the archive file for reading.
|
|
859
|
+
if (m_IsOpen) {
|
|
860
|
+
mz_zip_reader_end(&m_Archive);
|
|
861
|
+
}
|
|
862
|
+
m_ArchivePath = fileName;
|
|
863
|
+
|
|
864
|
+
/* get buffer with zip archive inside */
|
|
865
|
+
if (loadArchiveData(fileName) < 0) {
|
|
866
|
+
using namespace std::literals::string_literals;
|
|
867
|
+
throw ZipRuntimeError("ZipArchive::Open: failed to load archive data from file "s + fileName);
|
|
868
|
+
}
|
|
869
|
+
|
|
870
|
+
// if (!mz_zip_reader_init_file(&m_Archive, m_ArchivePath.c_str(), 0)) { // TBD: does miniz support unicode filenames on Windows?
|
|
871
|
+
if (!mz_zip_reader_init_mem(&m_Archive, m_zipData, m_zipSize, 0)) {
|
|
872
|
+
// throw ZipRuntimeError(mz_zip_get_error_string(m_Archive.m_last_error));
|
|
873
|
+
throw ZipRuntimeError(std::string(mz_zip_get_error_string(m_Archive.m_last_error)) + " (m_ArchivePath: " + m_ArchivePath + ")");
|
|
874
|
+
}
|
|
875
|
+
m_IsOpen = true;
|
|
876
|
+
|
|
877
|
+
// ===== Iterate through the archive and add the entries to the internal data structure
|
|
878
|
+
for (unsigned int i = 0; i < mz_zip_reader_get_num_files(&m_Archive); i++) {
|
|
879
|
+
ZipEntryInfo info;
|
|
880
|
+
if (!mz_zip_reader_file_stat(&m_Archive, i, &info)) {
|
|
881
|
+
// throw ZipRuntimeError(mz_zip_get_error_string(m_Archive.m_last_error));
|
|
882
|
+
throw ZipRuntimeError(std::string(mz_zip_get_error_string(m_Archive.m_last_error)) + " (m_ArchivePath: " + m_ArchivePath + ")");
|
|
883
|
+
}
|
|
884
|
+
|
|
885
|
+
m_ZipEntries.emplace_back(Impl::ZipEntry(info));
|
|
886
|
+
}
|
|
887
|
+
|
|
888
|
+
// ===== Remove entries with identical names. The newest entries will be retained.
|
|
889
|
+
auto isEqual = [](const Impl::ZipEntry& a, const Impl::ZipEntry& b) { return a.GetName() == b.GetName(); };
|
|
890
|
+
std::reverse(m_ZipEntries.begin(), m_ZipEntries.end());
|
|
891
|
+
m_ZipEntries.erase(std::unique(m_ZipEntries.begin(), m_ZipEntries.end(), isEqual), m_ZipEntries.end());
|
|
892
|
+
std::reverse(m_ZipEntries.begin(), m_ZipEntries.end());
|
|
893
|
+
|
|
894
|
+
// ===== Add folder entries if they don't exist
|
|
895
|
+
for (auto& entry : GetEntryNames(false, true)) {
|
|
896
|
+
if (entry.find('/') != std::string::npos) {
|
|
897
|
+
AddEntry(entry.substr(0, entry.rfind('/') + 1), "");
|
|
898
|
+
}
|
|
899
|
+
}
|
|
900
|
+
}
|
|
901
|
+
|
|
902
|
+
/**
|
|
903
|
+
* @brief Close the archive for reading and writing.
|
|
904
|
+
* @note If the archive has been modified but not saved, all changes will be discarded.
|
|
905
|
+
*/
|
|
906
|
+
void Close()
|
|
907
|
+
{
|
|
908
|
+
if (IsOpen()) {
|
|
909
|
+
mz_zip_reader_end(&m_Archive);
|
|
910
|
+
free(m_zipData);
|
|
911
|
+
m_zipData = nullptr; // prevent double-free
|
|
912
|
+
}
|
|
913
|
+
m_ArchivePath = "";
|
|
914
|
+
m_IsOpen = false; // 2024-12-18: minor bugfix, m_IsOpen was not set to false
|
|
915
|
+
m_ZipEntries.clear();
|
|
916
|
+
}
|
|
917
|
+
|
|
918
|
+
/**
|
|
919
|
+
* @brief Checks if the archive file is open for reading and writing.
|
|
920
|
+
* @return true if it is open; otherwise false;
|
|
921
|
+
*/
|
|
922
|
+
bool IsOpen() const
|
|
923
|
+
{
|
|
924
|
+
return m_IsOpen;
|
|
925
|
+
}
|
|
926
|
+
|
|
927
|
+
/**
|
|
928
|
+
* @brief Get a list of the entries in the archive. Depending on the input parameters, the list will include
|
|
929
|
+
* directories, files or both.
|
|
930
|
+
* @param includeDirs If true, the list will include directories; otherwise not. Default is true
|
|
931
|
+
* @param includeFiles If true, the list will include files; otherwise not. Default is true
|
|
932
|
+
* @return A std::vector of std::strings with the entry names.
|
|
933
|
+
*/
|
|
934
|
+
std::vector<std::string> GetEntryNames(bool includeDirs = true, bool includeFiles = true) const
|
|
935
|
+
{
|
|
936
|
+
if (!IsOpen()) throw ZipLogicError("Cannot call GetEntryNames on empty ZipArchive object!");
|
|
937
|
+
|
|
938
|
+
std::vector<std::string> result;
|
|
939
|
+
|
|
940
|
+
// ===== Iterate through all the entries in the archive
|
|
941
|
+
for (auto& item : m_ZipEntries) {
|
|
942
|
+
// ===== If directories should be included and the current entry is a directory, add it to the result.
|
|
943
|
+
if (includeDirs && item.IsDirectory()) {
|
|
944
|
+
result.emplace_back(item.GetName());
|
|
945
|
+
continue;
|
|
946
|
+
}
|
|
947
|
+
|
|
948
|
+
// ===== If files should be included and the current entry is a file, add it to the result.
|
|
949
|
+
if (includeFiles && !item.IsDirectory()) {
|
|
950
|
+
result.emplace_back(item.GetName());
|
|
951
|
+
continue;
|
|
952
|
+
}
|
|
953
|
+
}
|
|
954
|
+
|
|
955
|
+
return result;
|
|
956
|
+
}
|
|
957
|
+
|
|
958
|
+
/**
|
|
959
|
+
* @brief Get a list of the entries in a specific directory of the archive. Depending on the input parameters,
|
|
960
|
+
* the list will include directories, files or both.
|
|
961
|
+
* @details This function behaves slightly different than the GetEntryNames() function. All entries in the
|
|
962
|
+
* requested folder will be returned as absolute paths; however, only one level of subfolders will be returned.
|
|
963
|
+
* @param dir The directory with the entries to get.
|
|
964
|
+
* @param includeDirs If true, the list will include directories; otherwise not. Default is true
|
|
965
|
+
* @param includeFiles If true, the list will include files; otherwise not. Default is true
|
|
966
|
+
* @return A std::vector of std::strings with the entry names. The directory itself is not included.
|
|
967
|
+
*/
|
|
968
|
+
std::vector<std::string> GetEntryNamesInDir(const std::string& dir, bool includeDirs = true, bool includeFiles = true) const
|
|
969
|
+
{
|
|
970
|
+
if (!IsOpen()) throw ZipLogicError("Cannot call GetEntryNamesInDir on empty ZipArchive object!");
|
|
971
|
+
|
|
972
|
+
// ===== Get the full list of entries
|
|
973
|
+
auto result = GetEntryNames(includeDirs, includeFiles);
|
|
974
|
+
|
|
975
|
+
// ===== Remove all entries not in the directory in question, as well as the root directory itself.
|
|
976
|
+
if (!dir.empty()) {
|
|
977
|
+
auto theDir = dir;
|
|
978
|
+
if (theDir.back() != '/') {
|
|
979
|
+
theDir += '/';
|
|
980
|
+
}
|
|
981
|
+
|
|
982
|
+
result.erase(std::remove_if(result.begin(),
|
|
983
|
+
result.end(),
|
|
984
|
+
[&](const std::string& filename) {
|
|
985
|
+
return filename.substr(0, theDir.size()) != theDir || filename == theDir;
|
|
986
|
+
}),
|
|
987
|
+
result.end());
|
|
988
|
+
}
|
|
989
|
+
|
|
990
|
+
// ===== Ensure that only one level of subdirectories are included.
|
|
991
|
+
result.erase(std::remove_if(result.begin(),
|
|
992
|
+
result.end(),
|
|
993
|
+
[&](const std::string& filename) {
|
|
994
|
+
auto subFolderDepth = std::count(filename.begin(), filename.end(), '/');
|
|
995
|
+
auto rootDepth =
|
|
996
|
+
(dir.empty() ? 1
|
|
997
|
+
: (dir.back() == '/' ? std::count(dir.begin(), dir.end(), '/') + 1
|
|
998
|
+
: std::count(dir.begin(), dir.end(), '/') + 2));
|
|
999
|
+
return (subFolderDepth == rootDepth && filename.back() != '/') || (subFolderDepth > rootDepth);
|
|
1000
|
+
}),
|
|
1001
|
+
result.end());
|
|
1002
|
+
|
|
1003
|
+
return result;
|
|
1004
|
+
}
|
|
1005
|
+
|
|
1006
|
+
/**
|
|
1007
|
+
* @brief Get a list of the metadata for entries in the archive. Depending on the input parameters, the list will include
|
|
1008
|
+
* directories, files or both.
|
|
1009
|
+
* @param includeDirs If true, the list will include directories; otherwise not. Default is true
|
|
1010
|
+
* @param includeFiles If true, the list will include files; otherwise not. Default is true
|
|
1011
|
+
* @return A std::vector of ZipEntryMetaData structs with the entry metadata.
|
|
1012
|
+
*/
|
|
1013
|
+
std::vector<ZipEntryMetaData> GetMetaData(bool includeDirs = true, bool includeFiles = true)
|
|
1014
|
+
{
|
|
1015
|
+
if (!IsOpen()) throw ZipLogicError("Cannot call GetMetaData on empty ZipArchive object!");
|
|
1016
|
+
|
|
1017
|
+
std::vector<ZipEntryMetaData> result;
|
|
1018
|
+
for (auto& item : m_ZipEntries) {
|
|
1019
|
+
if (includeDirs && item.IsDirectory()) {
|
|
1020
|
+
result.emplace_back(ZipEntryMetaData(item.m_EntryInfo));
|
|
1021
|
+
continue;
|
|
1022
|
+
}
|
|
1023
|
+
|
|
1024
|
+
if (includeFiles && !item.IsDirectory()) {
|
|
1025
|
+
result.emplace_back(ZipEntryMetaData(item.m_EntryInfo));
|
|
1026
|
+
continue;
|
|
1027
|
+
}
|
|
1028
|
+
}
|
|
1029
|
+
|
|
1030
|
+
return result;
|
|
1031
|
+
}
|
|
1032
|
+
|
|
1033
|
+
/**
|
|
1034
|
+
* @brief Get a list of the metadata for entries in a specific directory of the archive. Depending on the input
|
|
1035
|
+
* parameters, the list will include directories, files or both.
|
|
1036
|
+
* @param dir The directory with the entries to get.
|
|
1037
|
+
* @param includeDirs If true, the list will include directories; otherwise not. Default is true
|
|
1038
|
+
* @param includeFiles If true, the list will include files; otherwise not. Default is true
|
|
1039
|
+
* @return A std::vector of ZipEntryMetaData structs with the entry metadata. The directory itself is not included.
|
|
1040
|
+
*/
|
|
1041
|
+
std::vector<ZipEntryMetaData> GetMetaDataInDir(const std::string& dir, bool includeDirs = true, bool includeFiles = true)
|
|
1042
|
+
{
|
|
1043
|
+
if (!IsOpen()) throw ZipLogicError("Cannot call GetMetaDataInDir on empty ZipArchive object!");
|
|
1044
|
+
|
|
1045
|
+
std::vector<ZipEntryMetaData> result;
|
|
1046
|
+
for (auto& item : m_ZipEntries) {
|
|
1047
|
+
if (item.GetName().substr(0, dir.size()) != dir) {
|
|
1048
|
+
continue;
|
|
1049
|
+
}
|
|
1050
|
+
|
|
1051
|
+
if (includeDirs && item.IsDirectory()) {
|
|
1052
|
+
result.emplace_back(ZipEntryMetaData(item.m_EntryInfo));
|
|
1053
|
+
continue;
|
|
1054
|
+
}
|
|
1055
|
+
|
|
1056
|
+
if (includeFiles && !item.IsDirectory()) {
|
|
1057
|
+
result.emplace_back(ZipEntryMetaData(item.m_EntryInfo));
|
|
1058
|
+
continue;
|
|
1059
|
+
}
|
|
1060
|
+
}
|
|
1061
|
+
|
|
1062
|
+
return result;
|
|
1063
|
+
}
|
|
1064
|
+
|
|
1065
|
+
/**
|
|
1066
|
+
* @brief Get the number of entries in the archive. Depending on the input parameters, the number will include
|
|
1067
|
+
* directories, files or both.
|
|
1068
|
+
* @param includeDirs If true, the number will include directories; otherwise not. Default is true
|
|
1069
|
+
* @param includeFiles If true, the number will include files; otherwise not. Default is true
|
|
1070
|
+
* @return An int with the number of entries.
|
|
1071
|
+
*/
|
|
1072
|
+
int GetNumEntries(bool includeDirs = true, bool includeFiles = true) const
|
|
1073
|
+
{
|
|
1074
|
+
if (!IsOpen()) throw ZipLogicError("Cannot call GetNumEntries on empty ZipArchive object!");
|
|
1075
|
+
|
|
1076
|
+
return GetEntryNames(includeDirs, includeFiles).size();
|
|
1077
|
+
}
|
|
1078
|
+
|
|
1079
|
+
/**
|
|
1080
|
+
* @brief Get the number of entries in a specific directory of the archive. Depending on the input parameters,
|
|
1081
|
+
* the list will include directories, files or both.
|
|
1082
|
+
* @param dir The directory with the entries to get.
|
|
1083
|
+
* @param includeDirs If true, the number will include directories; otherwise not. Default is true.
|
|
1084
|
+
* @param includeFiles If true, the number will include files; otherwise not. Default is true.
|
|
1085
|
+
* @return An int with the number of entries. The directory itself is not included.
|
|
1086
|
+
*/
|
|
1087
|
+
int GetNumEntriesInDir(const std::string& dir, bool includeDirs = true, bool includeFiles = true) const
|
|
1088
|
+
{
|
|
1089
|
+
if (!IsOpen()) throw ZipLogicError("Cannot call GetNumEntriesInDir on empty ZipArchive object!");
|
|
1090
|
+
|
|
1091
|
+
return GetEntryNamesInDir(dir, includeDirs, includeFiles).size();
|
|
1092
|
+
}
|
|
1093
|
+
|
|
1094
|
+
/**
|
|
1095
|
+
* @brief Check if an entry with a given name exists in the archive.
|
|
1096
|
+
* @param entryName The name of the entry to check for.
|
|
1097
|
+
* @return true if it exists; otherwise false;
|
|
1098
|
+
*/
|
|
1099
|
+
bool HasEntry(const std::string& entryName) const
|
|
1100
|
+
{
|
|
1101
|
+
if (!IsOpen()) throw ZipLogicError("Cannot call HasEntry on empty ZipArchive object!");
|
|
1102
|
+
|
|
1103
|
+
auto result = GetEntryNames(true, true);
|
|
1104
|
+
return std::find(result.begin(), result.end(), entryName) != result.end();
|
|
1105
|
+
}
|
|
1106
|
+
|
|
1107
|
+
/**
|
|
1108
|
+
* @brief Save the archive with a new name. The original archive will remain unchanged.
|
|
1109
|
+
* @param filename The new filename.
|
|
1110
|
+
* @note If no filename is provided, the file will be saved with the existing name, overwriting any existing data.
|
|
1111
|
+
* @throws ZipException A ZipException object is thrown if calls to miniz function fails.
|
|
1112
|
+
*/
|
|
1113
|
+
void Save(std::string filename = "")
|
|
1114
|
+
{
|
|
1115
|
+
if (!IsOpen()) throw ZipLogicError("Cannot call Save on empty ZipArchive object!");
|
|
1116
|
+
|
|
1117
|
+
if (filename.empty()) {
|
|
1118
|
+
filename = m_ArchivePath;
|
|
1119
|
+
}
|
|
1120
|
+
|
|
1121
|
+
// ===== Generate a random file name with the same path as the current file
|
|
1122
|
+
std::string tempPath = OpenXLSX::GenerateRandomNameInSamePath(filename, 20);
|
|
1123
|
+
|
|
1124
|
+
// ===== Prepare an temporary archive file with the random filename;
|
|
1125
|
+
mz_zip_archive tempArchive = mz_zip_archive();
|
|
1126
|
+
if (!mz_zip_writer_init_file(&tempArchive, tempPath.c_str(), 0)) // pull request #210
|
|
1127
|
+
throw ZipRuntimeError(mz_zip_get_error_string(tempArchive.m_last_error)); // "
|
|
1128
|
+
|
|
1129
|
+
// ===== Iterate through the ZipEntries and add entries to the temporary file
|
|
1130
|
+
for (auto& file : m_ZipEntries) {
|
|
1131
|
+
if (file.IsDirectory()) continue; // TODO: Ensure this is the right thing to do (Excel issue)
|
|
1132
|
+
if (!file.IsModified()) {
|
|
1133
|
+
if (!mz_zip_writer_add_from_zip_reader(&tempArchive, &m_Archive, file.Index())) {
|
|
1134
|
+
throw ZipRuntimeError(mz_zip_get_error_string(m_Archive.m_last_error));
|
|
1135
|
+
}
|
|
1136
|
+
}
|
|
1137
|
+
|
|
1138
|
+
else {
|
|
1139
|
+
if (!mz_zip_writer_add_mem(&tempArchive,
|
|
1140
|
+
file.GetName().c_str(),
|
|
1141
|
+
file.m_EntryData.data(),
|
|
1142
|
+
file.m_EntryData.size(),
|
|
1143
|
+
MZ_DEFAULT_COMPRESSION)) {
|
|
1144
|
+
throw ZipRuntimeError(mz_zip_get_error_string(m_Archive.m_last_error));
|
|
1145
|
+
}
|
|
1146
|
+
}
|
|
1147
|
+
}
|
|
1148
|
+
|
|
1149
|
+
// ===== Finalize and close the temporary archive
|
|
1150
|
+
mz_zip_writer_finalize_archive(&tempArchive);
|
|
1151
|
+
mz_zip_writer_end(&tempArchive);
|
|
1152
|
+
|
|
1153
|
+
// ===== Validate the temporary file
|
|
1154
|
+
mz_zip_error errordata;
|
|
1155
|
+
if (!mz_zip_validate_file_archive(tempPath.c_str(), 0, &errordata)) {
|
|
1156
|
+
throw ZipRuntimeError(mz_zip_get_error_string(errordata));
|
|
1157
|
+
}
|
|
1158
|
+
|
|
1159
|
+
// ===== Close the current archive, delete the file with input filename (if it exists), rename the temporary and call Open.
|
|
1160
|
+
Close();
|
|
1161
|
+
OpenXLSX::remove(filename.c_str());
|
|
1162
|
+
OpenXLSX::rename(tempPath.c_str(), filename.c_str()); // forward to function supporting unicode on Windows
|
|
1163
|
+
Open(filename);
|
|
1164
|
+
}
|
|
1165
|
+
|
|
1166
|
+
/**
|
|
1167
|
+
* @brief
|
|
1168
|
+
* @param stream
|
|
1169
|
+
*/
|
|
1170
|
+
void Save(std::ostream& stream)
|
|
1171
|
+
{
|
|
1172
|
+
if (!IsOpen()) throw ZipLogicError("Cannot call ZipArchive::Save(std::ostream&) on empty ZipArchive object!");
|
|
1173
|
+
throw ZipLogicError("ZipArchive::Save(std::ostream&) is not yet implemented!"); // TODO: To be implemented
|
|
1174
|
+
(void) stream; // 2024-08-18: suppress -Wunused-parameter
|
|
1175
|
+
}
|
|
1176
|
+
|
|
1177
|
+
/**
|
|
1178
|
+
* @brief Deletes an entry from the archive.
|
|
1179
|
+
* @param name The name of the entry to delete.
|
|
1180
|
+
*/
|
|
1181
|
+
void DeleteEntry(const std::string& name)
|
|
1182
|
+
{
|
|
1183
|
+
if (!IsOpen()) throw ZipLogicError("Cannot call DeleteEntry on empty ZipArchive object!");
|
|
1184
|
+
|
|
1185
|
+
m_ZipEntries.erase(std::remove_if(m_ZipEntries.begin(),
|
|
1186
|
+
m_ZipEntries.end(),
|
|
1187
|
+
[&](const Impl::ZipEntry& entry) { return name == entry.GetName(); }),
|
|
1188
|
+
m_ZipEntries.end());
|
|
1189
|
+
}
|
|
1190
|
+
|
|
1191
|
+
/**
|
|
1192
|
+
* @brief Get the entry with the specified name.
|
|
1193
|
+
* @param name The name of the entry in the archive.
|
|
1194
|
+
* @return A ZipEntry object with the requested entry.
|
|
1195
|
+
*/
|
|
1196
|
+
ZipEntry GetEntry(const std::string& name)
|
|
1197
|
+
{
|
|
1198
|
+
if (!IsOpen()) throw ZipLogicError("Cannot call GetEntry on empty ZipArchive object!");
|
|
1199
|
+
|
|
1200
|
+
// ===== Look up ZipEntry object.
|
|
1201
|
+
auto result = std::find_if(m_ZipEntries.begin(), m_ZipEntries.end(), [&](const Impl::ZipEntry& entry) {
|
|
1202
|
+
return name == entry.GetName();
|
|
1203
|
+
});
|
|
1204
|
+
|
|
1205
|
+
// ===== If data has not been extracted from the archive (i.e., m_EntryData is empty),
|
|
1206
|
+
// ===== extract the data from the archive to the ZipEntry object.
|
|
1207
|
+
if (result->m_EntryData.empty()) {
|
|
1208
|
+
if (result->UncompressedSize())
|
|
1209
|
+
result->m_EntryData.resize(result->UncompressedSize());
|
|
1210
|
+
else
|
|
1211
|
+
result->m_EntryData.resize(1); // 2024-06-03 BUFIX: std::vector::data() can be nullptr when ::size() is 0, leading to a failure to load an empty file
|
|
1212
|
+
mz_zip_reader_extract_file_to_mem(&m_Archive, name.c_str(), result->m_EntryData.data(), result->m_EntryData.size(), 0);
|
|
1213
|
+
}
|
|
1214
|
+
|
|
1215
|
+
// ===== Check that the operation was successful
|
|
1216
|
+
if (!result->IsDirectory() && result->m_EntryData.data() == nullptr) {
|
|
1217
|
+
throw ZipRuntimeError(mz_zip_get_error_string(m_Archive.m_last_error));
|
|
1218
|
+
}
|
|
1219
|
+
|
|
1220
|
+
// ===== Return ZipEntry object with the file data.
|
|
1221
|
+
return ZipEntry(&*result);
|
|
1222
|
+
}
|
|
1223
|
+
|
|
1224
|
+
/**
|
|
1225
|
+
* @brief Extract the entry with the provided name to the destination path.
|
|
1226
|
+
* @param name The name of the entry to extract.
|
|
1227
|
+
* @param dest The path to extract the entry to.
|
|
1228
|
+
*/
|
|
1229
|
+
void ExtractEntry(const std::string& name, const std::string& dest)
|
|
1230
|
+
{
|
|
1231
|
+
if (!IsOpen()) throw ZipLogicError("Cannot call ExtractEntry on empty ZipArchive object!");
|
|
1232
|
+
|
|
1233
|
+
auto entry = GetEntry(name);
|
|
1234
|
+
|
|
1235
|
+
// ===== If the entry is a directory, create the directory as a subdirectory to dest
|
|
1236
|
+
if (entry.IsDirectory()) {
|
|
1237
|
+
#ifdef _WIN32
|
|
1238
|
+
_mkdir((dest + entry.Filename()).c_str());
|
|
1239
|
+
#else
|
|
1240
|
+
mkdir((dest + entry.Filename()).c_str(), 0733);
|
|
1241
|
+
#endif
|
|
1242
|
+
}
|
|
1243
|
+
|
|
1244
|
+
// ===== If the entry is a file, stream the entry data to a file.
|
|
1245
|
+
else {
|
|
1246
|
+
std::ofstream output(dest + "/" + entry.Filename(), std::ios::binary);
|
|
1247
|
+
for (auto ch : entry.GetData()) {
|
|
1248
|
+
output << static_cast<unsigned char>(ch);
|
|
1249
|
+
}
|
|
1250
|
+
output.close();
|
|
1251
|
+
}
|
|
1252
|
+
}
|
|
1253
|
+
|
|
1254
|
+
/**
|
|
1255
|
+
* @brief Extract all entries in the given directory to the destination path.
|
|
1256
|
+
* @param dir The name of the directory to extract.
|
|
1257
|
+
* @param dest The path to extract the entry to.
|
|
1258
|
+
* @todo To be implemented
|
|
1259
|
+
*/
|
|
1260
|
+
void ExtractDir(const std::string& dir, const std::string& dest)
|
|
1261
|
+
{
|
|
1262
|
+
if (!IsOpen()) throw ZipLogicError("Cannot call ZipArchive::ExtractDir(const std::string&, const std::string&) on empty ZipArchive object!");
|
|
1263
|
+
throw ZipLogicError("ZipArchive::ExtractDir(const std::string&, const std::string&) is not yet implemented!"); // TODO: To be implemented
|
|
1264
|
+
(void) dir; (void) dest; // 2024-08-18: suppress -Wunused-parameter
|
|
1265
|
+
}
|
|
1266
|
+
|
|
1267
|
+
/**
|
|
1268
|
+
* @brief Extract all archive contents to the destination path.
|
|
1269
|
+
* @param dest The path to extract the entry to.
|
|
1270
|
+
* @todo To be implemented
|
|
1271
|
+
*/
|
|
1272
|
+
void ExtractAll(const std::string& dest)
|
|
1273
|
+
{
|
|
1274
|
+
if (!IsOpen()) throw ZipLogicError("Cannot call ZipArchive::ExtractAll(const std::string&) on empty ZipArchive object!");
|
|
1275
|
+
throw ZipLogicError("ZipArchive::ExtractAll(std::string const &) is not yet implemented!"); // TODO: To be implemented
|
|
1276
|
+
(void) dest; // 2024-08-18: suppress -Wunused-parameter
|
|
1277
|
+
}
|
|
1278
|
+
|
|
1279
|
+
/**
|
|
1280
|
+
* @brief Add a new entry to the archive.
|
|
1281
|
+
* @param name The name of the entry to add.
|
|
1282
|
+
* @param data The ZipEntryData to add. This is an alias of a std::vector<std::byte>, holding the binary data of the entry.
|
|
1283
|
+
* @return The ZipEntry object that has been added to the archive.
|
|
1284
|
+
* @note If an entry with given name already exists, it will be overwritten.
|
|
1285
|
+
*/
|
|
1286
|
+
ZipEntry AddEntry(const std::string& name, const ZipEntryData& data)
|
|
1287
|
+
{
|
|
1288
|
+
return AddEntryImpl(name, data);
|
|
1289
|
+
}
|
|
1290
|
+
|
|
1291
|
+
/**
|
|
1292
|
+
* @brief Add a new entry to the archive.
|
|
1293
|
+
* @param name The name of the entry to add.
|
|
1294
|
+
* @param data The std::string data to add.
|
|
1295
|
+
* @return The ZipEntry object that has been added to the archive.
|
|
1296
|
+
* @note If an entry with given name already exists, it will be overwritten.
|
|
1297
|
+
*/
|
|
1298
|
+
ZipEntry AddEntry(const std::string& name, const std::string& data)
|
|
1299
|
+
{
|
|
1300
|
+
ZipEntryData stringData;
|
|
1301
|
+
stringData.reserve(data.size());
|
|
1302
|
+
for (const auto& ch : data) {
|
|
1303
|
+
stringData.emplace_back(ch);
|
|
1304
|
+
}
|
|
1305
|
+
|
|
1306
|
+
return AddEntryImpl(name, stringData);
|
|
1307
|
+
}
|
|
1308
|
+
|
|
1309
|
+
/**
|
|
1310
|
+
* @brief Add a new entry to the archive, using another entry as input. This is mostly used for cloning existing entries
|
|
1311
|
+
* in the same archive, or for copying entries from one archive to another.
|
|
1312
|
+
* @param name The name of the entry to add.
|
|
1313
|
+
* @param entry The ZipEntry to add.
|
|
1314
|
+
* @return The ZipEntry object that has been added to the archive.
|
|
1315
|
+
* @note If an entry with given name already exists, it will be overwritten.
|
|
1316
|
+
*/
|
|
1317
|
+
ZipEntry AddEntry(const std::string& name, const ZipEntry& entry)
|
|
1318
|
+
{
|
|
1319
|
+
return AddEntryImpl(name, entry.GetData());
|
|
1320
|
+
}
|
|
1321
|
+
|
|
1322
|
+
private:
|
|
1323
|
+
/**
|
|
1324
|
+
* @brief Add a new entry to the archive.
|
|
1325
|
+
* @param name The name of the entry to add.
|
|
1326
|
+
* @param data The ZipEntryData to add. This is an alias of a std::vector<std::byte>, holding the binary data of the entry.
|
|
1327
|
+
* @return The ZipEntry object that has been added to the archive.
|
|
1328
|
+
* @note If an entry with given name already exists, it will be overwritten.
|
|
1329
|
+
*/
|
|
1330
|
+
ZipEntry AddEntryImpl(const std::string& name, const ZipEntryData& data)
|
|
1331
|
+
{
|
|
1332
|
+
if (!IsOpen()) throw ZipLogicError("Cannot call AddEntry on empty ZipArchive object!");
|
|
1333
|
+
|
|
1334
|
+
// ===== Ensure that all folders and subfolders have an entry in the archive
|
|
1335
|
+
auto folders = GetEntryNames(true, false);
|
|
1336
|
+
auto pos = 0;
|
|
1337
|
+
while (name.find('/', pos) != std::string::npos) {
|
|
1338
|
+
pos = name.find('/', pos) + 1;
|
|
1339
|
+
auto folder = name.substr(0, pos);
|
|
1340
|
+
|
|
1341
|
+
// ===== If folder isn't registered in the archive, add it.
|
|
1342
|
+
if (std::find(folders.begin(), folders.end(), folder) == folders.end()) {
|
|
1343
|
+
m_ZipEntries.emplace_back(Impl::ZipEntry(folder, ""));
|
|
1344
|
+
folders.emplace_back(folder);
|
|
1345
|
+
}
|
|
1346
|
+
}
|
|
1347
|
+
|
|
1348
|
+
// ===== Check if an entry with the given name already exists in the archive.
|
|
1349
|
+
auto result = std::find_if(m_ZipEntries.begin(), m_ZipEntries.end(), [&](const Impl::ZipEntry& entry) {
|
|
1350
|
+
return name == entry.GetName();
|
|
1351
|
+
});
|
|
1352
|
+
|
|
1353
|
+
// ===== If the entry exists, replace the existing data with the new data, and return the ZipEntry object.
|
|
1354
|
+
if (result != m_ZipEntries.end()) {
|
|
1355
|
+
result->SetData(data);
|
|
1356
|
+
return ZipEntry(&*result);
|
|
1357
|
+
}
|
|
1358
|
+
|
|
1359
|
+
// ===== Finally, add a new entry with the given name and data, and return the object.
|
|
1360
|
+
return ZipEntry(&m_ZipEntries.emplace_back(Impl::ZipEntry(name, data)));
|
|
1361
|
+
}
|
|
1362
|
+
|
|
1363
|
+
private:
|
|
1364
|
+
void *m_zipData; // the raw data of the unmodified source archive, TODO: (re-)set on ZipArchive::Open
|
|
1365
|
+
size_t m_zipSize; // the size in bytes of the unmodified source archive stored at m_zipData
|
|
1366
|
+
mz_zip_archive m_Archive = mz_zip_archive(); /**< The struct used by miniz, to handle archive files. */
|
|
1367
|
+
std::string m_ArchivePath = ""; /**< The path of the archive file. */
|
|
1368
|
+
bool m_IsOpen = false; /**< A flag indicating if the file is currently open for reading and writing. */
|
|
1369
|
+
|
|
1370
|
+
std::vector<Impl::ZipEntry> m_ZipEntries = std::vector<Impl::ZipEntry>(); /**< Data structure for all entries in the archive. */
|
|
1371
|
+
};
|
|
1372
|
+
} // namespace Zippy
|
|
1373
|
+
|
|
1374
|
+
|
|
1375
|
+
#endif // ZIPPY2_LIBRARY_H
|