react-native-nitro-xlsx 0.1.4 → 0.2.6

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.
Files changed (428) hide show
  1. package/NitroXlsx.podspec +27 -27
  2. package/Package.swift +35 -10
  3. package/README.md +220 -58
  4. package/android/CMakeLists.txt +24 -27
  5. package/android/cpp-adapter.cpp +12 -0
  6. package/android/src/main/java/com/margelo/nitro/xlsx/NitroXlsxPackage.kt +9 -0
  7. package/cpp/HybridNitroXlsx.cpp +25 -179
  8. package/cpp/HybridNitroXlsx.hpp +2 -2
  9. package/cpp/HybridXlsxConditionalFormat.cpp +252 -0
  10. package/cpp/HybridXlsxConditionalFormat.hpp +62 -0
  11. package/cpp/HybridXlsxConditionalFormats.cpp +46 -0
  12. package/cpp/HybridXlsxConditionalFormats.hpp +28 -0
  13. package/cpp/HybridXlsxWorkbook.cpp +159 -196
  14. package/cpp/HybridXlsxWorkbook.hpp +7 -2
  15. package/cpp/HybridXlsxWorksheet.cpp +433 -62
  16. package/cpp/HybridXlsxWorksheet.hpp +73 -26
  17. package/cpp/XlsxCacheDir.cpp +76 -0
  18. package/cpp/XlsxCacheDir.hpp +27 -0
  19. package/cpp/XlsxError.hpp +68 -0
  20. package/cpp/XlsxJson.cpp +185 -0
  21. package/cpp/XlsxJson.hpp +36 -0
  22. package/ios/XlsxCacheDir.mm +60 -0
  23. package/nitrogen/generated/android/NitroXlsx+autolinking.cmake +2 -0
  24. package/nitrogen/generated/shared/c++/HybridNitroXlsxSpec.hpp +5 -3
  25. package/nitrogen/generated/shared/c++/HybridXlsxConditionalFormatSpec.cpp +54 -0
  26. package/nitrogen/generated/shared/c++/HybridXlsxConditionalFormatSpec.hpp +95 -0
  27. package/nitrogen/generated/shared/c++/HybridXlsxConditionalFormatsSpec.cpp +24 -0
  28. package/nitrogen/generated/shared/c++/HybridXlsxConditionalFormatsSpec.hpp +68 -0
  29. package/nitrogen/generated/shared/c++/HybridXlsxWorkbookSpec.cpp +3 -0
  30. package/nitrogen/generated/shared/c++/HybridXlsxWorkbookSpec.hpp +6 -1
  31. package/nitrogen/generated/shared/c++/HybridXlsxWorksheetSpec.cpp +47 -19
  32. package/nitrogen/generated/shared/c++/HybridXlsxWorksheetSpec.hpp +52 -20
  33. package/package.json +3 -3
  34. package/scripts/run-cpp-tests.sh +14 -0
  35. package/src/__mocks__/react-native-nitro-modules.ts +1 -0
  36. package/src/__tests__/index.test.ts +76 -7
  37. package/src/index.ts +107 -18
  38. package/src/specs/NitroXlsx.nitro.ts +141 -44
  39. package/thirdparty/OpenXLSX/.clang-format +118 -0
  40. package/thirdparty/OpenXLSX/.clang-tidy +28 -0
  41. package/thirdparty/OpenXLSX/.gitignore +130 -0
  42. package/thirdparty/OpenXLSX/Benchmarks/2024-07-29-benchmarks_before_XMLNode_wrappers +46 -0
  43. package/thirdparty/OpenXLSX/Benchmarks/2024-07-29-benchmarks_with_XMLNode_wrappers_and_namespace_and_stripping +49 -0
  44. package/thirdparty/OpenXLSX/Benchmarks/2024-07-29-benchmarks_with_XMLNode_wrappers_and_namespace_char_support +49 -0
  45. package/thirdparty/OpenXLSX/Benchmarks/2024-07-29-benchmarks_with_XMLNode_wrappers_and_namespace_support +49 -0
  46. package/thirdparty/OpenXLSX/Benchmarks/2024-07-29-benchmarks_with_XMLNode_wrappers_and_namespaced_name_disabled +49 -0
  47. package/thirdparty/OpenXLSX/Benchmarks/2024-08-11-benchmarks_post-XLCellIterator-Rework +46 -0
  48. package/thirdparty/OpenXLSX/Benchmarks/2024-08-14-benchmarks_post-default-row-column-style-support +46 -0
  49. package/thirdparty/OpenXLSX/Benchmarks/2024-09-02-benchmarks +46 -0
  50. package/thirdparty/OpenXLSX/Benchmarks/2024-12-19-benchmarks +46 -0
  51. package/thirdparty/OpenXLSX/Benchmarks/2024-12-30-benchmarks-post-XLSharedStrings-by-ref +46 -0
  52. package/thirdparty/OpenXLSX/Benchmarks/2025-01-09-benchmarks-post-conditionalFormatsAndSheetProtection +46 -0
  53. package/thirdparty/OpenXLSX/Benchmarks/2025-01-10-benchmarks-post-XLCellValue-bugfix +46 -0
  54. package/thirdparty/OpenXLSX/Benchmarks/2025-01-31-benchmarks-post-XLComments-implementation +46 -0
  55. package/thirdparty/OpenXLSX/Benchmarks/2025-02-02-benchmarks-post-XLRowIterator-Rework +46 -0
  56. package/thirdparty/OpenXLSX/Benchmarks/2025-07-20-benchmarks-after-hiding-pugixml-internals +46 -0
  57. package/thirdparty/OpenXLSX/Benchmarks/2025-08-29-benchmarks-after-code-review-with-libzip +46 -0
  58. package/thirdparty/OpenXLSX/Benchmarks/Benchmark.cpp +249 -0
  59. package/thirdparty/OpenXLSX/Benchmarks/CMakeLists.txt +19 -0
  60. package/thirdparty/OpenXLSX/CMakeLists.txt +466 -0
  61. package/thirdparty/OpenXLSX/Documentation/CMakeLists.txt +31 -0
  62. package/thirdparty/OpenXLSX/Documentation/Doxyfile.in +2471 -0
  63. package/thirdparty/OpenXLSX/Documentation/DoxygenLayout.xml +194 -0
  64. package/thirdparty/OpenXLSX/Documentation/customdoxygen.css +1355 -0
  65. package/thirdparty/OpenXLSX/Examples/CMakeLists.txt +103 -0
  66. package/thirdparty/OpenXLSX/Examples/Demo1.cpp +279 -0
  67. package/thirdparty/OpenXLSX/Examples/Demo10.cpp +545 -0
  68. package/thirdparty/OpenXLSX/Examples/Demo1A.cpp +137 -0
  69. package/thirdparty/OpenXLSX/Examples/Demo2.cpp +65 -0
  70. package/thirdparty/OpenXLSX/Examples/Demo3.cpp +89 -0
  71. package/thirdparty/OpenXLSX/Examples/Demo4.cpp +86 -0
  72. package/thirdparty/OpenXLSX/Examples/Demo5.cpp +77 -0
  73. package/thirdparty/OpenXLSX/Examples/Demo6.cpp +103 -0
  74. package/thirdparty/OpenXLSX/Examples/Demo7.cpp +79 -0
  75. package/thirdparty/OpenXLSX/Examples/Demo8.cpp +117 -0
  76. package/thirdparty/OpenXLSX/Examples/Demo9.cpp +363 -0
  77. package/thirdparty/OpenXLSX/Examples/cmake/FindLIBZIP.cmake +61 -0
  78. package/thirdparty/OpenXLSX/Examples/external/CustomZip/CustomZip.hpp +256 -0
  79. package/thirdparty/OpenXLSX/LICENSE.md +29 -0
  80. package/thirdparty/OpenXLSX/Makefile.GNU +530 -0
  81. package/thirdparty/OpenXLSX/Notes/TBDs.txt +16 -0
  82. package/thirdparty/OpenXLSX/Notes/confirmed-TBCs.txt +8 -0
  83. package/thirdparty/OpenXLSX/Notes/styles-missing-support.xml +12 -0
  84. package/thirdparty/OpenXLSX/Notes/todo-list.txt +108 -0
  85. package/thirdparty/OpenXLSX/OpenXLSX/CMakeLists.txt +631 -0
  86. package/thirdparty/OpenXLSX/OpenXLSX/OpenXLSX.hpp +63 -0
  87. package/thirdparty/OpenXLSX/OpenXLSX/OpenXLSXConfig.cmake +11 -0
  88. package/thirdparty/OpenXLSX/OpenXLSX/cmake/bundle_static_library.cmake +198 -0
  89. package/thirdparty/OpenXLSX/OpenXLSX/cmake/patch_pkg_config.cmake +69 -0
  90. package/thirdparty/OpenXLSX/OpenXLSX/headers/IZipArchive.hpp +361 -0
  91. package/thirdparty/OpenXLSX/OpenXLSX/headers/OpenXLSX-Exports.hpp +12 -0
  92. package/thirdparty/OpenXLSX/OpenXLSX/headers/XLCell.hpp +367 -0
  93. package/thirdparty/OpenXLSX/OpenXLSX/headers/XLCellIterator.hpp +252 -0
  94. package/thirdparty/OpenXLSX/OpenXLSX/headers/XLCellRange.hpp +223 -0
  95. package/thirdparty/OpenXLSX/OpenXLSX/headers/XLCellReference.hpp +317 -0
  96. package/thirdparty/OpenXLSX/OpenXLSX/headers/XLCellValue.hpp +793 -0
  97. package/thirdparty/OpenXLSX/OpenXLSX/headers/XLColor.hpp +232 -0
  98. package/thirdparty/OpenXLSX/OpenXLSX/headers/XLColumn.hpp +159 -0
  99. package/thirdparty/OpenXLSX/OpenXLSX/headers/XLCommandQuery.hpp +228 -0
  100. package/thirdparty/OpenXLSX/OpenXLSX/headers/XLComments.hpp +270 -0
  101. package/thirdparty/OpenXLSX/OpenXLSX/headers/XLConstants.hpp +18 -0
  102. package/thirdparty/OpenXLSX/OpenXLSX/headers/XLContentTypes.hpp +264 -0
  103. package/thirdparty/OpenXLSX/OpenXLSX/headers/XLDateTime.hpp +175 -0
  104. package/thirdparty/OpenXLSX/OpenXLSX/headers/XLDocument.hpp +505 -0
  105. package/thirdparty/OpenXLSX/OpenXLSX/headers/XLDrawing.hpp +452 -0
  106. package/thirdparty/OpenXLSX/OpenXLSX/headers/XLException.hpp +161 -0
  107. package/thirdparty/OpenXLSX/OpenXLSX/headers/XLFormula.hpp +375 -0
  108. package/thirdparty/OpenXLSX/OpenXLSX/headers/XLIterator.hpp +40 -0
  109. package/thirdparty/OpenXLSX/OpenXLSX/headers/XLMergeCells.hpp +216 -0
  110. package/thirdparty/OpenXLSX/OpenXLSX/headers/XLProperties.hpp +348 -0
  111. package/thirdparty/OpenXLSX/OpenXLSX/headers/XLRelationships.hpp +348 -0
  112. package/thirdparty/OpenXLSX/OpenXLSX/headers/XLRow.hpp +721 -0
  113. package/thirdparty/OpenXLSX/OpenXLSX/headers/XLRowData.hpp +488 -0
  114. package/thirdparty/OpenXLSX/OpenXLSX/headers/XLSharedStrings.hpp +204 -0
  115. package/thirdparty/OpenXLSX/OpenXLSX/headers/XLSheet.hpp +1640 -0
  116. package/thirdparty/OpenXLSX/OpenXLSX/headers/XLStyles.hpp +2390 -0
  117. package/thirdparty/OpenXLSX/OpenXLSX/headers/XLTables.hpp +132 -0
  118. package/thirdparty/OpenXLSX/OpenXLSX/headers/XLWorkbook.hpp +404 -0
  119. package/thirdparty/OpenXLSX/OpenXLSX/headers/XLXmlData.hpp +283 -0
  120. package/thirdparty/OpenXLSX/OpenXLSX/headers/XLXmlFile.hpp +194 -0
  121. package/thirdparty/OpenXLSX/OpenXLSX/headers/XLXmlParser.hpp +282 -0
  122. package/thirdparty/OpenXLSX/OpenXLSX/headers/XLXmlParserForwardDeclarations.hpp +85 -0
  123. package/thirdparty/OpenXLSX/OpenXLSX/headers/XLZipArchive.hpp +232 -0
  124. package/thirdparty/OpenXLSX/OpenXLSX/headers/detail/LibZip.hpp +447 -0
  125. package/thirdparty/OpenXLSX/OpenXLSX/headers/detail/OpenXLSXFileSystemTools.hpp +207 -0
  126. package/thirdparty/OpenXLSX/OpenXLSX/headers/detail/Zippy.hpp +1375 -0
  127. package/thirdparty/OpenXLSX/OpenXLSX/sources/XLCell.cpp +340 -0
  128. package/thirdparty/OpenXLSX/OpenXLSX/sources/XLCellIterator.cpp +427 -0
  129. package/thirdparty/OpenXLSX/OpenXLSX/sources/XLCellRange.cpp +221 -0
  130. package/thirdparty/OpenXLSX/OpenXLSX/sources/XLCellReference.cpp +408 -0
  131. package/thirdparty/OpenXLSX/OpenXLSX/sources/XLCellValue.cpp +519 -0
  132. package/thirdparty/OpenXLSX/OpenXLSX/sources/XLColor.cpp +202 -0
  133. package/thirdparty/OpenXLSX/OpenXLSX/sources/XLColumn.cpp +141 -0
  134. package/thirdparty/OpenXLSX/OpenXLSX/sources/XLComments.cpp +637 -0
  135. package/thirdparty/OpenXLSX/OpenXLSX/sources/XLContentTypes.cpp +329 -0
  136. package/thirdparty/OpenXLSX/OpenXLSX/sources/XLDateTime.cpp +269 -0
  137. package/thirdparty/OpenXLSX/OpenXLSX/sources/XLDocument.cpp +1678 -0
  138. package/thirdparty/OpenXLSX/OpenXLSX/sources/XLDrawing.cpp +784 -0
  139. package/thirdparty/OpenXLSX/OpenXLSX/sources/XLFormula.cpp +201 -0
  140. package/thirdparty/OpenXLSX/OpenXLSX/sources/XLMergeCells.cpp +357 -0
  141. package/thirdparty/OpenXLSX/OpenXLSX/sources/XLProperties.cpp +810 -0
  142. package/thirdparty/OpenXLSX/OpenXLSX/sources/XLRelationships.cpp +529 -0
  143. package/thirdparty/OpenXLSX/OpenXLSX/sources/XLRow.cpp +918 -0
  144. package/thirdparty/OpenXLSX/OpenXLSX/sources/XLRowData.cpp +508 -0
  145. package/thirdparty/OpenXLSX/OpenXLSX/sources/XLSharedStrings.cpp +220 -0
  146. package/thirdparty/OpenXLSX/OpenXLSX/sources/XLSheet.cpp +1970 -0
  147. package/thirdparty/OpenXLSX/OpenXLSX/sources/XLStyles.cpp +3014 -0
  148. package/thirdparty/OpenXLSX/OpenXLSX/sources/XLTables.cpp +125 -0
  149. package/thirdparty/OpenXLSX/OpenXLSX/sources/XLWorkbook.cpp +784 -0
  150. package/thirdparty/OpenXLSX/OpenXLSX/sources/XLXmlData.cpp +247 -0
  151. package/thirdparty/OpenXLSX/OpenXLSX/sources/XLXmlFile.cpp +160 -0
  152. package/thirdparty/OpenXLSX/OpenXLSX/sources/XLXmlParser.cpp +261 -0
  153. package/thirdparty/OpenXLSX/OpenXLSX/sources/XLZipArchive.cpp +266 -0
  154. package/thirdparty/OpenXLSX/OpenXLSX/sources/utilities/XLUtilities.hpp +478 -0
  155. package/thirdparty/OpenXLSX/README.md +1279 -0
  156. package/thirdparty/OpenXLSX/Scripts/cmake-cleanup.sh +102 -0
  157. package/thirdparty/OpenXLSX/Scripts/compile.sh +23 -0
  158. package/thirdparty/OpenXLSX/Scripts/demos-cleanup.sh +25 -0
  159. package/thirdparty/OpenXLSX/Scripts/demos-run-all.sh +60 -0
  160. package/thirdparty/OpenXLSX/Scripts/guarded-xml-format.sh +47 -0
  161. package/thirdparty/OpenXLSX/Scripts/make-gnu.sh +11 -0
  162. package/thirdparty/OpenXLSX/Scripts/uninstall-manifest.sh +48 -0
  163. package/thirdparty/OpenXLSX/Scripts/xml-format-all.sh +19 -0
  164. package/thirdparty/OpenXLSX/Scripts/xml-format.sh +38 -0
  165. package/thirdparty/OpenXLSX/Tests/CMakeLists.txt +37 -0
  166. package/thirdparty/OpenXLSX/Tests/catch/catch.hpp +17799 -0
  167. package/thirdparty/OpenXLSX/Tests/catch/catch_reporter_automake.hpp +68 -0
  168. package/thirdparty/OpenXLSX/Tests/catch/catch_reporter_sonarqube.hpp +182 -0
  169. package/thirdparty/OpenXLSX/Tests/catch/catch_reporter_tap.hpp +278 -0
  170. package/thirdparty/OpenXLSX/Tests/catch/catch_reporter_teamcity.hpp +212 -0
  171. package/thirdparty/OpenXLSX/Tests/main.cpp +55 -0
  172. package/thirdparty/OpenXLSX/Tests/testXLCell.cpp +176 -0
  173. package/thirdparty/OpenXLSX/Tests/testXLCellRange.cpp +180 -0
  174. package/thirdparty/OpenXLSX/Tests/testXLCellReference.cpp +160 -0
  175. package/thirdparty/OpenXLSX/Tests/testXLCellValue.cpp +366 -0
  176. package/thirdparty/OpenXLSX/Tests/testXLCellValueProxy.cpp +255 -0
  177. package/thirdparty/OpenXLSX/Tests/testXLColor.cpp +75 -0
  178. package/thirdparty/OpenXLSX/Tests/testXLDateTime.cpp +229 -0
  179. package/thirdparty/OpenXLSX/Tests/testXLDocument.cpp +197 -0
  180. package/thirdparty/OpenXLSX/Tests/testXLFormula.cpp +131 -0
  181. package/thirdparty/OpenXLSX/Tests/testXLRow.cpp +597 -0
  182. package/thirdparty/OpenXLSX/Tests/testXLSheet.cpp +77 -0
  183. package/thirdparty/OpenXLSX/Tests/ziptest-with-libs.cpp +88 -0
  184. package/thirdparty/OpenXLSX/Tests/ziptest.cpp +735 -0
  185. package/thirdparty/OpenXLSX/cmake/get-git-HEAD-ID.cmake +45 -0
  186. package/thirdparty/OpenXLSX/cmake/libopenxlsxCPackOptions.cmake.in +20 -0
  187. package/thirdparty/OpenXLSX/cmake/manage_dependency.cmake +813 -0
  188. package/thirdparty/OpenXLSX/cmake/recursive_library_type_test.cmake +52 -0
  189. package/thirdparty/OpenXLSX/gnu-make-crutch/OpenXLSX-Exports-shared.hpp +42 -0
  190. package/thirdparty/OpenXLSX/gnu-make-crutch/OpenXLSX-Exports-static.hpp +42 -0
  191. package/thirdparty/OpenXLSX/vcpkg.json +24 -0
  192. package/thirdparty/README.md +42 -0
  193. package/thirdparty/miniz/.clang-format +47 -0
  194. package/thirdparty/miniz/.travis.yml +2 -0
  195. package/thirdparty/miniz/CMakeLists.txt +333 -0
  196. package/thirdparty/miniz/CMakePresets.json +31 -0
  197. package/thirdparty/miniz/ChangeLog.md +272 -0
  198. package/thirdparty/miniz/Config.cmake.in +1 -0
  199. package/thirdparty/miniz/LICENSE +22 -0
  200. package/thirdparty/miniz/amalgamate.sh +57 -0
  201. package/thirdparty/miniz/examples/example1.c +105 -0
  202. package/thirdparty/miniz/examples/example2.c +164 -0
  203. package/thirdparty/miniz/examples/example3.c +269 -0
  204. package/thirdparty/miniz/examples/example4.c +102 -0
  205. package/thirdparty/miniz/examples/example5.c +327 -0
  206. package/thirdparty/miniz/examples/example6.c +189 -0
  207. package/thirdparty/miniz/meson.build +21 -0
  208. package/thirdparty/miniz/miniz.c +646 -0
  209. package/thirdparty/miniz/miniz.h +615 -0
  210. package/thirdparty/miniz/miniz.pc.in +13 -0
  211. package/thirdparty/miniz/miniz_common.h +89 -0
  212. package/thirdparty/miniz/miniz_export.h +20 -0
  213. package/thirdparty/miniz/miniz_tdef.c +1602 -0
  214. package/thirdparty/miniz/miniz_tdef.h +199 -0
  215. package/thirdparty/miniz/miniz_tinfl.c +778 -0
  216. package/thirdparty/miniz/miniz_tinfl.h +150 -0
  217. package/thirdparty/miniz/miniz_zip.c +4895 -0
  218. package/thirdparty/miniz/miniz_zip.h +454 -0
  219. package/thirdparty/miniz/readme.md +46 -0
  220. package/thirdparty/miniz/test.sh +36 -0
  221. package/thirdparty/miniz/tests/add_in_place_fuzzer.c +87 -0
  222. package/thirdparty/miniz/tests/catch_amalgamated.cpp +10795 -0
  223. package/thirdparty/miniz/tests/catch_amalgamated.hpp +13143 -0
  224. package/thirdparty/miniz/tests/checksum_fuzzer.c +26 -0
  225. package/thirdparty/miniz/tests/compress_fuzzer.c +91 -0
  226. package/thirdparty/miniz/tests/flush_fuzzer.c +88 -0
  227. package/thirdparty/miniz/tests/fuzz_main.c +55 -0
  228. package/thirdparty/miniz/tests/large_fuzzer.c +133 -0
  229. package/thirdparty/miniz/tests/main.cpp +185 -0
  230. package/thirdparty/miniz/tests/miniz_tdefl_fuzzer.cc +115 -0
  231. package/thirdparty/miniz/tests/miniz_tester.cpp +1881 -0
  232. package/thirdparty/miniz/tests/miniz_zip_validate_fuzzer.cc +71 -0
  233. package/thirdparty/miniz/tests/miniz_zip_writer_fuzzer.cc +96 -0
  234. package/thirdparty/miniz/tests/ossfuzz.sh +48 -0
  235. package/thirdparty/miniz/tests/small_fuzzer.c +126 -0
  236. package/thirdparty/miniz/tests/timer.cpp +152 -0
  237. package/thirdparty/miniz/tests/timer.h +40 -0
  238. package/thirdparty/miniz/tests/uncompress2_fuzzer.c +21 -0
  239. package/thirdparty/miniz/tests/uncompress_fuzzer.c +30 -0
  240. package/thirdparty/miniz/tests/zip.dict +9 -0
  241. package/thirdparty/miniz/tests/zip_fuzzer.c +63 -0
  242. package/thirdparty/pugixml/.codecov.yml +7 -0
  243. package/thirdparty/pugixml/.gitattributes +1 -0
  244. package/thirdparty/pugixml/CMakeLists.txt +330 -0
  245. package/thirdparty/pugixml/LICENSE.md +24 -0
  246. package/thirdparty/pugixml/Makefile +98 -0
  247. package/thirdparty/pugixml/README.md +81 -0
  248. package/thirdparty/pugixml/SECURITY.md +9 -0
  249. package/thirdparty/pugixml/appveyor.yml +50 -0
  250. package/thirdparty/pugixml/docs/config.adoc +7 -0
  251. package/thirdparty/pugixml/docs/images/dom_tree.png +0 -0
  252. package/thirdparty/pugixml/docs/images/vs2005_link1.png +0 -0
  253. package/thirdparty/pugixml/docs/images/vs2005_link2.png +0 -0
  254. package/thirdparty/pugixml/docs/images/vs2005_pch1.png +0 -0
  255. package/thirdparty/pugixml/docs/images/vs2005_pch2.png +0 -0
  256. package/thirdparty/pugixml/docs/images/vs2005_pch3.png +0 -0
  257. package/thirdparty/pugixml/docs/images/vs2005_pch4.png +0 -0
  258. package/thirdparty/pugixml/docs/images/vs2010_link1.png +0 -0
  259. package/thirdparty/pugixml/docs/images/vs2010_link2.png +0 -0
  260. package/thirdparty/pugixml/docs/manual.adoc +3326 -0
  261. package/thirdparty/pugixml/docs/manual.html +6395 -0
  262. package/thirdparty/pugixml/docs/quickstart.adoc +287 -0
  263. package/thirdparty/pugixml/docs/quickstart.html +1107 -0
  264. package/thirdparty/pugixml/docs/samples/character.xml +8 -0
  265. package/thirdparty/pugixml/docs/samples/custom_memory_management.cpp +27 -0
  266. package/thirdparty/pugixml/docs/samples/include.cpp +64 -0
  267. package/thirdparty/pugixml/docs/samples/load_error_handling.cpp +33 -0
  268. package/thirdparty/pugixml/docs/samples/load_file.cpp +16 -0
  269. package/thirdparty/pugixml/docs/samples/load_memory.cpp +66 -0
  270. package/thirdparty/pugixml/docs/samples/load_options.cpp +30 -0
  271. package/thirdparty/pugixml/docs/samples/load_stream.cpp +97 -0
  272. package/thirdparty/pugixml/docs/samples/modify_add.cpp +29 -0
  273. package/thirdparty/pugixml/docs/samples/modify_base.cpp +43 -0
  274. package/thirdparty/pugixml/docs/samples/modify_remove.cpp +27 -0
  275. package/thirdparty/pugixml/docs/samples/save_custom_writer.cpp +116 -0
  276. package/thirdparty/pugixml/docs/samples/save_declaration.cpp +27 -0
  277. package/thirdparty/pugixml/docs/samples/save_file.cpp +17 -0
  278. package/thirdparty/pugixml/docs/samples/save_options.cpp +48 -0
  279. package/thirdparty/pugixml/docs/samples/save_stream.cpp +18 -0
  280. package/thirdparty/pugixml/docs/samples/save_subtree.cpp +26 -0
  281. package/thirdparty/pugixml/docs/samples/text.cpp +35 -0
  282. package/thirdparty/pugixml/docs/samples/transitions.xml +7 -0
  283. package/thirdparty/pugixml/docs/samples/traverse_base.cpp +51 -0
  284. package/thirdparty/pugixml/docs/samples/traverse_iter.cpp +27 -0
  285. package/thirdparty/pugixml/docs/samples/traverse_predicate.cpp +48 -0
  286. package/thirdparty/pugixml/docs/samples/traverse_rangefor.cpp +32 -0
  287. package/thirdparty/pugixml/docs/samples/traverse_walker.cpp +35 -0
  288. package/thirdparty/pugixml/docs/samples/tree.xml +12 -0
  289. package/thirdparty/pugixml/docs/samples/weekly-shift_jis.xml +78 -0
  290. package/thirdparty/pugixml/docs/samples/weekly-utf-16.xml +0 -0
  291. package/thirdparty/pugixml/docs/samples/weekly-utf-8.xml +78 -0
  292. package/thirdparty/pugixml/docs/samples/xgconsole.xml +12 -0
  293. package/thirdparty/pugixml/docs/samples/xpath_error.cpp +43 -0
  294. package/thirdparty/pugixml/docs/samples/xpath_query.cpp +36 -0
  295. package/thirdparty/pugixml/docs/samples/xpath_select.cpp +28 -0
  296. package/thirdparty/pugixml/docs/samples/xpath_variables.cpp +38 -0
  297. package/thirdparty/pugixml/readme.txt +50 -0
  298. package/thirdparty/pugixml/scripts/archive.py +54 -0
  299. package/thirdparty/pugixml/scripts/cocoapods_push.sh +4 -0
  300. package/thirdparty/pugixml/scripts/natvis/pugixml.natvis +77 -0
  301. package/thirdparty/pugixml/scripts/natvis/pugixml_compact.natvis +506 -0
  302. package/thirdparty/pugixml/scripts/nuget/build/native/pugixml-propertiesui.xml +17 -0
  303. package/thirdparty/pugixml/scripts/nuget/build/native/pugixml.targets +28 -0
  304. package/thirdparty/pugixml/scripts/nuget/pugixml.nuspec +20 -0
  305. package/thirdparty/pugixml/scripts/nuget_build.ps1 +60 -0
  306. package/thirdparty/pugixml/scripts/premake4.lua +92 -0
  307. package/thirdparty/pugixml/scripts/pugixml-config.cmake.in +12 -0
  308. package/thirdparty/pugixml/scripts/pugixml.pc.in +11 -0
  309. package/thirdparty/pugixml/scripts/pugixml.podspec +14 -0
  310. package/thirdparty/pugixml/scripts/pugixml.xcodeproj/project.pbxproj +212 -0
  311. package/thirdparty/pugixml/scripts/pugixml_airplay.mkf +13 -0
  312. package/thirdparty/pugixml/scripts/pugixml_codeblocks.cbp +44 -0
  313. package/thirdparty/pugixml/scripts/pugixml_codelite.project +56 -0
  314. package/thirdparty/pugixml/scripts/pugixml_dll.rc +45 -0
  315. package/thirdparty/pugixml/scripts/pugixml_vs2005.vcproj +343 -0
  316. package/thirdparty/pugixml/scripts/pugixml_vs2005_static.vcproj +343 -0
  317. package/thirdparty/pugixml/scripts/pugixml_vs2008.vcproj +339 -0
  318. package/thirdparty/pugixml/scripts/pugixml_vs2008_static.vcproj +339 -0
  319. package/thirdparty/pugixml/scripts/pugixml_vs2010.vcxproj +191 -0
  320. package/thirdparty/pugixml/scripts/pugixml_vs2010_static.vcxproj +191 -0
  321. package/thirdparty/pugixml/scripts/pugixml_vs2013.vcxproj +199 -0
  322. package/thirdparty/pugixml/scripts/pugixml_vs2013_static.vcxproj +199 -0
  323. package/thirdparty/pugixml/scripts/pugixml_vs2015.vcxproj +172 -0
  324. package/thirdparty/pugixml/scripts/pugixml_vs2015_static.vcxproj +176 -0
  325. package/thirdparty/pugixml/scripts/pugixml_vs2017.vcxproj +172 -0
  326. package/thirdparty/pugixml/scripts/pugixml_vs2017_static.vcxproj +176 -0
  327. package/thirdparty/pugixml/scripts/pugixml_vs2019.vcxproj +176 -0
  328. package/thirdparty/pugixml/scripts/pugixml_vs2019_static.vcxproj +180 -0
  329. package/thirdparty/pugixml/scripts/pugixml_vs2022.vcxproj +176 -0
  330. package/thirdparty/pugixml/scripts/pugixml_vs2022_static.vcxproj +180 -0
  331. package/thirdparty/pugixml/scripts/pugixml_vs2026.vcxproj +176 -0
  332. package/thirdparty/pugixml/scripts/pugixml_vs2026_static.vcxproj +180 -0
  333. package/thirdparty/pugixml/scripts/sbom.cdx.json +47 -0
  334. package/thirdparty/pugixml/src/pugiconfig.hpp +81 -0
  335. package/thirdparty/pugixml/src/pugixml.cpp +13776 -0
  336. package/thirdparty/pugixml/src/pugixml.hpp +1604 -0
  337. package/thirdparty/pugixml/tests/allocator.cpp +175 -0
  338. package/thirdparty/pugixml/tests/allocator.hpp +10 -0
  339. package/thirdparty/pugixml/tests/autotest-appveyor.ps1 +93 -0
  340. package/thirdparty/pugixml/tests/cmake-appveyor.ps1 +57 -0
  341. package/thirdparty/pugixml/tests/data/empty.xml +0 -0
  342. package/thirdparty/pugixml/tests/data/large.xml +1 -0
  343. package/thirdparty/pugixml/tests/data/latintest_latin1.xml +1 -0
  344. package/thirdparty/pugixml/tests/data/latintest_utf8.xml +1 -0
  345. package/thirdparty/pugixml/tests/data/multiline.xml +3 -0
  346. package/thirdparty/pugixml/tests/data/small.xml +1 -0
  347. package/thirdparty/pugixml/tests/data/truncation.xml +19 -0
  348. package/thirdparty/pugixml/tests/data/utftest_utf16_be.xml +0 -0
  349. package/thirdparty/pugixml/tests/data/utftest_utf16_be_bom.xml +0 -0
  350. package/thirdparty/pugixml/tests/data/utftest_utf16_be_clean.xml +0 -0
  351. package/thirdparty/pugixml/tests/data/utftest_utf16_be_nodecl.xml +0 -0
  352. package/thirdparty/pugixml/tests/data/utftest_utf16_le.xml +0 -0
  353. package/thirdparty/pugixml/tests/data/utftest_utf16_le_bom.xml +0 -0
  354. package/thirdparty/pugixml/tests/data/utftest_utf16_le_clean.xml +0 -0
  355. package/thirdparty/pugixml/tests/data/utftest_utf16_le_nodecl.xml +0 -0
  356. package/thirdparty/pugixml/tests/data/utftest_utf32_be.xml +0 -0
  357. package/thirdparty/pugixml/tests/data/utftest_utf32_be_bom.xml +0 -0
  358. package/thirdparty/pugixml/tests/data/utftest_utf32_be_clean.xml +0 -0
  359. package/thirdparty/pugixml/tests/data/utftest_utf32_be_nodecl.xml +0 -0
  360. package/thirdparty/pugixml/tests/data/utftest_utf32_le.xml +0 -0
  361. package/thirdparty/pugixml/tests/data/utftest_utf32_le_bom.xml +0 -0
  362. package/thirdparty/pugixml/tests/data/utftest_utf32_le_clean.xml +0 -0
  363. package/thirdparty/pugixml/tests/data/utftest_utf32_le_nodecl.xml +0 -0
  364. package/thirdparty/pugixml/tests/data/utftest_utf8.xml +87 -0
  365. package/thirdparty/pugixml/tests/data/utftest_utf8_bom.xml +87 -0
  366. package/thirdparty/pugixml/tests/data/utftest_utf8_clean.xml +84 -0
  367. package/thirdparty/pugixml/tests/data/utftest_utf8_nodecl.xml +86 -0
  368. package/thirdparty/pugixml/tests/data//321/202/320/265/321/201/321/202.xml +1 -0
  369. package/thirdparty/pugixml/tests/data_fuzz_parse/basic.xml +1 -0
  370. package/thirdparty/pugixml/tests/data_fuzz_parse/doctype.xml +1 -0
  371. package/thirdparty/pugixml/tests/data_fuzz_parse/refs.xml +1 -0
  372. package/thirdparty/pugixml/tests/data_fuzz_parse/types.xml +1 -0
  373. package/thirdparty/pugixml/tests/data_fuzz_parse/utf16.xml +0 -0
  374. package/thirdparty/pugixml/tests/data_fuzz_parse/utf32.xml +0 -0
  375. package/thirdparty/pugixml/tests/data_fuzz_xpath/basic.xpath +1 -0
  376. package/thirdparty/pugixml/tests/data_fuzz_xpath/functions.xpath +1 -0
  377. package/thirdparty/pugixml/tests/data_fuzz_xpath/math.xpath +1 -0
  378. package/thirdparty/pugixml/tests/data_fuzz_xpath/path.xpath +1 -0
  379. package/thirdparty/pugixml/tests/data_fuzz_xpath/predicate.xpath +1 -0
  380. package/thirdparty/pugixml/tests/fuzz_parse.cpp +14 -0
  381. package/thirdparty/pugixml/tests/fuzz_parse.dict +72 -0
  382. package/thirdparty/pugixml/tests/fuzz_setup.sh +11 -0
  383. package/thirdparty/pugixml/tests/fuzz_xpath.cpp +46 -0
  384. package/thirdparty/pugixml/tests/fuzz_xpath.dict +72 -0
  385. package/thirdparty/pugixml/tests/helpers.hpp +114 -0
  386. package/thirdparty/pugixml/tests/main.cpp +218 -0
  387. package/thirdparty/pugixml/tests/test.cpp +220 -0
  388. package/thirdparty/pugixml/tests/test.hpp +175 -0
  389. package/thirdparty/pugixml/tests/test_compact.cpp +150 -0
  390. package/thirdparty/pugixml/tests/test_deprecated.cpp +25 -0
  391. package/thirdparty/pugixml/tests/test_document.cpp +1910 -0
  392. package/thirdparty/pugixml/tests/test_dom_modify.cpp +2122 -0
  393. package/thirdparty/pugixml/tests/test_dom_text.cpp +601 -0
  394. package/thirdparty/pugixml/tests/test_dom_traverse.cpp +1481 -0
  395. package/thirdparty/pugixml/tests/test_header_guard.cpp +3 -0
  396. package/thirdparty/pugixml/tests/test_header_iosfwd_1.cpp +3 -0
  397. package/thirdparty/pugixml/tests/test_header_iosfwd_2.cpp +3 -0
  398. package/thirdparty/pugixml/tests/test_header_iostream_1.cpp +3 -0
  399. package/thirdparty/pugixml/tests/test_header_iostream_2.cpp +3 -0
  400. package/thirdparty/pugixml/tests/test_header_only_1.cpp +21 -0
  401. package/thirdparty/pugixml/tests/test_header_only_2.cpp +21 -0
  402. package/thirdparty/pugixml/tests/test_header_string_1.cpp +3 -0
  403. package/thirdparty/pugixml/tests/test_header_string_2.cpp +3 -0
  404. package/thirdparty/pugixml/tests/test_header_string_iostream.cpp +5 -0
  405. package/thirdparty/pugixml/tests/test_memory.cpp +303 -0
  406. package/thirdparty/pugixml/tests/test_parse.cpp +1463 -0
  407. package/thirdparty/pugixml/tests/test_parse_doctype.cpp +366 -0
  408. package/thirdparty/pugixml/tests/test_unicode.cpp +152 -0
  409. package/thirdparty/pugixml/tests/test_version.cpp +5 -0
  410. package/thirdparty/pugixml/tests/test_write.cpp +757 -0
  411. package/thirdparty/pugixml/tests/test_xpath.cpp +833 -0
  412. package/thirdparty/pugixml/tests/test_xpath_api.cpp +646 -0
  413. package/thirdparty/pugixml/tests/test_xpath_functions.cpp +844 -0
  414. package/thirdparty/pugixml/tests/test_xpath_operators.cpp +566 -0
  415. package/thirdparty/pugixml/tests/test_xpath_parse.cpp +428 -0
  416. package/thirdparty/pugixml/tests/test_xpath_paths.cpp +787 -0
  417. package/thirdparty/pugixml/tests/test_xpath_paths_abbrev_w3c.cpp +219 -0
  418. package/thirdparty/pugixml/tests/test_xpath_paths_w3c.cpp +312 -0
  419. package/thirdparty/pugixml/tests/test_xpath_variables.cpp +683 -0
  420. package/thirdparty/pugixml/tests/test_xpath_xalan_1.cpp +411 -0
  421. package/thirdparty/pugixml/tests/test_xpath_xalan_2.cpp +417 -0
  422. package/thirdparty/pugixml/tests/test_xpath_xalan_3.cpp +321 -0
  423. package/thirdparty/pugixml/tests/test_xpath_xalan_4.cpp +300 -0
  424. package/thirdparty/pugixml/tests/test_xpath_xalan_5.cpp +295 -0
  425. package/thirdparty/pugixml/tests/writer_string.cpp +79 -0
  426. package/thirdparty/pugixml/tests/writer_string.hpp +27 -0
  427. package/ios/dummy.swift +0 -2
  428. package/scripts/prepare-openxlsx.js +0 -109
@@ -0,0 +1,810 @@
1
+ /*
2
+
3
+ ____ ____ ___ ____ ____ ____ ___
4
+ 6MMMMb `MM( )M' `MM' 6MMMMb\`MM( )M'
5
+ 8P Y8 `MM. d' MM 6M' ` `MM. d'
6
+ 6M Mb __ ____ ____ ___ __ `MM. d' MM MM `MM. d'
7
+ MM MM `M6MMMMb 6MMMMb `MM 6MMb `MM. d' MM YM. `MM. d'
8
+ MM MM MM' `Mb 6M' `Mb MMM9 `Mb `MMd MM YMMMMb `MMd
9
+ MM MM MM MM MM MM MM' MM dMM. MM `Mb dMM.
10
+ MM MM MM MM MMMMMMMM MM MM d'`MM. MM MM d'`MM.
11
+ YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM.
12
+ 8b d8 MM. ,M9 YM d9 MM MM d' `MM. MM / L ,M9 d' `MM.
13
+ YMMMM9 MMYMMM9 YMMMM9 _MM_ _MM_M(_ _)MM_ _MMMMMMM MYMMMM9 _M(_ _)MM_
14
+ MM
15
+ MM
16
+ _MM_
17
+
18
+ Copyright (c) 2018, Kenneth Troldal Balslev
19
+
20
+ All rights reserved.
21
+
22
+ Redistribution and use in source and binary forms, with or without
23
+ modification, are permitted provided that the following conditions are met:
24
+ - Redistributions of source code must retain the above copyright
25
+ notice, this list of conditions and the following disclaimer.
26
+ - Redistributions in binary form must reproduce the above copyright
27
+ notice, this list of conditions and the following disclaimer in the
28
+ documentation and/or other materials provided with the distribution.
29
+ - Neither the name of the author nor the
30
+ names of any contributors may be used to endorse or promote products
31
+ derived from this software without specific prior written permission.
32
+
33
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
34
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
35
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36
+ DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
37
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
38
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
39
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
40
+ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
41
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
42
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
43
+
44
+ */
45
+
46
+ // ===== External Includes ===== //
47
+ #include <string>
48
+ #include <vector>
49
+
50
+ // ===== OpenXLSX Includes ===== //
51
+ #include "XLDocument.hpp"
52
+ #include "XLProperties.hpp"
53
+ #include "XLRelationships.hpp" // GetStringFromType
54
+ #include "XLXmlParser.hpp" // pugixml wrapper
55
+ #include "utilities/XLUtilities.hpp" // appendAndGetAttribute
56
+
57
+ #include "XLException.hpp"
58
+
59
+ using namespace OpenXLSX;
60
+
61
+ namespace // anonymous namespace for module local functions
62
+ {
63
+ /**
64
+ * @brief insert node with nodeNameToInsert before insertBeforeThis and copy all the consecutive whitespace nodes preceeding insertBeforeThis
65
+ * @param nodeNameToInsert create a new element node with this name
66
+ * @param insertBeforeThis self-explanatory, isn't it? :)
67
+ * @returns the inserted XMLNode
68
+ * @throws XLInternalError if insertBeforeThis has no parent node
69
+ */
70
+ XMLNode prettyInsertXmlNodeBefore(std::string nodeNameToInsert, XMLNode insertBeforeThis)
71
+ {
72
+ XMLNode parentNode = insertBeforeThis.parent();
73
+ if (parentNode.empty())
74
+ throw XLInternalError("prettyInsertXmlNodeBefore can not insert before a node that has no parent");
75
+
76
+ // ===== Find potential whitespaces preceeding insertBeforeThis
77
+ XMLNode whitespaces = insertBeforeThis;
78
+ while (whitespaces.previous_sibling().type() == pugi::node_pcdata) whitespaces = whitespaces.previous_sibling();
79
+
80
+ // ===== Insert the nodeNameToInsert before insertBeforeThis, "hijacking" the preceeding whitespace nodes
81
+ XMLNode insertedNode = parentNode.insert_child_before(nodeNameToInsert.c_str(), insertBeforeThis);
82
+ // ===== Copy all hijacked whitespaces to also preceed (again) the node insertBeforeThis
83
+ while( whitespaces.type() == pugi::node_pcdata ) {
84
+ parentNode.insert_copy_before(whitespaces, insertBeforeThis);
85
+ whitespaces = whitespaces.next_sibling();
86
+ }
87
+ return insertedNode;
88
+ }
89
+
90
+ /**
91
+ * @brief fetch the <HeadingPairs><vt:vector> node from docNode, create if not existing
92
+ * @param docNode the xml document from which to fetch
93
+ * @returns an XMLNode for the <vt:vector> child of <HeadingPairs>
94
+ * @throws XLInternalError in case either XML element does not exist and fails to create
95
+ */
96
+ XMLNode headingPairsNode(XMLNode docNode)
97
+ {
98
+ XMLNode headingPairs = docNode.child("HeadingPairs");
99
+ if (headingPairs.empty()) {
100
+ XMLNode titlesOfParts = docNode.child("TitlesOfParts"); // attempt to locate TitlesOfParts to insert HeadingPairs right before
101
+ if( titlesOfParts.empty() )
102
+ headingPairs = docNode.append_child("HeadingPairs");
103
+ else
104
+ headingPairs = prettyInsertXmlNodeBefore("HeadingPairs", titlesOfParts);
105
+ if (headingPairs.empty())
106
+ throw XLInternalError("headingPairsNode was unable to create XML element HeadingPairs");
107
+ }
108
+ XMLNode node = headingPairs.first_child_of_type(pugi::node_element);
109
+ if (node.empty()) { // heading pairs child "vt:vector" does not exist
110
+ node = headingPairs.append_child("vt:vector", XLForceNamespace);
111
+ if (node.empty())
112
+ throw XLInternalError("headingPairsNode was unable to create HeadingPairs child element <vt:vector>");
113
+ node.append_attribute("size") = 0; // NOTE: size counts each heading pair as 2 - but for now, there are no entries
114
+ node.append_attribute("baseType") = "variant";
115
+ }
116
+ // ===== Finally, return what should be a good "vt:vector" node with all the heading pairs
117
+ return node;
118
+ }
119
+
120
+ XMLAttribute headingPairsSize(XMLNode docNode)
121
+ {
122
+ return docNode.child("HeadingPairs").first_child_of_type(pugi::node_element).attribute("size");
123
+ }
124
+
125
+ #ifdef __GNUC__ // conditionally enable GCC specific pragmas to suppress unused function warning
126
+ # pragma GCC diagnostic push
127
+ # pragma GCC diagnostic ignored "-Wunused-function"
128
+ #endif // __GNUC__
129
+ std::vector<std::string> headingPairsCategoriesStrings(XMLNode docNode)
130
+ {
131
+ // 2024-05-28 DONE: tested this code with two pairs in headingPairsNode
132
+ std::vector<std::string> result;
133
+ XMLNode item = headingPairsNode(docNode).first_child_of_type(pugi::node_element);
134
+ while (not item.empty()) {
135
+ result.push_back(item.first_child_of_type(pugi::node_element).child_value());
136
+ item = item.next_sibling_of_type(pugi::node_element)
137
+ .next_sibling_of_type(pugi::node_element); // advance two elements to skip count node
138
+ }
139
+ return result; // 2024-05-28: std::move should not be used when the operand of a return statement is the name of a local variable
140
+ // as this can prevent named return value optimization (NRVO, copy elision)
141
+ }
142
+ #ifdef __GNUC__ // conditionally enable GCC specific pragmas to suppress unused function warning
143
+ # pragma GCC diagnostic pop
144
+ #endif // __GNUC__
145
+
146
+ /**
147
+ * @brief fetch the <TitlesOfParts><vt:vector> XML node, create if not existing
148
+ * @param docNode the xml document from which to fetch
149
+ * @returns an XMLNode for the <vt:vector> child of <TitlesOfParts>
150
+ * @throws XLInternalError in case either XML element does not exist and fails to create
151
+ */
152
+ XMLNode sheetNames(XMLNode docNode)
153
+ {
154
+ XMLNode titlesOfParts = docNode.child("TitlesOfParts");
155
+ if (titlesOfParts.empty()) {
156
+ // ===== Attempt to find a good position to insert TitlesOfParts
157
+ XMLNode node = docNode.first_child_of_type(pugi::node_element);
158
+ std::string nodeName = node.name();
159
+ while (not node.empty() && (
160
+ /**/ nodeName == "Application"
161
+ /**/ || nodeName == "AppVersion"
162
+ /**/ || nodeName == "DocSecurity"
163
+ /**/ || nodeName == "ScaleCrop"
164
+ /**/ || nodeName == "Template"
165
+ /**/ || nodeName == "TotalTime"
166
+ /**/ || nodeName == "HeadingPairs"
167
+ /**/ )) {
168
+ node = node.next_sibling_of_type(pugi::node_element);
169
+ nodeName = node.name();
170
+ }
171
+
172
+ if (node.empty())
173
+ titlesOfParts = docNode.append_child("TitlesOfParts");
174
+ else
175
+ titlesOfParts = prettyInsertXmlNodeBefore("TitlesOfParts", node);
176
+ }
177
+ XMLNode vtVector = titlesOfParts.first_child_of_type(pugi::node_element);
178
+ if (vtVector.empty()) {
179
+ vtVector = titlesOfParts.prepend_child("vt:vector", XLForceNamespace);
180
+ if (vtVector.empty())
181
+ throw XLInternalError("sheetNames was unable to create TitlesOfParts child element <vt:vector>");
182
+ vtVector.append_attribute("size") = 0;
183
+ vtVector.append_attribute("baseType") = "lpstr";
184
+ }
185
+ return vtVector;
186
+ }
187
+
188
+ XMLAttribute sheetCount(XMLNode docNode) { return sheetNames(docNode).attribute("size"); }
189
+
190
+ /**
191
+ * @brief from the HeadingPairs node, look up name and return the next sibling (which should be the associated value node)
192
+ * @param docNode the XML document giving access to the <HeadingPairs> node
193
+ * @param name the value pair whose attribute to return
194
+ * @returns XMLNode where the value associated with name is stored (the next element sibling from the node matching name)
195
+ * @returns XMLNode{} (empty) if name is not found or has no next element sibling
196
+ */
197
+ XMLNode getHeadingPairsValue(XMLNode docNode, std::string name)
198
+ {
199
+ XMLNode item = headingPairsNode(docNode).first_child_of_type(pugi::node_element);
200
+ while (not item.empty() && item.first_child_of_type(pugi::node_element).child_value() != name)
201
+ item = item.next_sibling_of_type(pugi::node_element)
202
+ .next_sibling_of_type(pugi::node_element); // advance two elements to skip count node
203
+ if (not item.empty()) // if name was found
204
+ item = item.next_sibling_of_type(pugi::node_element); // advance once more to the value node
205
+
206
+ // ===== Return the first element child of the <vt:variant> node containing the heading pair value
207
+ // (returns an empty node if item or first_child_of_type is empty)
208
+ return item.first_child_of_type(pugi::node_element);
209
+ }
210
+ } // anonymous namespace
211
+
212
+ /**
213
+ * @details
214
+ */
215
+ void XLProperties::ensureXmlNamespaces(XMLNode & props)
216
+ {
217
+ // ===== OpenXLSX_XLRelationships::GetStringFromType yields almost the string needed here, with added /relationships
218
+ // TBD: use hardcoded string?
219
+ std::string xmlns = OpenXLSX_XLRelationships::GetStringFromType(XLRelationshipType::CoreProperties);
220
+ const std::string rels = "/relationships/";
221
+ size_t pos = xmlns.find(rels);
222
+ if (pos != std::string::npos)
223
+ xmlns.replace(pos, rels.size(), "/");
224
+ else
225
+ xmlns = "http://schemas.openxmlformats.org/package/2006/metadata/core-properties"; // fallback to hardcoded string
226
+
227
+ appendAndGetAttribute(props, "xmlns:cp", xmlns.c_str());
228
+ appendAndGetAttribute(props, "xmlns:dc", "http://purl.org/dc/elements/1.1/");
229
+ appendAndGetAttribute(props, "xmlns:dcterms", "http://purl.org/dc/terms/");
230
+ appendAndGetAttribute(props, "xmlns:dcmitype", "http://purl.org/dc/dcmitype/");
231
+ appendAndGetAttribute(props, "xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
232
+
233
+ // props.append_attribute("xmlns:cp") = xmlns.c_str();
234
+ // props.append_attribute("xmlns:dc") = "http://purl.org/dc/elements/1.1/";
235
+ // props.append_attribute("xmlns:dcterms") = "http://purl.org/dc/terms/";
236
+ // props.append_attribute("xmlns:dcmitype") = "http://purl.org/dc/dcmitype/";
237
+ // props.append_attribute("xmlns:xsi") = "http://www.w3.org/2001/XMLSchema-instance";
238
+ }
239
+
240
+ /**
241
+ * @details
242
+ */
243
+ void XLProperties::createFromTemplate()
244
+ {
245
+ // std::cout << "XLProperties created with empty docProps/core.xml, creating from scratch!" << std::endl;
246
+ if(m_xmlData == nullptr)
247
+ throw XLInternalError("XLProperties m_xmlData is nullptr");
248
+
249
+ XMLNode props = xmlDocument().prepend_child("cp:coreProperties");
250
+ ensureXmlNamespaces(props);
251
+ props.append_child("dc:creator").text().set("Kenneth Balslev");
252
+ props.append_child("cp:lastModifiedBy").text().set("Kenneth Balslev");
253
+
254
+ XMLNode prop {};
255
+ prop = props.append_child("dcterms:created");
256
+ prop.append_attribute("xsi:type") = "dcterms:W3CDTF";
257
+ prop.text().set("2019-08-16T00:34:14Z");
258
+ prop = props.append_child("dcterms:modified");
259
+ prop.append_attribute("xsi:type") = "dcterms:W3CDTF";
260
+ prop.text().set("2019-08-16T00:34:26Z");
261
+ }
262
+
263
+ /**
264
+ * @details
265
+ */
266
+ XLProperties::XLProperties() = default;
267
+
268
+ /**
269
+ * @details
270
+ */
271
+ XLProperties::XLProperties(XLXmlData* xmlData) : XLXmlFile(xmlData)
272
+ {
273
+ XMLNode doc = xmlData->getXmlDocument()->document_element();
274
+ XMLNode child = doc.first_child_of_type(pugi::node_element);
275
+ size_t childCount = 0;
276
+ while (not child.empty()) {
277
+ ++childCount;
278
+ child = child.next_sibling_of_type(pugi::node_element);
279
+ break; // one child is enough to determine document is not empty.
280
+ }
281
+ if (!childCount)
282
+ createFromTemplate();
283
+ else { // 2026-06-10: ensure that cp::coreProperties and XML namespaces are defined in existing documents, too
284
+ XMLNode props = xmlDocument().child("cp:coreProperties");
285
+ if (props.empty())
286
+ props = xmlDocument().prepend_child("cp:coreProperties");
287
+ ensureXmlNamespaces(props);
288
+ }
289
+ }
290
+
291
+ /**
292
+ * @details copy constructor
293
+ */
294
+ XLProperties::XLProperties(const XLProperties& other)
295
+ : XLXmlFile(other)
296
+ {}
297
+
298
+ /**
299
+ * @details move constructor
300
+ */
301
+ XLProperties::XLProperties(XLProperties&& other) noexcept = default;
302
+
303
+ /**
304
+ * @details copy assignment operator
305
+ */
306
+ XLProperties& XLProperties::operator=(const XLProperties& other)
307
+ {
308
+ if (&other != this) {
309
+ XLProperties temp = other; // copy-construct
310
+ *this = std::move(temp); // move-assign & invalidate temp
311
+ }
312
+ return *this;
313
+ }
314
+
315
+ /**
316
+ * @details move assignment operator
317
+ */
318
+ XLProperties& XLProperties::operator=(XLProperties&& other) = default;
319
+
320
+ /**
321
+ * @details
322
+ */
323
+ XLProperties::~XLProperties() = default;
324
+
325
+ /**
326
+ * @details
327
+ */
328
+ void XLProperties::setProperty(const std::string& name, const std::string& value)
329
+ {
330
+ if (m_xmlData == nullptr) return;
331
+ XMLNode node = xmlDocument().document_element().child(name.c_str());
332
+ if (node.empty())
333
+ node = xmlDocument().document_element().append_child(name.c_str()); // .append_child, to be in line with ::property behavior
334
+
335
+ node.text().set(value.c_str());
336
+ }
337
+
338
+ /**
339
+ * @details
340
+ */
341
+ void XLProperties::setProperty(const std::string& name, int value) { setProperty(name, std::to_string(value)); }
342
+
343
+ /**
344
+ * @details
345
+ */
346
+ void XLProperties::setProperty(const std::string& name, double value) { setProperty(name, std::to_string(value)); }
347
+
348
+ /**
349
+ * @details
350
+ */
351
+ std::string XLProperties::property(const std::string& name) const
352
+ {
353
+ if (m_xmlData == nullptr) return "";
354
+ XMLNode property = xmlDocument().document_element().child(name.c_str());
355
+ if (property.empty()) property = xmlDocument().document_element().append_child(name.c_str());
356
+
357
+ return property.text().get();
358
+ }
359
+
360
+ /**
361
+ * @details
362
+ */
363
+ void XLProperties::deleteProperty(const std::string& name)
364
+ {
365
+ if (m_xmlData == nullptr) return;
366
+ if (const XMLNode property = xmlDocument().document_element().child(name.c_str()); not property.empty())
367
+ xmlDocument().document_element().remove_child(property);
368
+ }
369
+
370
+
371
+ /**
372
+ * @details
373
+ */
374
+ void XLAppProperties::ensureXmlNamespaces(XMLNode & props)
375
+ {
376
+ // ===== OpenXLSX_XLRelationships::GetStringFromType yields almost the string needed here, with added /relationships
377
+ // TBD: use hardcoded string?
378
+ std::string xmlns = OpenXLSX_XLRelationships::GetStringFromType(XLRelationshipType::ExtendedProperties);
379
+ const std::string rels = "/relationships/";
380
+ size_t pos = xmlns.find(rels);
381
+ if (pos != std::string::npos)
382
+ xmlns.replace(pos, rels.size(), "/");
383
+ else
384
+ xmlns = "http://schemas.openxmlformats.org/officeDocument/2006/extended-properties"; // fallback to hardcoded string
385
+
386
+ appendAndGetAttribute(props, "xmlns", xmlns.c_str());
387
+ appendAndGetAttribute(props, "xmlns:vt", "http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes");
388
+
389
+ // props.append_attribute("xmlns") = xmlns.c_str();
390
+ // props.append_attribute("xmlns:vt") = "http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes";
391
+ }
392
+
393
+
394
+ /**
395
+ * @details
396
+ */
397
+ void XLAppProperties::createFromTemplate(XMLDocument const & workbookXml)
398
+ {
399
+ // std::cout << "XLAppProperties created with empty docProps/app.xml, creating from scratch!" << std::endl;
400
+ if(m_xmlData == nullptr)
401
+ throw XLInternalError("XLAppProperties m_xmlData is nullptr");
402
+
403
+ std::map< uint32_t, std::string > sheetsOrderedById;
404
+
405
+ auto sheet = workbookXml.document_element().child("sheets").first_child_of_type(pugi::node_element);
406
+ while (not sheet.empty()) {
407
+ std::string sheetName = sheet.attribute("name").as_string();
408
+ uint32_t sheetId = sheet.attribute("sheetId").as_uint();
409
+ sheetsOrderedById.insert(std::pair<uint32_t, std::string>(sheetId, sheetName));
410
+ sheet = sheet.next_sibling_of_type();
411
+ }
412
+
413
+ uint32_t worksheetCount = 0;
414
+ for (const auto & [key, value] : sheetsOrderedById) {
415
+ if (key != ++worksheetCount)
416
+ throw XLInputError( "xl/workbook.xml is missing sheet with sheetId=\"" + std::to_string(worksheetCount) + "\"" );
417
+ }
418
+
419
+ XMLNode props = xmlDocument().prepend_child("Properties");
420
+ ensureXmlNamespaces(props);
421
+ props.append_child("Application").text().set("Microsoft Macintosh Excel");
422
+ props.append_child("DocSecurity").text().set(0);
423
+ props.append_child("ScaleCrop").text().set(false);
424
+
425
+ XMLNode headingPairs = props.append_child("HeadingPairs");
426
+ XMLNode vecHP = headingPairs.append_child("vt:vector", XLForceNamespace);
427
+ vecHP.append_attribute("size") = 2;
428
+ vecHP.append_attribute("baseType") = "variant";
429
+ vecHP.append_child("vt:variant", XLForceNamespace).append_child("vt:lpstr", XLForceNamespace).text().set("Worksheets");
430
+ // ===== 2024-09-02 minor bugfix issue #220, "vt:i4" value of "Worksheets" pair should be sheet count
431
+ vecHP.append_child("vt:variant", XLForceNamespace).append_child("vt:i4", XLForceNamespace).text().set(worksheetCount);
432
+
433
+ XMLNode sheetsVector = props.append_child("TitlesOfParts").append_child("vt:vector", XLForceNamespace); // 2024-08-17 BUGFIX: TitlesOfParts was wrongly appended to headingPairs
434
+ sheetsVector.append_attribute("size") = worksheetCount;
435
+ sheetsVector.append_attribute("baseType") = "lpstr";
436
+ for (const auto & [key, value] : sheetsOrderedById)
437
+ sheetsVector.append_child("vt:lpstr", XLForceNamespace).text().set(value.c_str());
438
+
439
+ // NOTE 2024-07-24: for an empty string, .text().set("") would create a "<Company></Company>" node that
440
+ // would get reduced to <Company/> on a simple open + save operation and thereby cause the *only* diff
441
+ // to the uncompressed workbook. For this cosmetic reasons, text().set was removed in this case
442
+ props.append_child("Company"); // .text().set("");
443
+ props.append_child("LinksUpToDate").text().set(false);
444
+ props.append_child("SharedDoc").text().set(false);
445
+ props.append_child("HyperlinksChanged").text().set(false);
446
+ props.append_child("AppVersion").text().set("16.0300");
447
+ }
448
+
449
+ /**
450
+ * @details
451
+ */
452
+ XLAppProperties::XLAppProperties() = default;
453
+
454
+ /**
455
+ * @details
456
+ */
457
+ XLAppProperties::XLAppProperties(XLXmlData* xmlData, XMLDocument const & workbookXml)
458
+ : XLXmlFile(xmlData)
459
+ {
460
+ XMLNode doc = xmlData->getXmlDocument()->document_element();
461
+ XMLNode child = doc.first_child_of_type(pugi::node_element);
462
+ size_t childCount = 0;
463
+ while (not child.empty()) {
464
+ ++childCount;
465
+ child = child.next_sibling_of_type(pugi::node_element);
466
+ break; // one child is enough to determine document is not empty.
467
+ }
468
+ if (!childCount)
469
+ createFromTemplate(workbookXml); // create fresh docProps/app.xml
470
+ else { // 2026-06-10: ensure that cp::coreProperties and XML namespaces are defined in existing documents, too
471
+ XMLNode props = xmlDocument().child("Properties");
472
+ if (props.empty())
473
+ props = xmlDocument().prepend_child("Properties");
474
+ ensureXmlNamespaces(props);
475
+ }
476
+ }
477
+
478
+ /**
479
+ * @details
480
+ */
481
+ XLAppProperties::XLAppProperties(XLXmlData* xmlData) : XLXmlFile(xmlData) {}
482
+
483
+ /**
484
+ * @details copy constructor
485
+ */
486
+ XLAppProperties::XLAppProperties(const XLAppProperties& other)
487
+ : XLXmlFile(other)
488
+ {}
489
+
490
+ /**
491
+ * @details move constructor
492
+ */
493
+ XLAppProperties::XLAppProperties(XLAppProperties&& other) noexcept = default;
494
+
495
+ /**
496
+ * @details copy assignment operator
497
+ */
498
+ XLAppProperties& XLAppProperties::operator=(const XLAppProperties& other)
499
+ {
500
+ if (&other != this) {
501
+ XLAppProperties temp = other; // copy-construct
502
+ *this = std::move(temp); // move-assign & invalidate temp
503
+ }
504
+ return *this;
505
+ }
506
+
507
+ /**
508
+ * @details move assignment operator
509
+ */
510
+ XLAppProperties& XLAppProperties::operator=(XLAppProperties&& other) noexcept = default;
511
+
512
+ /**
513
+ * @details
514
+ */
515
+ XLAppProperties::~XLAppProperties() = default;
516
+
517
+ /**
518
+ * @details
519
+ * @note increment == 0 is tolerated for now, used by alignWorksheets to add the value to HeadingPairs if not present
520
+ * However, generally this function should only be called with increment == -1 or increment == +1
521
+ */
522
+ void XLAppProperties::incrementSheetCount(int16_t increment)
523
+ {
524
+ int32_t newCount = sheetCount(xmlDocument().document_element()).as_int() + increment;
525
+ if (newCount < 1)
526
+ throw XLInternalError("must not decrement sheet count below 1");
527
+ sheetCount(xmlDocument().document_element()).set_value(newCount);
528
+ XMLNode headingPairWorksheetsValue = getHeadingPairsValue(xmlDocument().document_element(), "Worksheets");
529
+ if (headingPairWorksheetsValue.empty()) // seems heading pair does not exist
530
+ addHeadingPair("Worksheets", newCount);
531
+ else
532
+ headingPairWorksheetsValue.text().set(newCount);
533
+ }
534
+
535
+ /**
536
+ * @details ensure that <TitlesOfParts> contains the correct workbook sheet names and <HeadingPairs> Worksheets entry
537
+ * has the correct worksheet count
538
+ */
539
+ void XLAppProperties::alignWorksheets(std::vector<std::string> const & workbookSheetNames)
540
+ {
541
+ XMLNode titlesOfParts = sheetNames(xmlDocument().document_element()); // creates <TitlesOfParts><vt:vector> if not existing
542
+ XMLNode sheetName = titlesOfParts.first_child_of_type(pugi::node_element);
543
+ // size_t sheetCount = workbookSheetNames.size();
544
+ for (std::string workbookSheetName : workbookSheetNames) {
545
+ if (sheetName.empty())
546
+ sheetName = titlesOfParts.append_child("vt:lpstr", XLForceNamespace);
547
+ sheetName.text().set(workbookSheetName.c_str());
548
+ sheetName = sheetName.next_sibling_of_type(pugi::node_element); // advance to next entry in <TitlesOfParts>, potentially becomes an empty XMLNode()
549
+ }
550
+
551
+ // ===== If there are any excess sheet names, clean up.
552
+ if (not sheetName.empty()) {
553
+ // ===== Delete all whitespace nodes prior to the sheet names to be deleted
554
+ while (sheetName.previous_sibling().type() == pugi::node_pcdata) titlesOfParts.remove_child(sheetName.previous_sibling());
555
+
556
+ XMLNode lastSheetName = titlesOfParts.last_child_of_type(pugi::node_element); // delete up to & including this node, preserve whitespaces after
557
+ if (sheetName != lastSheetName) { // If lastSheetName is a node *behind* sheetName
558
+ // ===== Delete all nodes (elements and whitespace) up until lastSheetName
559
+ while (sheetName.next_sibling() != lastSheetName)
560
+ titlesOfParts.remove_child(sheetName.next_sibling());
561
+ // ===== Delete lastSheetName
562
+ titlesOfParts.remove_child(lastSheetName);
563
+ }
564
+ // ===== Delete sheetName
565
+ titlesOfParts.remove_child(sheetName);
566
+ }
567
+
568
+ sheetCount(xmlDocument().document_element()).set_value(workbookSheetNames.size()); // save size of <TitlesOfParts><vt:vector>
569
+ incrementSheetCount(0); // ensure that the sheet count is correctly reflected in <HeadingPairs> Worksheets entry
570
+ }
571
+
572
+ /**
573
+ * @details
574
+ */
575
+ void XLAppProperties::addSheetName(const std::string& title)
576
+ {
577
+ if (m_xmlData == nullptr) return;
578
+ XMLNode theNode = sheetNames(xmlDocument().document_element()).append_child("vt:lpstr", XLForceNamespace);
579
+ theNode.text().set(title.c_str());
580
+ incrementSheetCount(+1);
581
+ }
582
+
583
+ /**
584
+ * @details
585
+ */
586
+ void XLAppProperties::deleteSheetName(const std::string& title)
587
+ {
588
+ if (m_xmlData == nullptr) return;
589
+ XMLNode theNode = sheetNames(xmlDocument().document_element()).first_child_of_type(pugi::node_element);
590
+ while (not theNode.empty()) {
591
+ if (theNode.child_value() == title) {
592
+ sheetNames(xmlDocument().document_element()).remove_child(theNode);
593
+ incrementSheetCount(-1);
594
+ return;
595
+ }
596
+ theNode = theNode.next_sibling_of_type(pugi::node_element);
597
+ }
598
+ }
599
+
600
+ /**
601
+ * @details
602
+ */
603
+ void XLAppProperties::setSheetName(const std::string& oldTitle, const std::string& newTitle)
604
+ {
605
+ if (m_xmlData == nullptr) return;
606
+ XMLNode theNode = sheetNames(xmlDocument().document_element()).first_child_of_type(pugi::node_element);
607
+ while (not theNode.empty()) {
608
+ if (theNode.child_value() == oldTitle) {
609
+ theNode.text().set(newTitle.c_str());
610
+ return;
611
+ }
612
+ theNode = theNode.next_sibling_of_type(pugi::node_element);
613
+ }
614
+ }
615
+
616
+ /**
617
+ * @details
618
+ */
619
+ void XLAppProperties::addHeadingPair(const std::string& name, int value)
620
+ {
621
+ if (m_xmlData == nullptr) return;
622
+
623
+ XMLNode HeadingPairsNode = headingPairsNode(xmlDocument().document_element());
624
+ XMLNode item = HeadingPairsNode.first_child_of_type(pugi::node_element);
625
+ while (not item.empty() && item.first_child_of_type(pugi::node_element).child_value() != name)
626
+ item = item.next_sibling_of_type(pugi::node_element)
627
+ .next_sibling_of_type(pugi::node_element); // advance two elements to skip count node
628
+
629
+ XMLNode pairCategory = item; // could be an empty node
630
+ XMLNode pairValue {}; // initialize to empty node
631
+ if (not pairCategory.empty())
632
+ pairValue = pairCategory.next_sibling_of_type(pugi::node_element).first_child_of_type(pugi::node_element);
633
+ else {
634
+ item = HeadingPairsNode.last_child_of_type(pugi::node_element);
635
+ if (not item.empty())
636
+ pairCategory = HeadingPairsNode.insert_child_after("vt:variant", item, XLForceNamespace);
637
+ else
638
+ pairCategory = HeadingPairsNode.append_child("vt:variant", XLForceNamespace);
639
+ XMLNode categoryName = pairCategory.append_child("vt:lpstr", XLForceNamespace);
640
+ categoryName.text().set(name.c_str());
641
+ XMLNode pairValueParent = HeadingPairsNode.insert_child_after("vt:variant", pairCategory, XLForceNamespace);
642
+ pairValue = pairValueParent.append_child("vt:i4", XLForceNamespace);
643
+ }
644
+
645
+ if (not pairValue.empty())
646
+ pairValue.text().set(std::to_string(value).c_str());
647
+ else {
648
+ using namespace std::literals::string_literals;
649
+ throw XLInternalError("XLAppProperties::addHeadingPair: found no matching pair count value to name "s + name);
650
+ }
651
+ headingPairsSize(xmlDocument().document_element()).set_value(HeadingPairsNode.child_count_of_type());
652
+ }
653
+
654
+ /**
655
+ * @details
656
+ */
657
+ void XLAppProperties::deleteHeadingPair(const std::string& name)
658
+ {
659
+ if (m_xmlData == nullptr) return;
660
+
661
+ XMLNode HeadingPairsNode = headingPairsNode(xmlDocument().document_element());
662
+ XMLNode item = HeadingPairsNode.first_child_of_type(pugi::node_element);
663
+ while (not item.empty() && item.first_child_of_type(pugi::node_element).child_value() != name)
664
+ item = item.next_sibling_of_type(pugi::node_element)
665
+ .next_sibling_of_type(pugi::node_element); // advance two elements to skip count node
666
+
667
+ // ===== If item with name was found, remove pair and update headingPairsSize
668
+ if (not item.empty()) {
669
+ const XMLNode count = item.next_sibling_of_type(pugi::node_element);
670
+ // ===== 2024-05-28: delete all (non-element) nodes between item and count node, *then* delete non-element nodes following a count node
671
+ if (not count.empty()) {
672
+ while (item.next_sibling() != count)
673
+ HeadingPairsNode.remove_child(item.next_sibling()); // remove nodes between item & count nodes to be deleted jointly
674
+
675
+ // ===== Delete all non-element nodes following the count node
676
+ while ((not count.next_sibling().empty()) && (count.next_sibling().type() != pugi::node_element))
677
+ HeadingPairsNode.remove_child(count.next_sibling()); // remove all non-element nodes following a count node
678
+
679
+ HeadingPairsNode.remove_child(count);
680
+ }
681
+ // REMOVED: formatting doesn't get prettier by removing whitespaces on both sides of a pair
682
+ // while (item.previous_sibling().type() == pugi::node_pcdata) HeadingPairsNode.remove_child(item.previous_sibling());
683
+
684
+ HeadingPairsNode.remove_child(item);
685
+ headingPairsSize(xmlDocument().document_element()).set_value(HeadingPairsNode.child_count_of_type());
686
+ }
687
+ }
688
+
689
+ /**
690
+ * @details
691
+ */
692
+ void XLAppProperties::setHeadingPair(const std::string& name, int newValue)
693
+ {
694
+ if (m_xmlData == nullptr) return;
695
+
696
+ XMLNode pairValue = getHeadingPairsValue(xmlDocument().document_element(), name);
697
+ using namespace std::literals::string_literals;
698
+ if (not pairValue.empty() && (pairValue.raw_name() == "vt:i4"s))
699
+ pairValue.text().set(std::to_string(newValue).c_str());
700
+ else
701
+ throw XLInternalError("XLAppProperties::setHeadingPair: found no matching pair count value to name "s + name);
702
+ }
703
+
704
+ /**
705
+ * @details
706
+ */
707
+ void XLAppProperties::setProperty(const std::string& name, const std::string& value)
708
+ {
709
+ if (m_xmlData == nullptr) return;
710
+ auto property = xmlDocument().document_element().child(name.c_str());
711
+ if (property.empty()) xmlDocument().document_element().append_child(name.c_str());
712
+ property.text().set(value.c_str());
713
+ }
714
+
715
+ /**
716
+ * @details
717
+ */
718
+ std::string XLAppProperties::property(const std::string& name) const
719
+ {
720
+ if (m_xmlData == nullptr) return "";
721
+ XMLNode property = xmlDocument().document_element().child(name.c_str());
722
+ if (property.empty())
723
+ property = xmlDocument().document_element().append_child(name.c_str()); // BUGFIX 2024-05-21: re-assign the newly created node to
724
+ // property, so that .text().get() is defined behavior
725
+ return property.text().get();
726
+ // NOTE 2024-05-21: this was previously defined behavior because XMLNode::text() called from an empty xml_node returns an xml_text node
727
+ // constructed on an empty _root pointer, while in turn xml_text::get() returns a PUGIXML_TEXT("") for an empty xml_text node
728
+ // However, relying on all this implicit functionality was really ugly ;)
729
+ }
730
+
731
+ /**
732
+ * @details
733
+ */
734
+ void XLAppProperties::deleteProperty(const std::string& name)
735
+ {
736
+ if (m_xmlData == nullptr) return;
737
+ const auto property = xmlDocument().document_element().child(name.c_str());
738
+ if (property.empty()) return;
739
+
740
+ xmlDocument().document_element().remove_child(property);
741
+ }
742
+
743
+ /**
744
+ * @details
745
+ */
746
+ void XLAppProperties::appendSheetName(const std::string& sheetName)
747
+ {
748
+ if (m_xmlData == nullptr) return;
749
+ auto theNode = sheetNames(xmlDocument().document_element()).append_child("vt:lpstr", XLForceNamespace);
750
+ theNode.text().set(sheetName.c_str());
751
+ incrementSheetCount(+1);
752
+ }
753
+
754
+ /**
755
+ * @details
756
+ */
757
+ void XLAppProperties::prependSheetName(const std::string& sheetName)
758
+ {
759
+ if (m_xmlData == nullptr) return;
760
+ auto theNode = sheetNames(xmlDocument().document_element()).prepend_child("vt:lpstr", XLForceNamespace);
761
+ theNode.text().set(sheetName.c_str());
762
+ incrementSheetCount(+1);
763
+ }
764
+
765
+ /**
766
+ * @details
767
+ */
768
+ void XLAppProperties::insertSheetName(const std::string& sheetName, unsigned int index)
769
+ {
770
+ if (m_xmlData == nullptr) return;
771
+
772
+ if (index <= 1) {
773
+ prependSheetName(sheetName);
774
+ return;
775
+ }
776
+
777
+ // ===== If sheet needs to be appended...
778
+ if (index > sheetCount(xmlDocument().document_element()).as_uint()) {
779
+ // ===== If at least one sheet node exists, apply some pretty formatting by appending new sheet name between last sheet and trailing
780
+ // whitespaces.
781
+ const XMLNode lastSheet = sheetNames(xmlDocument().document_element()).last_child_of_type(pugi::node_element);
782
+ if (not lastSheet.empty()) {
783
+ XMLNode theNode = sheetNames(xmlDocument().document_element()).insert_child_after("vt:lpstr", lastSheet, XLForceNamespace);
784
+ theNode.text().set(sheetName.c_str());
785
+ // ===== Update sheet count before return statement.
786
+ incrementSheetCount(+1);
787
+ }
788
+ else
789
+ appendSheetName(sheetName);
790
+ return;
791
+ }
792
+
793
+ XMLNode curNode = sheetNames(xmlDocument().document_element()).first_child_of_type(pugi::node_element);
794
+ unsigned idx = 1;
795
+ while (not curNode.empty()) {
796
+ if (idx == index) break;
797
+ curNode = curNode.next_sibling_of_type(pugi::node_element);
798
+ ++idx;
799
+ }
800
+
801
+ if (curNode.empty()) {
802
+ appendSheetName(sheetName);
803
+ return;
804
+ }
805
+
806
+ XMLNode theNode = sheetNames(xmlDocument().document_element()).insert_child_before("vt:lpstr", curNode, XLForceNamespace);
807
+ theNode.text().set(sheetName.c_str());
808
+
809
+ incrementSheetCount(+1);
810
+ }