diff --git a/.gitignore b/.gitignore index 98a5778a..b9d22d3a 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,4 @@ Win32/ *.pyd python/record.txt python/xlntpyarrow.egg-info/ +/x64/ \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 482fea53..2cb7a053 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.2) +cmake_minimum_required(VERSION 3.1) project(xlnt_all) # This indicates to CMakeLists in subdirectories that they are part of a larger project @@ -11,28 +11,28 @@ option(STATIC "Set to ON to build xlnt as a static library instead of a shared l option(TESTS "Set to OFF to skip building test executable (in ./tests)" ON) option(SAMPLES "Set to ON to build executable code samples (in ./samples)" OFF) option(BENCHMARKS "Set to ON to build performance benchmarks (in ./benchmarks)" OFF) -option(ARROW "Set to ON to build Arrow conversion functions (in ./contrib/xlntarrow)" OFF) +option(PYTHON "Set to ON to build Arrow conversion functions (in ./python)" OFF) # Platform specific options if(NOT MSVC) - option(COVERAGE "Generate coverage data using gcov" OFF) + option(COVERAGE "Generate coverage data using gcov" OFF) endif() # Add components according to selected options if(SAMPLES) - add_subdirectory(samples) + add_subdirectory(samples) endif() if(BENCHMARKS) - add_subdirectory(benchmarks) + add_subdirectory(benchmarks) endif() if(TESTS) - add_subdirectory(tests) + add_subdirectory(tests) endif() if(PYTHON) - add_subdirectory(python) + add_subdirectory(python) endif() add_subdirectory(source) diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 00000000..76d62a21 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,46 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at thomas.fussell@gmail.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] + +[homepage]: http://contributor-covenant.org +[version]: http://contributor-covenant.org/version/1/4/ diff --git a/LICENSE.md b/LICENSE.md index 043183ce..b302dad3 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -26,6 +26,37 @@ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ``` +# Dependency Licences + +## [utfcpp](https://github.com/nemtrif/utfcpp) +>[Boost Software License - Version 1.0](https://github.com/nemtrif/utfcpp/blob/master/source/utf8.h) + +``` +Copyright 2006 Nemanja Trifunovic + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +``` + ## [POLE](http://www.dimin.net/software/pole/) >[BSD 2-Clause License](https://bitbucket.org/dimin/pole/src/c15e513bdce4c3a52b3dbc925d4d2bb520dc71d8/pole/LICENSE) @@ -92,6 +123,204 @@ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ``` +## [PartIO](https://www.disneyanimation.com/technology/partio.html) +>[BSD 3-Clause License (with specific non-attribution clause)](https://github.com/wdas/partio/blob/master/src/lib/io/ZIP.h) + +``` +Copyright 2010 Disney Enterprises, Inc. All rights reserved + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +* Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in +the documentation and/or other materials provided with the +distribution. + +* The names "Disney", "Walt Disney Pictures", "Walt Disney Animation +Studios" or the names of its contributors may NOT be used to +endorse or promote products derived from this software without +specific prior written permission from Walt Disney Pictures. + +Disclaimer: THIS SOFTWARE IS PROVIDED BY WALT DISNEY PICTURES AND +CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE, NONINFRINGEMENT AND TITLE ARE DISCLAIMED. +IN NO EVENT SHALL WALT DISNEY PICTURES, THE COPYRIGHT HOLDER OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND BASED ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. +``` + +## [miniz](https://github.com/richgel999/miniz) +>[Public Domain/MIT License](https://github.com/richgel999/miniz/blob/master/LICENSE) + +``` +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +For more information, please refer to + +Copyright 2013-2014 RAD Game Tools and Valve Software +Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC +All Rights Reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +``` + + +## [SHA-512 hash in C](https://www.nayuki.io/page/fast-sha2-hashes-in-x86-assembly) +>[MIT License](https://www.nayuki.io/res/fast-sha2-hashes-in-x86-assembly/sha512.c) + +``` +Copyright (c) 2016 Project Nayuki + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +``` + +## [SHA-1 hash in C](https://www.nayuki.io/page/fast-sha1-hash-implementation-in-x86-assembly) +>[MIT License](https://www.nayuki.io/res/fast-sha1-hash-implementation-in-x86-assembly/sha1-fast.c) + +``` +Copyright (c) 2014 Project Nayuki + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +``` + +## [LibTomCrypt](http://www.libtom.net/) +>[Public Domain](https://github.com/libtom/libtomcrypt/blob/develop/LICENSE) + +``` +LibTomCrypt is public domain. As should all quality software be. + +Tom St Denis +``` + +# Dependency Licences (Python Module) + +## [pybind11](https://github.com/pybind/pybind11) +>[BSD 3-Clause License](https://github.com/pybind/pybind11/blob/master/LICENSE) + +``` +Copyright (c) 2016 Wenzel Jakob , All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +You are under no obligation whatsoever to provide any bug fixes, patches, or +upgrades to the features, functionality or performance of the source code +("Enhancements") to anyone; however, if you choose to make your Enhancements +available either publicly, or directly to the author of this software, without +imposing a separate written license agreement for such Enhancements, then you +hereby grant the following license: a non-exclusive, royalty-free perpetual +license to install, use, modify, prepare derivative works, incorporate into +other computer software, distribute, and sublicense such enhancements or +derivative works thereof, in binary and source code form. +``` + + +# Dependency Licences (Testing Only) + ## [CxxTest](http://cxxtest.com/) >[LGPL License](https://github.com/CxxTest/cxxtest/blob/master/COPYING) @@ -262,92 +491,3 @@ apply, that proxy's public statement of acceptance of any version is permanent authorization for you to choose that version for the Library. ``` - -## [PartIO](https://www.disneyanimation.com/technology/partio.html) ->[BSD 3-Clause License (with specific non-attribution clause)](https://github.com/wdas/partio/blob/master/src/lib/io/ZIP.h) - -``` -Copyright 2010 Disney Enterprises, Inc. All rights reserved - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - -* Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright -notice, this list of conditions and the following disclaimer in -the documentation and/or other materials provided with the -distribution. - -* The names "Disney", "Walt Disney Pictures", "Walt Disney Animation -Studios" or the names of its contributors may NOT be used to -endorse or promote products derived from this software without -specific prior written permission from Walt Disney Pictures. - -Disclaimer: THIS SOFTWARE IS PROVIDED BY WALT DISNEY PICTURES AND -CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, -BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE, NONINFRINGEMENT AND TITLE ARE DISCLAIMED. -IN NO EVENT SHALL WALT DISNEY PICTURES, THE COPYRIGHT HOLDER OR -CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND BASED ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. -``` - -## [miniz](https://github.com/richgel999/miniz) ->[Public Domain/MIT License](https://github.com/richgel999/miniz/blob/master/LICENSE) - -``` -This is free and unencumbered software released into the public domain. - -Anyone is free to copy, modify, publish, use, compile, sell, or -distribute this software, either in source code form or as a compiled -binary, for any purpose, commercial or non-commercial, and by any -means. - -In jurisdictions that recognize copyright laws, the author or authors -of this software dedicate any and all copyright interest in the -software to the public domain. We make this dedication for the benefit -of the public at large and to the detriment of our heirs and -successors. We intend this dedication to be an overt act of -relinquishment in perpetuity of all present and future rights to this -software under copyright law. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR -OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, -ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -OTHER DEALINGS IN THE SOFTWARE. - -For more information, please refer to - -Copyright 2013-2014 RAD Game Tools and Valve Software -Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC -All Rights Reserved. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -``` diff --git a/benchmarks/CMakeLists.txt b/benchmarks/CMakeLists.txt index 45d8585c..726db779 100644 --- a/benchmarks/CMakeLists.txt +++ b/benchmarks/CMakeLists.txt @@ -1,11 +1,19 @@ -cmake_minimum_required(VERSION 3.2) +cmake_minimum_required(VERSION 3.1) project(xlnt.benchmarks) -set(CMAKE_CXX_STANDARD 14) +# Require C++11 compiler +set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD_REQUIRED ON) if(NOT COMBINED_PROJECT) - add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../source ${CMAKE_CURRENT_BINARY_DIR}/source) + # Include xlnt library + add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../source ${CMAKE_CURRENT_BINARY_DIR}/source) +endif() + +if(MSVC AND STATIC) + # Link with static C runtime + include(${CMAKE_CURRENT_SOURCE_DIR}/../cmake/ucm.cmake) + ucm_set_runtime(STATIC) endif() set(XLNT_BENCHMARK_DATA_DIR ${CMAKE_CURRENT_SOURCE_DIR}/data) @@ -13,20 +21,24 @@ set(XLNT_BENCHMARK_DATA_DIR ${CMAKE_CURRENT_SOURCE_DIR}/data) file(GLOB BENCHMARK_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) foreach(BENCHMARK_SOURCE IN ITEMS ${BENCHMARK_SOURCES}) - get_filename_component(BENCHMARK_NAME ${BENCHMARK_SOURCE} NAME_WE) - set(BENCHMARK_EXECUTABLE benchmark-${BENCHMARK_NAME}) + # Convert .cpp to benchmark- + get_filename_component(BENCHMARK_NAME ${BENCHMARK_SOURCE} NAME_WE) + set(BENCHMARK_EXECUTABLE benchmark-${BENCHMARK_NAME}) - add_executable(${BENCHMARK_EXECUTABLE} ${BENCHMARK_SOURCE}) + add_executable(${BENCHMARK_EXECUTABLE} ${BENCHMARK_SOURCE}) - target_link_libraries(${BENCHMARK_EXECUTABLE} PRIVATE xlnt) - target_include_directories(${BENCHMARK_EXECUTABLE} - PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../tests) - target_compile_definitions(${BENCHMARK_EXECUTABLE} PRIVATE XLNT_BENCHMARK_DATA_DIR=${XLNT_BENCHMARK_DATA_DIR}) + target_link_libraries(${BENCHMARK_EXECUTABLE} PRIVATE xlnt) + # Need to use some test helpers + target_include_directories(${BENCHMARK_EXECUTABLE} + PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../tests) + target_compile_definitions(${BENCHMARK_EXECUTABLE} + PRIVATE XLNT_BENCHMARK_DATA_DIR=${XLNT_BENCHMARK_DATA_DIR}) - if(MSVC AND NOT STATIC) - add_custom_command(TARGET ${BENCHMARK_EXECUTABLE} POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy_if_different - $ - $) - endif() + if(MSVC AND NOT STATIC) + # Copy xlnt DLL into benchmarks directory + add_custom_command(TARGET ${BENCHMARK_EXECUTABLE} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different + $ + $) + endif() endforeach() diff --git a/book.json b/book.json new file mode 100644 index 00000000..c51052a9 --- /dev/null +++ b/book.json @@ -0,0 +1,10 @@ +{ + "plugins": ["build"], + "pluginsConfig": { + "build": { + "template": "docs/template.ejs", + "format": "man", + "output": "docs/xlnt.3" + } + } +} diff --git a/cmake/ucm.cmake b/cmake/ucm.cmake new file mode 100644 index 00000000..5dc8e4e2 --- /dev/null +++ b/cmake/ucm.cmake @@ -0,0 +1,634 @@ +# +# ucm.cmake - useful cmake macros +# +# Copyright (c) 2016 Viktor Kirilov +# +# Distributed under the MIT Software License +# See accompanying file LICENSE.txt or copy at +# https://opensource.org/licenses/MIT +# +# The documentation can be found at the library's page: +# https://github.com/onqtam/ucm + +cmake_minimum_required(VERSION 2.8.12) + +include(CMakeParseArguments) + +# optionally include cotire - the git submodule might not be inited (or the user might have already included it) +if(NOT COMMAND cotire) + include(${CMAKE_CURRENT_LIST_DIR}/../cotire/CMake/cotire.cmake OPTIONAL) +endif() + +if(COMMAND cotire AND "1.7.9" VERSION_LESS "${COTIRE_CMAKE_MODULE_VERSION}") + set(ucm_with_cotire 1) +else() + set(ucm_with_cotire 0) +endif() + +option(UCM_UNITY_BUILD "Enable unity build for targets registered with the ucm_add_target() macro" OFF) +option(UCM_NO_COTIRE_FOLDER "Do not use a cotire folder in the solution explorer for all unity and cotire related targets" ON) + +# ucm_add_flags +# Adds compiler flags to CMAKE__FLAGS or to a specific config +macro(ucm_add_flags) + cmake_parse_arguments(ARG "C;CXX;CLEAR_OLD" "" "CONFIG" ${ARGN}) + + if(NOT ARG_CONFIG) + set(ARG_CONFIG " ") + endif() + + foreach(CONFIG ${ARG_CONFIG}) + # determine to which flags to add + if(NOT ${CONFIG} STREQUAL " ") + string(TOUPPER ${CONFIG} CONFIG) + set(CXX_FLAGS CMAKE_CXX_FLAGS_${CONFIG}) + set(C_FLAGS CMAKE_C_FLAGS_${CONFIG}) + else() + set(CXX_FLAGS CMAKE_CXX_FLAGS) + set(C_FLAGS CMAKE_C_FLAGS) + endif() + + # clear the old flags + if(${ARG_CLEAR_OLD}) + if("${ARG_CXX}" OR NOT "${ARG_C}") + set(${CXX_FLAGS} "") + endif() + if("${ARG_C}" OR NOT "${ARG_CXX}") + set(${C_FLAGS} "") + endif() + endif() + + # add all the passed flags + foreach(flag ${ARG_UNPARSED_ARGUMENTS}) + if("${ARG_CXX}" OR NOT "${ARG_C}") + set(${CXX_FLAGS} "${${CXX_FLAGS}} ${flag}") + endif() + if("${ARG_C}" OR NOT "${ARG_CXX}") + set(${C_FLAGS} "${${C_FLAGS}} ${flag}") + endif() + endforeach() + endforeach() + +endmacro() + +# ucm_set_flags +# Sets the CMAKE__FLAGS compiler flags or for a specific config +macro(ucm_set_flags) + ucm_add_flags(CLEAR_OLD ${ARGN}) +endmacro() + +# ucm_add_linker_flags +# Adds linker flags to CMAKE__LINKER_FLAGS or to a specific config +macro(ucm_add_linker_flags) + cmake_parse_arguments(ARG "CLEAR_OLD;EXE;MODULE;SHARED;STATIC" "" "CONFIG" ${ARGN}) + + if(NOT ARG_CONFIG) + set(ARG_CONFIG " ") + endif() + + foreach(CONFIG ${ARG_CONFIG}) + string(TOUPPER "${CONFIG}" CONFIG) + + if(NOT ${ARG_EXE} AND NOT ${ARG_MODULE} AND NOT ${ARG_SHARED} AND NOT ${ARG_STATIC}) + set(ARG_EXE 1) + set(ARG_MODULE 1) + set(ARG_SHARED 1) + set(ARG_STATIC 1) + endif() + + set(flags_configs "") + if(${ARG_EXE}) + if(NOT "${CONFIG}" STREQUAL " ") + list(APPEND flags_configs CMAKE_EXE_LINKER_FLAGS_${CONFIG}) + else() + list(APPEND flags_configs CMAKE_EXE_LINKER_FLAGS) + endif() + endif() + if(${ARG_MODULE}) + if(NOT "${CONFIG}" STREQUAL " ") + list(APPEND flags_configs CMAKE_MODULE_LINKER_FLAGS_${CONFIG}) + else() + list(APPEND flags_configs CMAKE_MODULE_LINKER_FLAGS) + endif() + endif() + if(${ARG_SHARED}) + if(NOT "${CONFIG}" STREQUAL " ") + list(APPEND flags_configs CMAKE_SHARED_LINKER_FLAGS_${CONFIG}) + else() + list(APPEND flags_configs CMAKE_SHARED_LINKER_FLAGS) + endif() + endif() + if(${ARG_STATIC}) + if(NOT "${CONFIG}" STREQUAL " ") + list(APPEND flags_configs CMAKE_STATIC_LINKER_FLAGS_${CONFIG}) + else() + list(APPEND flags_configs CMAKE_STATIC_LINKER_FLAGS) + endif() + endif() + + # clear the old flags + if(${ARG_CLEAR_OLD}) + foreach(flags ${flags_configs}) + set(${flags} "") + endforeach() + endif() + + # add all the passed flags + foreach(flag ${ARG_UNPARSED_ARGUMENTS}) + foreach(flags ${flags_configs}) + set(${flags} "${${flags}} ${flag}") + endforeach() + endforeach() + endforeach() +endmacro() + +# ucm_set_linker_flags +# Sets the CMAKE__LINKER_FLAGS linker flags or for a specific config +macro(ucm_set_linker_flags) + ucm_add_linker_flags(CLEAR_OLD ${ARGN}) +endmacro() + +# ucm_gather_flags +# Gathers all lists of flags for printing or manipulation +macro(ucm_gather_flags with_linker result) + set(${result} "") + # add the main flags without a config + list(APPEND ${result} CMAKE_C_FLAGS) + list(APPEND ${result} CMAKE_CXX_FLAGS) + if(${with_linker}) + list(APPEND ${result} CMAKE_EXE_LINKER_FLAGS) + list(APPEND ${result} CMAKE_MODULE_LINKER_FLAGS) + list(APPEND ${result} CMAKE_SHARED_LINKER_FLAGS) + list(APPEND ${result} CMAKE_STATIC_LINKER_FLAGS) + endif() + + if("${CMAKE_CONFIGURATION_TYPES}" STREQUAL "" AND NOT "${CMAKE_BUILD_TYPE}" STREQUAL "") + # handle single config generators - like makefiles/ninja - when CMAKE_BUILD_TYPE is set + string(TOUPPER ${CMAKE_BUILD_TYPE} config) + list(APPEND ${result} CMAKE_C_FLAGS_${config}) + list(APPEND ${result} CMAKE_CXX_FLAGS_${config}) + if(${with_linker}) + list(APPEND ${result} CMAKE_EXE_LINKER_FLAGS_${config}) + list(APPEND ${result} CMAKE_MODULE_LINKER_FLAGS_${config}) + list(APPEND ${result} CMAKE_SHARED_LINKER_FLAGS_${config}) + list(APPEND ${result} CMAKE_STATIC_LINKER_FLAGS_${config}) + endif() + else() + # handle multi config generators (like msvc, xcode) + foreach(config ${CMAKE_CONFIGURATION_TYPES}) + string(TOUPPER ${config} config) + list(APPEND ${result} CMAKE_C_FLAGS_${config}) + list(APPEND ${result} CMAKE_CXX_FLAGS_${config}) + if(${with_linker}) + list(APPEND ${result} CMAKE_EXE_LINKER_FLAGS_${config}) + list(APPEND ${result} CMAKE_MODULE_LINKER_FLAGS_${config}) + list(APPEND ${result} CMAKE_SHARED_LINKER_FLAGS_${config}) + list(APPEND ${result} CMAKE_STATIC_LINKER_FLAGS_${config}) + endif() + endforeach() + endif() +endmacro() + +# ucm_set_runtime +# Sets the runtime (static/dynamic) for msvc/gcc +macro(ucm_set_runtime) + cmake_parse_arguments(ARG "STATIC;DYNAMIC" "" "" ${ARGN}) + + if(ARG_UNPARSED_ARGUMENTS) + message(FATAL_ERROR "unrecognized arguments: ${ARG_UNPARSED_ARGUMENTS}") + endif() + + if(CMAKE_CXX_COMPILER_ID MATCHES "Clang" STREQUAL "") + message(AUTHOR_WARNING "ucm_set_runtime() does not support clang yet!") + endif() + + ucm_gather_flags(0 flags_configs) + + # add/replace the flags + # note that if the user has messed with the flags directly this function might fail + # - for example if with MSVC and the user has removed the flags - here we just switch/replace them + if("${ARG_STATIC}") + foreach(flags ${flags_configs}) + if(CMAKE_CXX_COMPILER_ID MATCHES "GNU") + if(NOT ${flags} MATCHES "-static-libstdc\\+\\+") + set(${flags} "${${flags}} -static-libstdc++") + endif() + if(NOT ${flags} MATCHES "-static-libgcc") + set(${flags} "${${flags}} -static-libgcc") + endif() + elseif(MSVC) + if(${flags} MATCHES "/MD") + string(REGEX REPLACE "/MD" "/MT" ${flags} "${${flags}}") + endif() + endif() + endforeach() + elseif("${ARG_DYNAMIC}") + foreach(flags ${flags_configs}) + if(CMAKE_CXX_COMPILER_ID MATCHES "GNU") + if(${flags} MATCHES "-static-libstdc\\+\\+") + string(REGEX REPLACE "-static-libstdc\\+\\+" "" ${flags} "${${flags}}") + endif() + if(${flags} MATCHES "-static-libgcc") + string(REGEX REPLACE "-static-libgcc" "" ${flags} "${${flags}}") + endif() + elseif(MSVC) + if(${flags} MATCHES "/MT") + string(REGEX REPLACE "/MT" "/MD" ${flags} "${${flags}}") + endif() + endif() + endforeach() + endif() +endmacro() + +# ucm_print_flags +# Prints all compiler flags for all configurations +macro(ucm_print_flags) + ucm_gather_flags(1 flags_configs) + message("") + foreach(flags ${flags_configs}) + message("${flags}: ${${flags}}") + endforeach() + message("") +endmacro() + +# ucm_count_sources +# Counts the number of source files +macro(ucm_count_sources) + cmake_parse_arguments(ARG "" "RESULT" "" ${ARGN}) + if(${ARG_RESULT} STREQUAL "") + message(FATAL_ERROR "Need to pass RESULT and a variable name to ucm_count_sources()") + endif() + + set(result 0) + foreach(SOURCE_FILE ${ARG_UNPARSED_ARGUMENTS}) + if("${SOURCE_FILE}" MATCHES \\.\(c|C|cc|cp|cpp|CPP|c\\+\\+|cxx|i|ii\)$) + math(EXPR result "${result} + 1") + endif() + endforeach() + set(${ARG_RESULT} ${result}) +endmacro() + +# ucm_include_file_in_sources +# Includes the file to the source with compiler flags +macro(ucm_include_file_in_sources) + cmake_parse_arguments(ARG "" "HEADER" "" ${ARGN}) + if(${ARG_HEADER} STREQUAL "") + message(FATAL_ERROR "Need to pass HEADER and a header file to ucm_include_file_in_sources()") + endif() + + foreach(src ${ARG_UNPARSED_ARGUMENTS}) + if(${src} MATCHES \\.\(c|C|cc|cp|cpp|CPP|c\\+\\+|cxx\)$) + # get old flags + get_source_file_property(old_compile_flags ${src} COMPILE_FLAGS) + if(old_compile_flags STREQUAL "NOTFOUND") + set(old_compile_flags "") + endif() + + # update flags + if(MSVC) + set_source_files_properties(${src} PROPERTIES COMPILE_FLAGS + "${old_compile_flags} /FI\"${CMAKE_CURRENT_SOURCE_DIR}/${ARG_HEADER}\"") + else() + set_source_files_properties(${src} PROPERTIES COMPILE_FLAGS + "${old_compile_flags} -include \"${CMAKE_CURRENT_SOURCE_DIR}/${ARG_HEADER}\"") + endif() + endif() + endforeach() +endmacro() + +# ucm_dir_list +# Returns a list of subdirectories for a given directory +macro(ucm_dir_list thedir result) + file(GLOB sub-dir "${thedir}/*") + set(list_of_dirs "") + foreach(dir ${sub-dir}) + if(IS_DIRECTORY ${dir}) + get_filename_component(DIRNAME ${dir} NAME) + LIST(APPEND list_of_dirs ${DIRNAME}) + endif() + endforeach() + set(${result} ${list_of_dirs}) +endmacro() + +# ucm_trim_front_words +# Trims X times the front word from a string separated with "/" and removes +# the front "/" characters after that (used for filters for visual studio) +macro(ucm_trim_front_words source out num_filter_trims) + set(result "${source}") + set(counter 0) + while(${counter} LESS ${num_filter_trims}) + MATH(EXPR counter "${counter} + 1") + # removes everything at the front up to a "/" character + string(REGEX REPLACE "^([^/]+)" "" result "${result}") + # removes all consecutive "/" characters from the front + string(REGEX REPLACE "^(/+)" "" result "${result}") + endwhile() + set(${out} ${result}) +endmacro() + +# ucm_remove_files +# Removes source files from a list of sources (path is the relative path for it to be found) +macro(ucm_remove_files) + cmake_parse_arguments(ARG "" "FROM" "" ${ARGN}) + + if("${ARG_UNPARSED_ARGUMENTS}" STREQUAL "") + message(FATAL_ERROR "Need to pass some relative files to ucm_remove_files()") + endif() + if(${ARG_FROM} STREQUAL "") + message(FATAL_ERROR "Need to pass FROM and a variable name to ucm_remove_files()") + endif() + + foreach(cur_file ${ARG_UNPARSED_ARGUMENTS}) + list(REMOVE_ITEM ${ARG_FROM} ${cur_file}) + endforeach() +endmacro() + +# ucm_remove_directories +# Removes all source files from the given directories from the sources list +macro(ucm_remove_directories) + cmake_parse_arguments(ARG "" "FROM" "MATCHES" ${ARGN}) + + if("${ARG_UNPARSED_ARGUMENTS}" STREQUAL "") + message(FATAL_ERROR "Need to pass some relative directories to ucm_remove_directories()") + endif() + if(${ARG_FROM} STREQUAL "") + message(FATAL_ERROR "Need to pass FROM and a variable name to ucm_remove_directories()") + endif() + + foreach(cur_dir ${ARG_UNPARSED_ARGUMENTS}) + foreach(cur_file ${${ARG_FROM}}) + string(REGEX MATCH ${cur_dir} res ${cur_file}) + if(NOT "${res}" STREQUAL "") + if("${ARG_MATCHES}" STREQUAL "") + list(REMOVE_ITEM ${ARG_FROM} ${cur_file}) + else() + foreach(curr_ptrn ${ARG_MATCHES}) + string(REGEX MATCH ${curr_ptrn} res ${cur_file}) + if(NOT "${res}" STREQUAL "") + list(REMOVE_ITEM ${ARG_FROM} ${cur_file}) + break() + endif() + endforeach() + endif() + endif() + endforeach() + endforeach() +endmacro() + +# ucm_add_files_impl +macro(ucm_add_files_impl result trim files) + foreach(cur_file ${files}) + SET(${result} ${${result}} ${cur_file}) + get_filename_component(FILEPATH ${cur_file} PATH) + ucm_trim_front_words("${FILEPATH}" FILEPATH "${trim}") + # replacing forward slashes with back slashes so filters can be generated (back slash used in parsing...) + STRING(REPLACE "/" "\\" FILTERS "${FILEPATH}") + SOURCE_GROUP("${FILTERS}" FILES ${cur_file}) + endforeach() +endmacro() + +# ucm_add_files +# Adds files to a list of sources +macro(ucm_add_files) + cmake_parse_arguments(ARG "" "TO;FILTER_POP" "" ${ARGN}) + + if("${ARG_UNPARSED_ARGUMENTS}" STREQUAL "") + message(FATAL_ERROR "Need to pass some relative files to ucm_add_files()") + endif() + if(${ARG_TO} STREQUAL "") + message(FATAL_ERROR "Need to pass TO and a variable name to ucm_add_files()") + endif() + + if("${ARG_FILTER_POP}" STREQUAL "") + set(ARG_FILTER_POP 0) + endif() + + ucm_add_files_impl(${ARG_TO} ${ARG_FILTER_POP} "${ARG_UNPARSED_ARGUMENTS}") +endmacro() + +# ucm_add_dir_impl +macro(ucm_add_dir_impl result rec trim dirs_in additional_ext) + set(dirs "${dirs_in}") + + # handle the "" and "." cases + if("${dirs}" STREQUAL "" OR "${dirs}" STREQUAL ".") + set(dirs "./") + endif() + + foreach(cur_dir ${dirs}) + # to circumvent some linux/cmake/path issues - barely made it work... + if(cur_dir STREQUAL "./") + set(cur_dir "") + else() + set(cur_dir "${cur_dir}/") + endif() + + # since unix is case sensitive - add these valid extensions too + # we don't use "UNIX" but instead "CMAKE_HOST_UNIX" because we might be cross + # compiling (for example emscripten) under windows and UNIX may be set to 1 + # Also OSX is case insensitive like windows... + set(additional_file_extensions "") + if(CMAKE_HOST_UNIX AND NOT APPLE) + set(additional_file_extensions + "${cur_dir}*.CPP" + "${cur_dir}*.C" + "${cur_dir}*.H" + "${cur_dir}*.HPP" + ) + endif() + + foreach(ext ${additional_ext}) + list(APPEND additional_file_extensions "${cur_dir}*.${ext}") + endforeach() + + # find all sources and set them as result + FILE(GLOB found_sources RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" + # https://gcc.gnu.org/onlinedocs/gcc-4.4.1/gcc/Overall-Options.html#index-file-name-suffix-71 + # sources + "${cur_dir}*.cpp" + "${cur_dir}*.cxx" + "${cur_dir}*.c++" + "${cur_dir}*.cc" + "${cur_dir}*.cp" + "${cur_dir}*.c" + "${cur_dir}*.i" + "${cur_dir}*.ii" + # headers + "${cur_dir}*.h" + "${cur_dir}*.h++" + "${cur_dir}*.hpp" + "${cur_dir}*.hxx" + "${cur_dir}*.hh" + "${cur_dir}*.inl" + "${cur_dir}*.inc" + "${cur_dir}*.ipp" + "${cur_dir}*.ixx" + "${cur_dir}*.txx" + "${cur_dir}*.tpp" + "${cur_dir}*.tcc" + "${cur_dir}*.tpl" + ${additional_file_extensions}) + SET(${result} ${${result}} ${found_sources}) + + # set the proper filters + ucm_trim_front_words("${cur_dir}" cur_dir "${trim}") + # replacing forward slashes with back slashes so filters can be generated (back slash used in parsing...) + STRING(REPLACE "/" "\\" FILTERS "${cur_dir}") + SOURCE_GROUP("${FILTERS}" FILES ${found_sources}) + endforeach() + + if(${rec}) + foreach(cur_dir ${dirs}) + ucm_dir_list("${cur_dir}" subdirs) + foreach(subdir ${subdirs}) + ucm_add_dir_impl(${result} ${rec} ${trim} "${cur_dir}/${subdir}" "${additional_ext}") + endforeach() + endforeach() + endif() +endmacro() + +# ucm_add_dirs +# Adds all files from directories traversing them recursively to a list of sources +# and generates filters according to their location (accepts relative paths only). +# Also this macro trims X times the front word from the filter string for visual studio filters. +macro(ucm_add_dirs) + cmake_parse_arguments(ARG "RECURSIVE" "TO;FILTER_POP" "ADDITIONAL_EXT" ${ARGN}) + + if(${ARG_TO} STREQUAL "") + message(FATAL_ERROR "Need to pass TO and a variable name to ucm_add_dirs()") + endif() + + if("${ARG_FILTER_POP}" STREQUAL "") + set(ARG_FILTER_POP 0) + endif() + + ucm_add_dir_impl(${ARG_TO} ${ARG_RECURSIVE} ${ARG_FILTER_POP} "${ARG_UNPARSED_ARGUMENTS}" "${ARG_ADDITIONAL_EXT}") +endmacro() + +# ucm_add_target +# Adds a target eligible for cotiring - unity build and/or precompiled header +macro(ucm_add_target) + cmake_parse_arguments(ARG "UNITY" "NAME;TYPE;PCH_FILE;CPP_PER_UNITY" "UNITY_EXCLUDED;SOURCES" ${ARGN}) + + if(NOT "${ARG_UNPARSED_ARGUMENTS}" STREQUAL "") + message(FATAL_ERROR "Unrecognized options passed to ucm_add_target()") + endif() + if("${ARG_NAME}" STREQUAL "") + message(FATAL_ERROR "Need to pass NAME and a name for the target to ucm_add_target()") + endif() + set(valid_types EXECUTABLE STATIC SHARED MODULE) + list(FIND valid_types "${ARG_TYPE}" is_type_valid) + if(${is_type_valid} STREQUAL "-1") + message(FATAL_ERROR "Need to pass TYPE and the type for the target [EXECUTABLE/STATIC/SHARED/MODULE] to ucm_add_target()") + endif() + if("${ARG_SOURCES}" STREQUAL "") + message(FATAL_ERROR "Need to pass SOURCES and a list of source files to ucm_add_target()") + endif() + + # init with the global unity flag + set(do_unity ${UCM_UNITY_BUILD}) + + # check the UNITY argument + if(NOT ARG_UNITY) + set(do_unity FALSE) + endif() + + # if target is excluded through the exclusion list + list(FIND UCM_UNITY_BUILD_EXCLUDE_TARGETS ${ARG_NAME} is_target_excluded) + if(NOT ${is_target_excluded} STREQUAL "-1") + set(do_unity FALSE) + endif() + + # unity build only for targets with > 1 source file (otherwise there will be an additional unnecessary target) + if(do_unity) # optimization + ucm_count_sources(${ARG_SOURCES} RESULT num_sources) + if(${num_sources} LESS 2) + set(do_unity FALSE) + endif() + endif() + + set(wanted_cotire ${do_unity}) + + # if cotire cannot be used + if(do_unity AND NOT ucm_with_cotire) + set(do_unity FALSE) + endif() + + # inform the developer that the current target might benefit from a unity build + if(NOT ARG_UNITY AND ${UCM_UNITY_BUILD}) + ucm_count_sources(${ARG_SOURCES} RESULT num_sources) + if(${num_sources} GREATER 1) + message(AUTHOR_WARNING "Target '${ARG_NAME}' may benefit from a unity build.\nIt has ${num_sources} sources - enable with UNITY flag") + endif() + endif() + + # prepare for the unity build + set(orig_target ${ARG_NAME}) + if(do_unity) + # the original target will be added with a different name than the requested + set(orig_target ${ARG_NAME}_ORIGINAL) + + # exclude requested files from unity build of the current target + foreach(excluded_file "${ARG_UNITY_EXCLUDED}") + set_source_files_properties(${excluded_file} PROPERTIES COTIRE_EXCLUDED TRUE) + endforeach() + endif() + + # add the original target + if(${ARG_TYPE} STREQUAL "EXECUTABLE") + add_executable(${orig_target} ${ARG_SOURCES}) + else() + add_library(${orig_target} ${ARG_TYPE} ${ARG_SOURCES}) + endif() + + if(do_unity) + # set the number of unity cpp files to be used for the unity target + if(NOT "${ARG_CPP_PER_UNITY}" STREQUAL "") + set_property(TARGET ${orig_target} PROPERTY COTIRE_UNITY_SOURCE_MAXIMUM_NUMBER_OF_INCLUDES "${ARG_CPP_PER_UNITY}") + else() + set_property(TARGET ${orig_target} PROPERTY COTIRE_UNITY_SOURCE_MAXIMUM_NUMBER_OF_INCLUDES "100") + endif() + + if(NOT "${ARG_PCH_FILE}" STREQUAL "") + set_target_properties(${orig_target} PROPERTIES COTIRE_CXX_PREFIX_HEADER_INIT "${ARG_PCH_FILE}") + else() + set_target_properties(${orig_target} PROPERTIES COTIRE_ENABLE_PRECOMPILED_HEADER FALSE) + endif() + # add a unity target for the original one with the name intended for the original + set_target_properties(${orig_target} PROPERTIES COTIRE_UNITY_TARGET_NAME ${ARG_NAME}) + + # this is the library call that does the magic + cotire(${orig_target}) + set_target_properties(clean_cotire PROPERTIES FOLDER "CMakePredefinedTargets") + + # disable the original target and enable the unity one + get_target_property(unity_target_name ${orig_target} COTIRE_UNITY_TARGET_NAME) + set_target_properties(${orig_target} PROPERTIES EXCLUDE_FROM_ALL 1 EXCLUDE_FROM_DEFAULT_BUILD 1) + set_target_properties(${unity_target_name} PROPERTIES EXCLUDE_FROM_ALL 0 EXCLUDE_FROM_DEFAULT_BUILD 0) + + # also set the name of the target output as the original one + set_target_properties(${unity_target_name} PROPERTIES OUTPUT_NAME ${ARG_NAME}) + if(UCM_NO_COTIRE_FOLDER) + # reset the folder property so all unity targets dont end up in a single folder in the solution explorer of VS + set_target_properties(${unity_target_name} PROPERTIES FOLDER "") + endif() + set_target_properties(all_unity PROPERTIES FOLDER "CMakePredefinedTargets") + elseif(NOT "${ARG_PCH_FILE}" STREQUAL "") + set(wanted_cotire TRUE) + if(ucm_with_cotire) + set_target_properties(${orig_target} PROPERTIES COTIRE_ADD_UNITY_BUILD FALSE) + set_target_properties(${orig_target} PROPERTIES COTIRE_CXX_PREFIX_HEADER_INIT "${ARG_PCH_FILE}") + cotire(${orig_target}) + set_target_properties(clean_cotire PROPERTIES FOLDER "CMakePredefinedTargets") + endif() + endif() + + # print a message if the target was requested to be cotired but it couldn't + if(wanted_cotire AND NOT ucm_with_cotire) + if(NOT COMMAND cotire) + message(AUTHOR_WARNING "Target \"${ARG_NAME}\" not cotired because cotire isn't loaded") + else() + message(AUTHOR_WARNING "Target \"${ARG_NAME}\" not cotired because cotire is older than the required version") + endif() + endif() +endmacro() diff --git a/docs/template.ejs b/docs/template.ejs new file mode 100644 index 00000000..4d03787e --- /dev/null +++ b/docs/template.ejs @@ -0,0 +1,3 @@ +<% for(var i = 0; i < summary.length; i++) {%> +<%- summary[i].content %> +<% } %> diff --git a/docs/xlnt.3 b/docs/xlnt.3 new file mode 100644 index 00000000..2fe512e3 --- /dev/null +++ b/docs/xlnt.3 @@ -0,0 +1,1859 @@ +.\"t +.\" Automatically generated by Pandoc 1.19.2.2 +.\" +.TH "" "" "" "" "" +.hy +.SH [IMAGE: xlnt +logo (https://user-images.githubusercontent.com/1735211/29433390-f37fa28e-836c-11e7-8a60-f8df4c30b424.png)] +.PD 0 +.P +.PD +.PP +[IMAGE: Travis Build +Status (https://travis-ci.org/tfussell/xlnt.svg?branch=master)] (https://travis-ci.org/tfussell/xlnt) +[IMAGE: AppVeyor Build +status (https://ci.appveyor.com/api/projects/status/2hs79a1xoxy16sol?svg=true)] (https://ci.appveyor.com/project/tfussell/xlnt) +[IMAGE: Coverage +Status (https://coveralls.io/repos/github/tfussell/xlnt/badge.svg?branch=master)] (https://coveralls.io/github/tfussell/xlnt?branch=master) +[IMAGE: ReadTheDocs Documentation +Status (https://readthedocs.org/projects/xlnt/badge/?version=latest)] (http://xlnt.readthedocs.org/en/latest/?badge=latest) +[IMAGE: License (http://img.shields.io/badge/license-MIT-blue.svg?style=flat)] (http://opensource.org/licenses/MIT) +.SS Introduction +.PP +xlnt is a modern C++ library for manipulating spreadsheets in memory and +reading/writing them from/to XLSX files as described in ECMA 376 4th +edition (http://www.ecma-international.org/publications/standards/Ecma-376.htm). +The first public release of xlnt version 1.0 was on May 10th, 2017. +Current work is focused on increasing compatibility, improving +performance, and brainstorming future development goals. +For a high\-level summary of what you can do with this library, see the +feature +list (https://tfussell.gitbooks.io/xlnt/content/docs/introduction/Features.html). +Contributions are welcome in the form of pull requests or discussions on +the repository\[aq]s Issues +page (https://github.com/tfussell/xlnt/issues). +.SS Example +.PP +Including xlnt in your project, creating a new spreadsheet, and saving +it as "example.xlsx" +.IP +.nf +\f[C] +#include\ + +int\ main() +{ +\ \ \ \ xlnt::workbook\ wb; +\ \ \ \ xlnt::worksheet\ ws\ =\ wb.active_sheet(); +\ \ \ \ ws.cell("A1").value(5); +\ \ \ \ ws.cell("B2").value("string\ data"); +\ \ \ \ ws.cell("C3").formula("=RAND()"); +\ \ \ \ ws.merge_cells("C3:C4"); +\ \ \ \ ws.freeze_panes("B2"); +\ \ \ \ wb.save("example.xlsx"); +\ \ \ \ return\ 0; +} +//\ compile\ with\ \-std=c++14\ \-Ixlnt/include\ \-lxlnt +\f[] +.fi +.SS Documentation +.PP +Documentation for the current release of xlnt is available +here (https://tfussell.gitbooks.io/xlnt/content/). +.SS License +.PP +xlnt is released to the public for free under the terms of the MIT +License. +See LICENSE.md (https://github.com/tfussell/xlnt/blob/master/LICENSE.md) +for the full text of the license and the licenses of xlnt\[aq]s +third\-party dependencies. +LICENSE.md (https://github.com/tfussell/xlnt/blob/master/LICENSE.md) +should be distributed alongside any assemblies that use xlnt in source +or compiled form. +.SS Introduction +.IP \[bu] 2 +Motivation (Motivation.md) +.IP \[bu] 2 +Examples (Examples.md) +.IP \[bu] 2 +Features (Features.md) +.IP \[bu] 2 +Installation (Installation.md) +.SS Motivation +.SS Examples +.SS Simple \- reading from an existing xlsx spread sheet. +.PP +The following C plus plus code will read the values from an xlsx file +and print the string values to the screen. +This is a very simple example to get you started. +.IP +.nf +\f[C] +#include\ +#include\ + +int\ main() +{ +\ \ \ \ xlnt::workbook\ wb; +\ \ \ \ wb.load("/home/timothymccallum/test.xlsx"); +\ \ \ \ auto\ ws\ =\ wb.active_sheet(); +\ \ \ \ std::clog\ <<\ "Processing\ spread\ sheet"\ <<\ std::endl; +\ \ \ \ for\ (auto\ row\ :\ ws.rows(false))\ +\ \ \ \ {\ +\ \ \ \ \ \ \ \ for\ (auto\ cell\ :\ row)\ +\ \ \ \ {\ +\ \ \ \ \ \ \ \ std::clog\ <<\ cell.to_string()\ <<\ std::endl; +\ \ \ \ } +\ \ \ \ } +\ \ \ \ std::clog\ <<\ "Processing\ complete"\ <<\ std::endl; +\ \ \ \ return\ 0; +} +\f[] +.fi +.PP +Save the contents of the above file +.IP +.nf +\f[C] +/home/timothymccallum/process.cpp +\f[] +.fi +.PP +Compile by typing the following command +.IP +.nf +\f[C] +g++\ \-std=c++14\ \-lxlnt\ process.cpp\ \-o\ process +\f[] +.fi +.PP +Excecute by typing the following command +.IP +.nf +\f[C] +\&./process +\f[] +.fi +.PP +The output of the program, in my case, is as follows +.IP +.nf +\f[C] +Processing\ spread\ sheet +This\ is\ cell\ A1. +This\ is\ cell\ B1 +\&...\ and\ this\ is\ cell\ C1 +We\ are\ now\ on\ the\ second\ row\ at\ cell\ A2 +B2 +C2 +Processing\ complete +\f[] +.fi +.PP +As you can see the process.cpp file simply walks through the spread +sheet values row by row and column by column (A1, B1, C1, A2, B2, C2 and +so on). +.SS Simple \- storing a spread sheet in a 2 dimensional C++ Vector for +further processing +.PP +Loading a spread sheet into a Vector provides oppourtunities for you to +perform high performance processing. +There will be more examples on performing fast look\-ups, merging data, +performing deduplication and more. +For now, let\[aq]s just learn how to get the spread sheet loaded into +memory. +.IP +.nf +\f[C] +#include\ +#include\ +#include\ + +int\ main() +{ +\ \ \ \ xlnt::workbook\ wb; +\ \ \ \ wb.load("/home/timothymccallum/test.xlsx"); +\ \ \ \ auto\ ws\ =\ wb.active_sheet(); +\ \ \ \ std::clog\ <<\ "Processing\ spread\ sheet"\ <<\ std::endl; +\ \ \ \ std::clog\ <<\ "Creating\ a\ single\ vector\ which\ stores\ the\ whole\ spread\ sheet"\ <<\ std::endl; +\ \ \ \ std::vector<\ std::vector\ >\ theWholeSpreadSheet; +\ \ \ \ for\ (auto\ row\ :\ ws.rows(false))\ +\ \ \ \ {\ +\ \ \ \ \ \ \ \ std::clog\ <<\ "Creating\ a\ fresh\ vector\ for\ just\ this\ row\ in\ the\ spread\ sheet"\ <<\ std::endl; +\ \ \ \ std::vector\ aSingleRow; +\ \ \ \ for\ (auto\ cell\ :\ row)\ +\ \ \ \ {\ +\ \ \ \ \ \ \ \ std::clog\ <<\ "Adding\ this\ cell\ to\ the\ row"\ <<\ std::endl; +\ \ \ \ \ \ \ \ aSingleRow.push_back(cell.to_string()); +\ \ \ \ } +\ \ \ \ std::clog\ <<\ "Adding\ this\ entire\ row\ to\ the\ vector\ which\ stores\ the\ whole\ spread\ sheet"\ <<\ std::endl; +\ \ \ \ theWholeSpreadSheet.push_back(aSingleRow); +\ \ \ \ } +\ \ \ \ std::clog\ <<\ "Processing\ complete"\ <<\ std::endl; +\ \ \ \ std::clog\ <<\ "Reading\ the\ vector\ and\ printing\ output\ to\ the\ screen"\ <<\ std::endl; +\ \ \ \ for\ (int\ rowInt\ =\ 0;\ rowInt\ <\ theWholeSpreadSheet.size();\ rowInt++) +\ \ \ \ { +\ \ \ \ \ \ \ \ for\ (int\ colInt\ =\ 0;\ colInt\ <\ theWholeSpreadSheet.at(rowInt).size();\ colInt++) +\ \ \ \ { +\ \ \ \ \ \ \ \ std::cout\ <<\ theWholeSpreadSheet.at(rowInt).at(colInt)\ <<\ std::endl; +\ \ \ \ \ \ \ \ } +\ \ \ \ } +\ \ \ \ return\ 0; +} +\f[] +.fi +.PP +Save the contents of the above file +.IP +.nf +\f[C] +/home/timothymccallum/process.cpp +\f[] +.fi +.PP +Compile by typing the following command +.IP +.nf +\f[C] +g++\ \-std=c++14\ \-lxlnt\ process.cpp\ \-o\ process +\f[] +.fi +.PP +Excecute by typing the following command +.IP +.nf +\f[C] +\&./process +\f[] +.fi +.PP +The output of the program, in my case, is as follows +.IP +.nf +\f[C] +Processing\ spread\ sheet +Creating\ a\ single\ vector\ which\ stores\ the\ whole\ spread\ sheet +Creating\ a\ fresh\ vector\ for\ just\ this\ row\ in\ the\ spread\ sheet +Adding\ this\ cell\ to\ the\ row +Adding\ this\ cell\ to\ the\ row +Adding\ this\ cell\ to\ the\ row +Adding\ this\ entire\ row\ to\ the\ vector\ which\ stores\ the\ whole\ spread\ sheet +Creating\ a\ fresh\ vector\ for\ just\ this\ row\ in\ the\ spread\ sheet +Adding\ this\ cell\ to\ the\ row +Adding\ this\ cell\ to\ the\ row +Adding\ this\ cell\ to\ the\ row +Adding\ this\ entire\ row\ to\ the\ vector\ which\ stores\ the\ whole\ spread\ sheet +Processing\ complete +Reading\ the\ vector\ and\ printing\ output\ to\ the\ screen +This\ is\ cell\ A1. +This\ is\ cell\ B1 +\&...\ and\ this\ is\ cell\ C1 +We\ are\ now\ on\ the\ second\ row\ at\ cell\ A2 +B2 +C2 +\f[] +.fi +.PP +You will have noticed that this process is very fast. +If you type the "time" as shown below, you can measure just how fast +loading and retrieving your spread sheet is, using xlnt; In this case +only a fraction of a second. +More on this later. +.IP +.nf +\f[C] +time\ ./process\ +\&... +real\ \ \ \ 0m0.044s +\f[] +.fi +.SS Simple \- writing values to a new xlsx spread sheet. +.IP +.nf +\f[C] +#include\ +#include\ +#include\ +#include\ + +int\ main() +{ +\ \ \ \ //Creating\ a\ 2\ dimensional\ vector\ which\ we\ will\ write\ values\ to +\ \ \ \ std::vector<\ std::vector\ >\ wholeWorksheet; +\ \ \ \ //Looping\ through\ each\ row\ (100\ rows\ as\ per\ the\ second\ argument\ in\ the\ for\ loop) +\ \ \ \ for\ (int\ outer\ =\ 0;\ outer\ <\ 100;\ outer++) +\ \ \ \ { +\ \ \ \ \ \ \ \ //Creating\ a\ fresh\ vector\ for\ a\ fresh\ row +\ \ \ \ std::vector\ singleRow; +\ \ \ \ //Looping\ through\ each\ of\ the\ columns\ (100\ as\ per\ the\ second\ argument\ in\ the\ for\ loop)\ in\ this\ particular\ row +\ \ \ \ for(int\ inner\ =\ 0;\ inner\ <\ 100;\ inner++) +\ \ \ \ { +\ \ \ \ \ \ \ \ //Adding\ a\ single\ value\ in\ each\ cell\ of\ the\ row\ +\ \ \ \ \ \ \ \ std::string\ val\ =\ std::to_string(inner\ +\ 1); +\ \ \ \ \ \ \ \ singleRow.push_back(val);\ \ \ \ \ \ \ \ \ \ \ \ +\ \ \ \ } +\ \ \ \ //Adding\ the\ single\ row\ to\ the\ 2\ dimensional\ vector +\ \ \ \ wholeWorksheet.push_back(singleRow); +\ \ \ \ std::clog\ <<\ "Writing\ to\ row\ "\ <<\ outer\ <<\ "\ in\ the\ vector\ "\ <<\ std::endl; +\ \ \ \ } +\ \ \ \ //Writing\ to\ the\ spread\ sheet +\ \ \ \ //Creating\ the\ output\ workbook\ +\ \ \ \ std::clog\ <<\ "Creating\ workbook"\ <<\ std::endl; +\ \ \ \ xlnt::workbook\ wbOut; +\ \ \ \ //Setting\ the\ destination\ output\ file\ name +\ \ \ \ std::string\ dest_filename\ =\ "output.xlsx"; +\ \ \ \ //Creating\ the\ output\ worksheet +\ \ \ \ xlnt::worksheet\ wsOut\ =\ wbOut.active_sheet(); +\ \ \ \ //Giving\ the\ output\ worksheet\ a\ title/name +\ \ \ \ wsOut.title("data"); +\ \ \ \ //We\ will\ now\ be\ looping\ through\ the\ 2\ dimensional\ vector\ which\ we\ created\ above +\ \ \ \ //In\ this\ case\ we\ have\ two\ iterators\ one\ for\ the\ outer\ loop\ (row)\ and\ one\ for\ the\ inner\ loop\ (column) +\ \ \ \ std::clog\ <<\ "Looping\ through\ vector\ and\ writing\ to\ spread\ sheet"\ <<\ std::endl; +\ \ \ \ for\ (int\ fOut\ =\ 0;\ fOut\ <\ wholeWorksheet.size();\ fOut++) +\ \ \ \ { +\ \ \ \ \ \ \ \ std::clog\ <<\ "Row"\ <<\ fOut\ <<\ std::endl; +\ \ \ \ \ \ \ \ for\ (int\ fIn\ =\ 0;\ fIn\ <\ wholeWorksheet.at(fOut).size();\ fIn++) +\ \ \ \ \ \ \ \ { +\ \ \ \ \ \ \ \ \ \ \ \ //Take\ notice\ of\ the\ difference\ between\ accessing\ the\ vector\ and\ accessing\ the\ work\ sheet +\ \ \ \ \ \ \ \ //As\ you\ may\ already\ know\ Excel\ spread\ sheets\ start\ at\ row\ 1\ and\ column\ 1\ (not\ row\ 0\ and\ column\ 0\ like\ you\ would\ expect\ from\ a\ C++\ vector)\ +\ \ \ \ \ \ \ \ //In\ short\ the\ xlnt\ cell\ reference\ starts\ at\ column\ 1\ row\ 1\ (hence\ the\ +\ 1s\ below)\ and\ the\ vector\ reference\ starts\ at\ row\ 0\ and\ column\ 0 +\ \ \ \ \ \ \ \ wsOut.cell(xlnt::cell_reference(fIn\ +\ 1,\ fOut\ +\ 1)).value(wholeWorksheet.at(fOut).at(fIn)); +\ \ \ \ \ \ \ \ //Further\ clarification\ to\ avoid\ confusion +\ \ \ \ \ \ \ \ //Cell\ reference\ arguments\ are\ (column\ number,\ row\ number);\ e.g.\ cell_reference(fIn\ +\ 1,\ fOut\ +\ 1) +\ \ \ \ \ \ \ \ //Vector\ arguments\ are\ (row\ number,\ column\ number);\ e.g.\ wholeWorksheet.at(fOut).at(fIn) +\ \ \ \ } +\ \ \ \ } +\ \ \ \ std::clog\ <<\ "Finished\ writing\ spread\ sheet"\ <<\ std::endl; +\ \ \ \ wbOut.save(dest_filename);\ +\ \ \ \ return\ 0; +} +\f[] +.fi +.PP +This process is also quite quick; a time command showed that xlnt was +able to create and write 10, 000 values to the output spread sheet in +0.582 seconds. +.SS Features +.PP +.TS +tab(@); +l l l l. +T{ +Feature +T}@T{ +Read +T}@T{ +Edit +T}@T{ +Write +T} +_ +T{ +Excel\-style Workbook +T}@T{ +✓ +T}@T{ +✓ +T}@T{ +✓ +T} +T{ +LibreOffice\-style Workbook +T}@T{ +✓ +T}@T{ +✓ +T}@T{ +✓ +T} +T{ +Numbers\-style Workbook +T}@T{ +✓ +T}@T{ +✓ +T}@T{ +✓ +T} +T{ +Encrypted Workbook (Excel 2007\-2010) +T}@T{ +✓ +T}@T{ +✓ +T}@T{ +T} +T{ +Encrypted Workbook (Excel 2013\-2016) +T}@T{ +✓ +T}@T{ +✓ +T}@T{ +T} +T{ +Excel Binary Workbook (.xlsb) +T}@T{ +T}@T{ +T}@T{ +T} +T{ +Excel Macro\-Enabled Workbook (.xlsm) +T}@T{ +T}@T{ +T}@T{ +T} +T{ +Excel Macro\-Enabled Template (.xltm) +T}@T{ +T}@T{ +T}@T{ +T} +T{ +Document Properties +T}@T{ +✓ +T}@T{ +✓ +T}@T{ +✓ +T} +T{ +Numeric Cell Values +T}@T{ +✓ +T}@T{ +✓ +T}@T{ +✓ +T} +T{ +Inline String Cell Values +T}@T{ +✓ +T}@T{ +✓ +T}@T{ +✓ +T} +T{ +Shared String Cell Values +T}@T{ +✓ +T}@T{ +✓ +T}@T{ +✓ +T} +T{ +Shared String Text Run Formatting (e.g. +varied fonts within a cell) +T}@T{ +✓ +T}@T{ +✓ +T}@T{ +✓ +T} +T{ +Hyperlink Cell Values +T}@T{ +T}@T{ +T}@T{ +T} +T{ +Formula Cell Values +T}@T{ +T}@T{ +T}@T{ +T} +T{ +Formula Evaluation +T}@T{ +T}@T{ +T}@T{ +T} +T{ +Page Margins +T}@T{ +✓ +T}@T{ +✓ +T}@T{ +✓ +T} +T{ +Page Setup +T}@T{ +T}@T{ +T}@T{ +T} +T{ +Print Area +T}@T{ +T}@T{ +T}@T{ +T} +T{ +Comments +T}@T{ +✓ +T}@T{ +✓ +T}@T{ +T} +T{ +Header and Footer +T}@T{ +T}@T{ +T}@T{ +T} +T{ +Custom Views +T}@T{ +T}@T{ +T}@T{ +T} +T{ +Charts +T}@T{ +T}@T{ +T}@T{ +T} +T{ +Chartsheets +T}@T{ +T}@T{ +T}@T{ +T} +T{ +Dialogsheets +T}@T{ +T}@T{ +T}@T{ +T} +T{ +Themes +T}@T{ +✓ +T}@T{ +T}@T{ +✓ +T} +T{ +Cell Styles +T}@T{ +✓ +T}@T{ +✓ +T}@T{ +✓ +T} +T{ +Cell Formats +T}@T{ +✓ +T}@T{ +✓ +T}@T{ +✓ +T} +T{ +Formatting\->Alignment (e.g. +right align) +T}@T{ +✓ +T}@T{ +✓ +T}@T{ +✓ +T} +T{ +Formatting\->Border (e.g. +red cell outline) +T}@T{ +✓ +T}@T{ +✓ +T}@T{ +✓ +T} +T{ +Formatting\->Fill (e.g. +green cell background) +T}@T{ +✓ +T}@T{ +✓ +T}@T{ +✓ +T} +T{ +Formatting\->Font (e.g. +blue cell text) +T}@T{ +✓ +T}@T{ +✓ +T}@T{ +✓ +T} +T{ +Formatting\->Number Format (e.g. +show 2 decimals) +T}@T{ +✓ +T}@T{ +✓ +T}@T{ +✓ +T} +T{ +Formatting\->Protection (e.g. +hide formulas) +T}@T{ +✓ +T}@T{ +✓ +T}@T{ +✓ +T} +T{ +Column Styles +T}@T{ +T}@T{ +T}@T{ +T} +T{ +Row Styles +T}@T{ +T}@T{ +T}@T{ +T} +T{ +Sheet Styles +T}@T{ +T}@T{ +T}@T{ +T} +T{ +Conditional Formatting +T}@T{ +T}@T{ +T}@T{ +T} +T{ +Tables +T}@T{ +T}@T{ +T}@T{ +T} +T{ +Table Formatting +T}@T{ +T}@T{ +T}@T{ +T} +T{ +Pivot Tables +T}@T{ +T}@T{ +T}@T{ +T} +T{ +XLSX Thumbnail +T}@T{ +✓ +T}@T{ +T}@T{ +✓ +T} +T{ +Custom OOXML Properties +T}@T{ +T}@T{ +T}@T{ +T} +T{ +Custom OOXML Parts +T}@T{ +T}@T{ +T}@T{ +T} +T{ +Drawing +T}@T{ +T}@T{ +T}@T{ +T} +T{ +Text Box +T}@T{ +T}@T{ +T}@T{ +T} +T{ +WordArt +T}@T{ +T}@T{ +T}@T{ +T} +T{ +Embedded Content (e.g. +images) +T}@T{ +T}@T{ +T}@T{ +T} +T{ +Excel VBA +T}@T{ +T}@T{ +T}@T{ +T} +.TE +.SH Getting xlnt +.SS Binaries +.SS Homebrew +.SS Arch +.SS vcpkg +.SS Compiling xlnt 1.x.x from Source on Ubuntu 16.04 LTS (Xenial Xerus) +.PP +Time required: Approximately 5 minutes (depending on your internet +speed) +.IP +.nf +\f[C] +sudo\ apt\-get\ update +sudo\ apt\-get\ upgrade +sudo\ apt\-get\ install\ cmake +sudo\ apt\-get\ install\ zlibc +\f[] +.fi +.PP +The following steps update the compiler and set the appropriate +environment variables \- see note [1] below for the reason why we need +to update the standard available compiler +.IP +.nf +\f[C] +sudo\ add\-apt\-repository\ ppa:ubuntu\-toolchain\-r/test +sudo\ apt\ update +sudo\ apt\-get\ upgrade +sudo\ apt\-get\ install\ gcc\-6\ g++\-6 +export\ CC=/usr/bin/gcc\-6\ \ +export\ CXX=/usr/bin/g++\-6 +\f[] +.fi +.PP +The following steps will intall xlnt Download the zip file from the xlnt +repository +.IP +.nf +\f[C] +cd\ ~ +unzip\ Downloads/xlnt\-master.zip +cd\ xlnt\-master +cmake\ . +make\ \-j\ 2 +sudo\ make\ install +\f[] +.fi +.PP +The following step will map the shared library names to the location of +the corresponding shared library files +.IP +.nf +\f[C] +sudo\ ldconfig +\f[] +.fi +.PP +xlnt will now be ready to use on your Ubuntu instance. +.PP +[1] Xlnt requires a minimum of gcc 6.2.0 The most recent gcc version +available using the standard APT repositories is gcc 5.4.0 (obtained +through build\-essential 12.1ubuntu2). +If these older versions of gcc are used an error "workbook.cpp error +1502:31 \[aq]extended_property\[aq] is not a class, namespace or +enumeration" will occur during the xlnt make command. +.SS Compiling from Source +.PP +Build configurations for Visual Studio, GNU Make, Ninja, and Xcode can +be created using cmake (https://cmake.org/) v3.2+. +A full list of cmake generators can be found +here (https://cmake.org/cmake/help/v3.0/manual/cmake-generators.7.html). +A basic build would look like (starting in the root xlnt directory): +.IP +.nf +\f[C] +mkdir\ build +cd\ build +cmake\ .. +make\ \-j8 +\f[] +.fi +.PP +The resulting shared (e.g. +libxlnt.dylib) library would be found in the build/lib directory. +Other cmake configuration options for xlnt can be found using "cmake +\-LH". +These options include building a static library instead of shared and +whether to build sample executables or not. +An example of building a static library with an Xcode project: +.IP +.nf +\f[C] +mkdir\ build +cd\ build +cmake\ \-D\ STATIC=ON\ \-G\ Xcode\ .. +cmake\ \-\-build\ . +cd\ bin\ &&\ ./xlnt.test +\f[] +.fi +.PP +\f[I]Note for Windows: cmake defaults to building a 32\-bit library +project. To build a 64\-bit library, use the Win64 generator\f[] +.IP +.nf +\f[C] +cmake\ \-G\ "Visual\ Studio\ 14\ 2015\ Win64"\ .. +\f[] +.fi +.SS Basics +.IP \[bu] 2 +Workbook (/docs/basics/Workbook.md) +.IP \[bu] 2 +Worksheet (/docs/basics/Worksheet.md) +.IP \[bu] 2 +Cell (/docs/basics/Cell.md) +.IP \[bu] 2 +Iteration (/docs/basics/Iteration.md) +.SS Workbook +.SS Worksheet +.SS Cell +.SS Iteration +.SS Advanced +.IP \[bu] 2 +Formatting (Formatting.md) +.IP \[bu] 2 +Properties (Properties.md) +.IP \[bu] 2 +Printing (Printing.md) +.IP \[bu] 2 +Encryption (Encryption.md) +.IP \[bu] 2 +Views (Views.md) +.SH Formatting +.SS Format vs. Style +.IP +.nf +\f[C] +#include\ +#include\ + +int\ main() +{ +\ \ \ \ xlnt::workbook\ wb; +\ \ \ \ auto\ cell\ =\ wb.active_sheet().cell("A1"); +\ \ \ \ return\ 0; +} +\f[] +.fi +.PP +In the context of xlnt, format and style have specific distinct +meanings. +A style in xlnt corresponds to a named style created in the "Cell +styles" dropdown in Excel. +It must have a name and optionally any of: alignment, border, fill, +font, number format, protection. +A format in xlnt corresponds to the alignment, border, fill, font, +number format, and protection settings applied to a cell via +right\-click\->"Format Cells". +A cell can have both a format and a style. +The style properties will generally override the format properties. +.SS Number Formatting +.IP +.nf +\f[C] +#include\ +#include\ + +int\ main() +{ +\ \ \ \ xlnt::workbook\ wb; +\ \ \ \ auto\ cell\ =\ wb.active_sheet().cell("A1"); +\ \ \ \ cell.number_format(xlnt::number_format::percentage()); +\ \ \ \ cell.value(0.513); +\ \ \ \ std::cout\ <<\ cell.to_string()\ <<\ std::endl; +\ \ \ \ return\ 0; +} +\f[] +.fi +.PP +An xlnt::number_format is the format code used when displaying a value +in a cell. +For example, a number_format of "0.00" implies that the number 13.726 +should be displayed as "13.73". +Many number formats are built\-in to Excel and can be access with +xlnt::number_format static constructors. +Other custom number formats can be created by passing a string to the +xlnt::number_format constructor (#cell-const-cell-amp). +.SH Properties +.IP +.nf +\f[C] +xlnt::workbook\ wb; + +wb.core_property(xlnt::core_property::category,\ "hors\ categorie"); +wb.core_property(xlnt::core_property::content_status,\ "good"); +wb.core_property(xlnt::core_property::created,\ xlnt::datetime(2017,\ 1,\ 15)); +wb.core_property(xlnt::core_property::creator,\ "me"); +wb.core_property(xlnt::core_property::description,\ "description"); +wb.core_property(xlnt::core_property::identifier,\ "id"); +wb.core_property(xlnt::core_property::keywords,\ {\ "wow",\ "such"\ }); +wb.core_property(xlnt::core_property::language,\ "Esperanto"); +wb.core_property(xlnt::core_property::last_modified_by,\ "someone"); +wb.core_property(xlnt::core_property::last_printed,\ xlnt::datetime(2017,\ 1,\ 15)); +wb.core_property(xlnt::core_property::modified,\ xlnt::datetime(2017,\ 1,\ 15)); +wb.core_property(xlnt::core_property::revision,\ "3"); +wb.core_property(xlnt::core_property::subject,\ "subject"); +wb.core_property(xlnt::core_property::title,\ "title"); +wb.core_property(xlnt::core_property::version,\ "1.0"); + +wb.extended_property(xlnt::extended_property::application,\ "xlnt"); +wb.extended_property(xlnt::extended_property::app_version,\ "0.9.3"); +wb.extended_property(xlnt::extended_property::characters,\ 123); +wb.extended_property(xlnt::extended_property::characters_with_spaces,\ 124); +wb.extended_property(xlnt::extended_property::company,\ "Incorporated\ Inc."); +wb.extended_property(xlnt::extended_property::dig_sig,\ "?"); +wb.extended_property(xlnt::extended_property::doc_security,\ 0); +wb.extended_property(xlnt::extended_property::heading_pairs,\ true); +wb.extended_property(xlnt::extended_property::hidden_slides,\ false); +wb.extended_property(xlnt::extended_property::h_links,\ 0); +wb.extended_property(xlnt::extended_property::hyperlink_base,\ 0); +wb.extended_property(xlnt::extended_property::hyperlinks_changed,\ true); +wb.extended_property(xlnt::extended_property::lines,\ 42); +wb.extended_property(xlnt::extended_property::links_up_to_date,\ false); +wb.extended_property(xlnt::extended_property::manager,\ "johnny"); +wb.extended_property(xlnt::extended_property::m_m_clips,\ "?"); +wb.extended_property(xlnt::extended_property::notes,\ "note"); +wb.extended_property(xlnt::extended_property::pages,\ 19); +wb.extended_property(xlnt::extended_property::paragraphs,\ 18); +wb.extended_property(xlnt::extended_property::presentation_format,\ "format"); +wb.extended_property(xlnt::extended_property::scale_crop,\ true); +wb.extended_property(xlnt::extended_property::shared_doc,\ false); +wb.extended_property(xlnt::extended_property::slides,\ 17); +wb.extended_property(xlnt::extended_property::template_,\ "template!"); +wb.extended_property(xlnt::extended_property::titles_of_parts,\ {\ "title"\ }); +wb.extended_property(xlnt::extended_property::total_time,\ 16); +wb.extended_property(xlnt::extended_property::words,\ 101); + +wb.custom_property("test",\ {\ 1,\ 2,\ 3\ }); +wb.custom_property("Editor",\ "John\ Smith"); + +wb.save("lots_of_properties.xlsx"); +\f[] +.fi +.SS Printing +.SS Encryption +.SS Views +.SS API +.IP \[bu] 2 +cell (cell.md) +.IP \[bu] 2 +cell_reference (cell_reference.md) +.SH cell +.SS \f[C]using\ xlnt::cell::type\ =\ \ cell_typeundefined\f[] +.PP +Alias xlnt::cell_type to xlnt::cell::type since it looks nicer. +.SS \f[C]friend\ class\ detail::xlsx_consumerundefined\f[] +.SS \f[C]friend\ class\ detail::xlsx_producerundefined\f[] +.SS \f[C]friend\ struct\ detail::cell_implundefined\f[] +.SS \f[C]static\ const\ std::unordered_map&\ xlnt::cell::error_codes()\f[] +.PP +Returns a map of error strings such as #DIV/0! and their associated +indices. +.SS \f[C]xlnt::cell::cell(const\ cell\ &)=default\f[] +.PP +Default copy constructor. +.SS \f[C]bool\ xlnt::cell::has_value()\ const\f[] +.PP +Returns true if value has been set and has not been cleared using +cell::clear_value(). +.SS \f[C]T\ xlnt::cell::value()\ const\f[] +.PP +Returns the value of this cell as an instance of type T. +Overloads exist for most C++ fundamental types like bool, int, etc. +as well as for std::string and xlnt datetime types: date, time, +datetime, and timedelta. +.SS \f[C]void\ xlnt::cell::clear_value()\f[] +.PP +Makes this cell have a value of type null. +All other cell attributes are retained. +.SS \f[C]void\ xlnt::cell::value(std::nullptr_t)\f[] +.PP +Sets the type of this cell to null. +.SS \f[C]void\ xlnt::cell::value(bool\ boolean_value)\f[] +.PP +Sets the value of this cell to the given boolean value. +.SS \f[C]void\ xlnt::cell::value(int\ int_value)\f[] +.PP +Sets the value of this cell to the given value. +.SS \f[C]void\ xlnt::cell::value(unsigned\ int\ int_value)\f[] +.PP +Sets the value of this cell to the given value. +.SS \f[C]void\ xlnt::cell::value(long\ long\ int\ int_value)\f[] +.PP +Sets the value of this cell to the given value. +.SS \f[C]void\ xlnt::cell::value(unsigned\ long\ long\ int\ int_value)\f[] +.PP +Sets the value of this cell to the given value. +.SS \f[C]void\ xlnt::cell::value(float\ float_value)\f[] +.PP +Sets the value of this cell to the given value. +.SS \f[C]void\ xlnt::cell::value(double\ float_value)\f[] +.PP +Sets the value of this cell to the given value. +.SS \f[C]void\ xlnt::cell::value(long\ double\ float_value)\f[] +.PP +Sets the value of this cell to the given value. +.SS \f[C]void\ xlnt::cell::value(const\ date\ &date_value)\f[] +.PP +Sets the value of this cell to the given value. +.SS \f[C]void\ xlnt::cell::value(const\ time\ &time_value)\f[] +.PP +Sets the value of this cell to the given value. +.SS \f[C]void\ xlnt::cell::value(const\ datetime\ &datetime_value)\f[] +.PP +Sets the value of this cell to the given value. +.SS \f[C]void\ xlnt::cell::value(const\ timedelta\ &timedelta_value)\f[] +.PP +Sets the value of this cell to the given value. +.SS \f[C]void\ xlnt::cell::value(const\ std::string\ &string_value)\f[] +.PP +Sets the value of this cell to the given value. +.SS \f[C]void\ xlnt::cell::value(const\ char\ *string_value)\f[] +.PP +Sets the value of this cell to the given value. +.SS \f[C]void\ xlnt::cell::value(const\ rich_text\ &text_value)\f[] +.PP +Sets the value of this cell to the given value. +.SS \f[C]void\ xlnt::cell::value(const\ cell\ other_cell)\f[] +.PP +Sets the value and formatting of this cell to that of other_cell. +.SS \f[C]void\ xlnt::cell::value(const\ std::string\ &string_value,\ bool\ infer_type)\f[] +.PP +Analyzes string_value to determine its type, convert it to that type, +and set the value of this cell to that converted value. +.SS \f[C]type\ xlnt::cell::data_type()\ const\f[] +.PP +Returns the type of this cell. +.SS \f[C]void\ xlnt::cell::data_type(type\ t)\f[] +.PP +Sets the type of this cell. +This should usually be done indirectly by setting the value of the cell +to a value of that type. +.SS \f[C]bool\ xlnt::cell::garbage_collectible()\ const\f[] +.PP +There\[aq]s no reason to keep a cell which has no value and is not a +placeholder. +Returns true if this cell has no value, style, isn\[aq]t merged, etc. +.SS \f[C]bool\ xlnt::cell::is_date()\ const\f[] +.PP +Returns true iff this cell\[aq]s number format matches a date format. +.SS \f[C]cell_reference\ xlnt::cell::reference()\ const\f[] +.PP +Returns a cell_reference that points to the location of this cell. +.SS \f[C]column_t\ xlnt::cell::column()\ const\f[] +.PP +Returns the column of this cell. +.SS \f[C]row_t\ xlnt::cell::row()\ const\f[] +.PP +Returns the row of this cell. +.SS \f[C]std::pair\ xlnt::cell::anchor()\ const\f[] +.PP +Returns the location of this cell as an ordered pair (left, top). +.SS \f[C]std::string\ xlnt::cell::hyperlink()\ const\f[] +.PP +Returns the URL of this cell\[aq]s hyperlink. +.SS \f[C]void\ xlnt::cell::hyperlink(const\ std::string\ &url)\f[] +.PP +Adds a hyperlink to this cell pointing to the URL of the given value. +.SS \f[C]void\ xlnt::cell::hyperlink(const\ std::string\ &url,\ const\ std::string\ &display)\f[] +.PP +Adds a hyperlink to this cell pointing to the URI of the given value and +sets the text value of the cell to the given parameter. +.SS \f[C]void\ xlnt::cell::hyperlink(xlnt::cell\ target)\f[] +.PP +Adds an internal hyperlink to this cell pointing to the given cell. +.SS \f[C]bool\ xlnt::cell::has_hyperlink()\ const\f[] +.PP +Returns true if this cell has a hyperlink set. +.SS \f[C]class\ alignment\ xlnt::cell::computed_alignment()\ const\f[] +.PP +Returns the alignment that should be used when displaying this cell +graphically based on the workbook default, the cell\-level format, and +the named style applied to the cell in that order. +.SS \f[C]class\ border\ xlnt::cell::computed_border()\ const\f[] +.PP +Returns the border that should be used when displaying this cell +graphically based on the workbook default, the cell\-level format, and +the named style applied to the cell in that order. +.SS \f[C]class\ fill\ xlnt::cell::computed_fill()\ const\f[] +.PP +Returns the fill that should be used when displaying this cell +graphically based on the workbook default, the cell\-level format, and +the named style applied to the cell in that order. +.SS \f[C]class\ font\ xlnt::cell::computed_font()\ const\f[] +.PP +Returns the font that should be used when displaying this cell +graphically based on the workbook default, the cell\-level format, and +the named style applied to the cell in that order. +.SS \f[C]class\ number_format\ xlnt::cell::computed_number_format()\ const\f[] +.PP +Returns the number format that should be used when displaying this cell +graphically based on the workbook default, the cell\-level format, and +the named style applied to the cell in that order. +.SS \f[C]class\ protection\ xlnt::cell::computed_protection()\ const\f[] +.PP +Returns the protection that should be used when displaying this cell +graphically based on the workbook default, the cell\-level format, and +the named style applied to the cell in that order. +.SS \f[C]bool\ xlnt::cell::has_format()\ const\f[] +.PP +Returns true if this cell has had a format applied to it. +.SS \f[C]const\ class\ format\ xlnt::cell::format()\ const\f[] +.PP +Returns the format applied to this cell. +If this cell has no format, an invalid_attribute exception will be +thrown. +.SS \f[C]void\ xlnt::cell::format(const\ class\ format\ new_format)\f[] +.PP +Applies the cell\-level formatting of new_format to this cell. +.SS \f[C]void\ xlnt::cell::clear_format()\f[] +.PP +Removes the cell\-level formatting from this cell. +This doesn\[aq]t affect the style that may also be applied to the cell. +Throws an invalid_attribute exception if no format is applied. +.SS \f[C]class\ number_format\ xlnt::cell::number_format()\ const\f[] +.PP +Returns the number format of this cell. +.SS \f[C]void\ xlnt::cell::number_format(const\ class\ number_format\ &format)\f[] +.PP +Creates a new format in the workbook, sets its number_format to the +given format, and applies the format to this cell. +.SS \f[C]class\ font\ xlnt::cell::font()\ const\f[] +.PP +Returns the font applied to the text in this cell. +.SS \f[C]void\ xlnt::cell::font(const\ class\ font\ &font_)\f[] +.PP +Creates a new format in the workbook, sets its font to the given font, +and applies the format to this cell. +.SS \f[C]class\ fill\ xlnt::cell::fill()\ const\f[] +.PP +Returns the fill applied to this cell. +.SS \f[C]void\ xlnt::cell::fill(const\ class\ fill\ &fill_)\f[] +.PP +Creates a new format in the workbook, sets its fill to the given fill, +and applies the format to this cell. +.SS \f[C]class\ border\ xlnt::cell::border()\ const\f[] +.PP +Returns the border of this cell. +.SS \f[C]void\ xlnt::cell::border(const\ class\ border\ &border_)\f[] +.PP +Creates a new format in the workbook, sets its border to the given +border, and applies the format to this cell. +.SS \f[C]class\ alignment\ xlnt::cell::alignment()\ const\f[] +.PP +Returns the alignment of the text in this cell. +.SS \f[C]void\ xlnt::cell::alignment(const\ class\ alignment\ &alignment_)\f[] +.PP +Creates a new format in the workbook, sets its alignment to the given +alignment, and applies the format to this cell. +.SS \f[C]class\ protection\ xlnt::cell::protection()\ const\f[] +.PP +Returns the protection of this cell. +.SS \f[C]void\ xlnt::cell::protection(const\ class\ protection\ &protection_)\f[] +.PP +Creates a new format in the workbook, sets its protection to the given +protection, and applies the format to this cell. +.SS \f[C]bool\ xlnt::cell::has_style()\ const\f[] +.PP +Returns true if this cell has had a style applied to it. +.SS \f[C]class\ style\ xlnt::cell::style()\f[] +.PP +Returns a wrapper pointing to the named style applied to this cell. +.SS \f[C]const\ class\ style\ xlnt::cell::style()\ const\f[] +.PP +Returns a wrapper pointing to the named style applied to this cell. +.SS \f[C]void\ xlnt::cell::style(const\ class\ style\ &new_style)\f[] +.PP +Sets the named style applied to this cell to a style named style_name. +Equivalent to style(new_style.name()). +.SS \f[C]void\ xlnt::cell::style(const\ std::string\ &style_name)\f[] +.PP +Sets the named style applied to this cell to a style named style_name. +If this style has not been previously created in the workbook, a +key_not_found exception will be thrown. +.SS \f[C]void\ xlnt::cell::clear_style()\f[] +.PP +Removes the named style from this cell. +An invalid_attribute exception will be thrown if this cell has no style. +This will not affect the cell format of the cell. +.SS \f[C]std::string\ xlnt::cell::formula()\ const\f[] +.PP +Returns the string representation of the formula applied to this cell. +.SS \f[C]void\ xlnt::cell::formula(const\ std::string\ &formula)\f[] +.PP +Sets the formula of this cell to the given value. +This formula string should begin with \[aq]=\[aq]. +.SS \f[C]void\ xlnt::cell::clear_formula()\f[] +.PP +Removes the formula from this cell. +After this is called, has_formula() will return false. +.SS \f[C]bool\ xlnt::cell::has_formula()\ const\f[] +.PP +Returns true if this cell has had a formula applied to it. +.SS \f[C]std::string\ xlnt::cell::to_string()\ const\f[] +.PP +Returns a string representing the value of this cell. +If the data type is not a string, it will be converted according to the +number format. +.SS \f[C]bool\ xlnt::cell::is_merged()\ const\f[] +.PP +Returns true iff this cell has been merged with one or more surrounding +cells. +.SS \f[C]void\ xlnt::cell::merged(bool\ merged)\f[] +.PP +Makes this a merged cell iff merged is true. +Generally, this shouldn\[aq]t be called directly. +Instead, use worksheet::merge_cells on its parent worksheet. +.SS \f[C]std::string\ xlnt::cell::error()\ const\f[] +.PP +Returns the error string that is stored in this cell. +.SS \f[C]void\ xlnt::cell::error(const\ std::string\ &error)\f[] +.PP +Directly assigns the value of this cell to be the given error. +.SS \f[C]cell\ xlnt::cell::offset(int\ column,\ int\ row)\f[] +.PP +Returns a cell from this cell\[aq]s parent workbook at a relative offset +given by the parameters. +.SS \f[C]class\ worksheet\ xlnt::cell::worksheet()\f[] +.PP +Returns the worksheet that owns this cell. +.SS \f[C]const\ class\ worksheet\ xlnt::cell::worksheet()\ const\f[] +.PP +Returns the worksheet that owns this cell. +.SS \f[C]class\ workbook&\ xlnt::cell::workbook()\f[] +.PP +Returns the workbook of the worksheet that owns this cell. +.SS \f[C]const\ class\ workbook&\ xlnt::cell::workbook()\ const\f[] +.PP +Returns the workbook of the worksheet that owns this cell. +.SS \f[C]calendar\ xlnt::cell::base_date()\ const\f[] +.PP +Returns the base date of the parent workbook. +.SS \f[C]std::string\ xlnt::cell::check_string(const\ std::string\ &to_check)\f[] +.PP +Returns to_check after verifying and fixing encoding, size, and illegal +characters. +.SS \f[C]bool\ xlnt::cell::has_comment()\f[] +.PP +Returns true if this cell has a comment applied. +.SS \f[C]void\ xlnt::cell::clear_comment()\f[] +.PP +Deletes the comment applied to this cell if it exists. +.SS \f[C]class\ comment\ xlnt::cell::comment()\f[] +.PP +Gets the comment applied to this cell. +.SS \f[C]void\ xlnt::cell::comment(const\ std::string\ &text,\ const\ std::string\ &author="Microsoft\ Office\ User")\f[] +.PP +Creates a new comment with the given text and optional author and +applies it to the cell. +.SS \f[C]void\ xlnt::cell::comment(const\ std::string\ &comment_text,\ const\ class\ font\ &comment_font,\ const\ std::string\ &author="Microsoft\ Office\ User")\f[] +.PP +Creates a new comment with the given text, formatting, and optional +author and applies it to the cell. +.SS \f[C]void\ xlnt::cell::comment(const\ class\ comment\ &new_comment)\f[] +.PP +Apply the comment provided as the only argument to the cell. +.SS \f[C]double\ xlnt::cell::width()\ const\f[] +.PP +Returns the width of this cell in pixels. +.SS \f[C]double\ xlnt::cell::height()\ const\f[] +.PP +Returns the height of this cell in pixels. +.SS \f[C]cell&\ xlnt::cell::operator=(const\ cell\ &rhs)\f[] +.PP +Makes this cell interally point to rhs. +The cell data originally pointed to by this cell will be unchanged. +.SS \f[C]bool\ xlnt::cell::operator==(const\ cell\ &comparand)\ const\f[] +.PP +Returns true if this cell the same cell as comparand (compared by +reference). +.SS \f[C]bool\ xlnt::cell::operator==(std::nullptr_t)\ const\f[] +.PP +Returns true if this cell is uninitialized. +.SH cell_reference +.SS \f[C]static\ std::pair\ xlnt::cell_reference::split_reference(const\ std::string\ &reference_string)\f[] +.PP +Splits a coordinate string like "A1" into an equivalent pair like {"A", +1}. +.SS \f[C]static\ std::pair\ xlnt::cell_reference::split_reference(const\ std::string\ &reference_string,\ bool\ &absolute_column,\ bool\ &absolute_row)\f[] +.PP +Splits a coordinate string like "A1" into an equivalent pair like {"A", +1}. +Reference parameters absolute_column and absolute_row will be set to +true if column part or row part are prefixed by a dollar\-sign +indicating they are absolute, otherwise false. +.SS \f[C]xlnt::cell_reference::cell_reference()\f[] +.PP +Default constructor makes a reference to the top\-left\-most cell, "A1". +.SS \f[C]xlnt::cell_reference::cell_reference(const\ char\ *reference_string)\f[] +.PP +Constructs a cell_reference from a string reprenting a cell coordinate +(e.g. +$B14). +.SS \f[C]xlnt::cell_reference::cell_reference(const\ std::string\ &reference_string)\f[] +.PP +Constructs a cell_reference from a string reprenting a cell coordinate +(e.g. +$B14). +.SS \f[C]xlnt::cell_reference::cell_reference(column_t\ column,\ row_t\ row)\f[] +.PP +Constructs a cell_reference from a 1\-indexed column index and row +index. +.SS \f[C]cell_reference&\ xlnt::cell_reference::make_absolute(bool\ absolute_column=true,\ bool\ absolute_row=true)\f[] +.PP +Converts a coordinate to an absolute coordinate string (e.g. +B12 \-> $B$12) Defaulting to true, absolute_column and absolute_row can +optionally control whether the resulting cell_reference has an absolute +column (e.g. +B12 \-> $B12) and absolute row (e.g. +B12 \-> B$12) respectively. +.SS \f[C]bool\ xlnt::cell_reference::column_absolute()\ const\f[] +.PP +Returns true if the reference refers to an absolute column, otherwise +false. +.SS \f[C]void\ xlnt::cell_reference::column_absolute(bool\ absolute_column)\f[] +.PP +Makes this reference have an absolute column if absolute_column is true, +otherwise not absolute. +.SS \f[C]bool\ xlnt::cell_reference::row_absolute()\ const\f[] +.PP +Returns true if the reference refers to an absolute row, otherwise +false. +.SS \f[C]void\ xlnt::cell_reference::row_absolute(bool\ absolute_row)\f[] +.PP +Makes this reference have an absolute row if absolute_row is true, +otherwise not absolute. +.SS \f[C]column_t\ xlnt::cell_reference::column()\ const\f[] +.PP +Returns a string that identifies the column of this reference (e.g. +second column from left is "B") +.SS \f[C]void\ xlnt::cell_reference::column(const\ std::string\ &column_string)\f[] +.PP +Sets the column of this reference from a string that identifies a +particular column. +.SS \f[C]column_t::index_t\ xlnt::cell_reference::column_index()\ const\f[] +.PP +Returns a 1\-indexed numeric index of the column of this reference. +.SS \f[C]void\ xlnt::cell_reference::column_index(column_t\ column)\f[] +.PP +Sets the column of this reference from a 1\-indexed number that +identifies a particular column. +.SS \f[C]row_t\ xlnt::cell_reference::row()\ const\f[] +.PP +Returns a 1\-indexed numeric index of the row of this reference. +.SS \f[C]void\ xlnt::cell_reference::row(row_t\ row)\f[] +.PP +Sets the row of this reference from a 1\-indexed number that identifies +a particular row. +.SS \f[C]cell_reference\ xlnt::cell_reference::make_offset(int\ column_offset,\ int\ row_offset)\ const\f[] +.PP +Returns a cell_reference offset from this cell_reference by the number +of columns and rows specified by the parameters. +A negative value for column_offset or row_offset results in a reference +above or left of this cell_reference, respectively. +.SS \f[C]std::string\ xlnt::cell_reference::to_string()\ const\f[] +.PP +Returns a string like "A1" for cell_reference(1, 1). +.SS \f[C]range_reference\ xlnt::cell_reference::to_range()\ const\f[] +.PP +Returns a 1x1 range_reference containing only this cell_reference. +.SS \f[C]range_reference\ xlnt::cell_reference::operator,(const\ cell_reference\ &other)\ const\f[] +.PP +I\[aq]ve always wanted to overload the comma operator. +cell_reference("A", 1), cell_reference("B", 1) will return +range_reference(cell_reference("A", 1), cell_reference("B", 1)) +.SS \f[C]bool\ xlnt::cell_reference::operator==(const\ cell_reference\ &comparand)\ const\f[] +.PP +Returns true if this reference is identical to comparand including in +absoluteness of column and row. +.SS \f[C]bool\ xlnt::cell_reference::operator==(const\ std::string\ &reference_string)\ const\f[] +.PP +Constructs a cell_reference from reference_string and return the result +of their comparison. +.SS \f[C]bool\ xlnt::cell_reference::operator==(const\ char\ *reference_string)\ const\f[] +.PP +Constructs a cell_reference from reference_string and return the result +of their comparison. +.SS \f[C]bool\ xlnt::cell_reference::operator!=(const\ cell_reference\ &comparand)\ const\f[] +.PP +Returns true if this reference is not identical to comparand including +in absoluteness of column and row. +.SS \f[C]bool\ xlnt::cell_reference::operator!=(const\ std::string\ &reference_string)\ const\f[] +.PP +Constructs a cell_reference from reference_string and return the result +of their comparison. +.SS \f[C]bool\ xlnt::cell_reference::operator!=(const\ char\ *reference_string)\ const\f[] +.PP +Constructs a cell_reference from reference_string and return the result +of their comparison. +.SH Change Log +.PP +This project adheres to Semantic Versioning (http://semver.org/). +Every release is documented on the Github +Releases (https://github.com/tfussell/xlnt/releases) page. +.SH Contributing to xlnt +.PP +xlnt welcomes contributions from everyone regardless of skill level +(provided you can write C++ or documentation). +.SS Getting Started +.PP +Look through the list of issues to find something interesting to work +on. +Help is appreciated with any issues, but important timely issues are +labeled as "help wanted". +Issues labeled "docs" might be good for those who want to contribute +without having to know too much C++. +You might also find something that the code is missing without an +associated issue. +That\[aq]s fine to work on to, but it might be best to make an issue +first in case someone else is working on it. +.SS Contributions +.PP +Contributions to xlnt should be made in the form of pull requests on +GitHub. +Each pull request will be reviewed and either merged into the current +development branch or given feedback for changes that would be required +to do so. +.PP +All code in this repository is under the MIT License. +You should agree to these terms before submitting any code to xlnt. +.SS Pull Request Checklist +.IP \[bu] 2 +Branch from the head of the current development branch. +Until version 1.0 is released, this the master branch. +.IP \[bu] 2 +Commits should be as small as possible, while ensuring that each commit +is correct independently (i.e. +each commit should compile and pass all tests). +Commits that don\[aq]t follow the coding style indicated in +\&.clang\-format (e.g. +indentation) are less likely to be accepted until they are fixed. +.IP \[bu] 2 +If your pull request is not getting reviewed or you need a specific +person to review it, you can \@\-reply a reviewer asking for a review in +the pull request or a comment. +.IP \[bu] 2 +Add tests relevant to the fixed defect or new feature. +It\[aq]s best to do this before making any changes, make sure that the +tests fail, then make changes ensuring that it ultimately passes the +tests (i.e. +TDD). +xlnt uses cxxtest for testing. +Tests are contained in a tests directory inside each module (e.g. +source/workbook/tests/test\f[I]workbook.hpp) in the form of a header +file. Each test is a separate function with a name that starts like +"test\f[]". +See for information about CxxTest or +take a look at existing tests. +.SS Conduct +.PP +Just try to be nice\-\-we\[aq]re all volunteers here. +.SS Communication +.PP +Add a comment to an existing issue on GitHub, open a new issue for +defects or feature requests, or contact \@tfussell if you want. +.SH License +.SS xlnt (https://github.com/tfussell/xlnt) +.RS +.PP +MIT License (https://github.com/tfussell/xlnt/blob/master/LICENSE.md) +.RE +.IP +.nf +\f[C] +Copyright\ (c)\ 2014\-2017\ Thomas\ Fussell + +Permission\ is\ hereby\ granted,\ free\ of\ charge,\ to\ any\ person\ obtaining\ a +copy\ of\ this\ software\ and\ associated\ documentation\ files\ (the +"Software"),\ to\ deal\ in\ the\ Software\ without\ restriction,\ including +without\ limitation\ the\ rights\ to\ use,\ copy,\ modify,\ merge,\ publish, +distribute,\ sublicense,\ and/or\ sell\ copies\ of\ the\ Software,\ and\ to +permit\ persons\ to\ whom\ the\ Software\ is\ furnished\ to\ do\ so,\ subject\ to +the\ following\ conditions: + +The\ above\ copyright\ notice\ and\ this\ permission\ notice\ shall\ be\ included +in\ all\ copies\ or\ substantial\ portions\ of\ the\ Software. + +THE\ SOFTWARE\ IS\ PROVIDED\ "AS\ IS",\ WITHOUT\ WARRANTY\ OF\ ANY\ KIND,\ EXPRESS +OR\ IMPLIED,\ INCLUDING\ BUT\ NOT\ LIMITED\ TO\ THE\ WARRANTIES\ OF +MERCHANTABILITY,\ FITNESS\ FOR\ A\ PARTICULAR\ PURPOSE\ AND\ NONINFRINGEMENT. +IN\ NO\ EVENT\ SHALL\ THE\ AUTHORS\ OR\ COPYRIGHT\ HOLDERS\ BE\ LIABLE\ FOR\ ANY +CLAIM,\ DAMAGES\ OR\ OTHER\ LIABILITY,\ WHETHER\ IN\ AN\ ACTION\ OF\ CONTRACT, +TORT\ OR\ OTHERWISE,\ ARISING\ FROM,\ OUT\ OF\ OR\ IN\ CONNECTION\ WITH\ THE +SOFTWARE\ OR\ THE\ USE\ OR\ OTHER\ DEALINGS\ IN\ THE\ SOFTWARE. +\f[] +.fi +.SS POLE (http://www.dimin.net/software/pole/) +.RS +.PP +BSD 2\-Clause +License (https://bitbucket.org/dimin/pole/src/c15e513bdce4c3a52b3dbc925d4d2bb520dc71d8/pole/LICENSE) +.RE +.IP +.nf +\f[C] +POLE\ \-\ Portable\ C++\ library\ to\ access\ OLE\ Storage +Copyright\ (C)\ 2002\-2007\ Ariya\ Hidayat\ (ariya\@kde.org).\ All\ rights\ reserved. + +Redistribution\ and\ use\ in\ source\ and\ binary\ forms,\ with\ or\ without +modification,\ are\ permitted\ provided\ that\ the\ following\ conditions +are\ met: + +1.\ Redistributions\ of\ source\ code\ must\ retain\ the\ above\ copyright +\ \ \ notice,\ this\ list\ of\ conditions\ and\ the\ following\ disclaimer. +2.\ Redistributions\ in\ binary\ form\ must\ reproduce\ the\ above\ copyright +\ \ \ notice,\ this\ list\ of\ conditions\ and\ the\ following\ disclaimer\ in\ the +\ \ \ documentation\ and/or\ other\ materials\ provided\ with\ the\ distribution. + +THIS\ SOFTWARE\ IS\ PROVIDED\ BY\ THE\ AUTHOR\ "AS\ IS"\ AND\ ANY\ EXPRESS\ OR +IMPLIED\ WARRANTIES,\ INCLUDING,\ BUT\ NOT\ LIMITED\ TO,\ THE\ IMPLIED\ WARRANTIES +OF\ MERCHANTABILITY\ AND\ FITNESS\ FOR\ A\ PARTICULAR\ PURPOSE\ ARE\ DISCLAIMED. +IN\ NO\ EVENT\ SHALL\ THE\ AUTHOR\ BE\ LIABLE\ FOR\ ANY\ DIRECT,\ INDIRECT, +INCIDENTAL,\ SPECIAL,\ EXEMPLARY,\ OR\ CONSEQUENTIAL\ DAMAGES\ (INCLUDING,\ BUT +NOT\ LIMITED\ TO,\ PROCUREMENT\ OF\ SUBSTITUTE\ GOODS\ OR\ SERVICES;\ LOSS\ OF\ USE, +DATA,\ OR\ PROFITS;\ OR\ BUSINESS\ INTERRUPTION)\ HOWEVER\ CAUSED\ AND\ ON\ ANY +THEORY\ OF\ LIABILITY,\ WHETHER\ IN\ CONTRACT,\ STRICT\ LIABILITY,\ OR\ TORT +(INCLUDING\ NEGLIGENCE\ OR\ OTHERWISE)\ ARISING\ IN\ ANY\ WAY\ OUT\ OF\ THE\ USE\ OF +THIS\ SOFTWARE,\ EVEN\ IF\ ADVISED\ OF\ THE\ POSSIBILITY\ OF\ SUCH\ DAMAGE. +\f[] +.fi +.SS libstudxml (http://www.codesynthesis.com/projects/libstudxml/) +.RS +.PP +MIT License (http://www.codesynthesis.com/licenses/mit.txt) +.RE +.IP +.nf +\f[C] +Summary:\ Everything\ is\ licensed\ under\ the\ MIT\ License\ (text\ below). + +Code\ found\ in\ the\ xml/details/expat/\ directory\ is\ distributed\ under +the\ MIT\ License\ (see\ the\ xml/details/expat/LICENSE\ file\ for\ copyright +information). + +Code\ found\ in\ the\ xml/details/genx/\ directory\ is\ distributed\ under +the\ MIT\ License\ (see\ the\ xml/details/genx/LICENSE\ file\ for\ copyright +information). + +The\ rest\ is\ Copyright\ (c)\ 2013\-2014\ Code\ Synthesis\ Tools\ CC\ and\ is +distributed\ under\ the\ MIT\ License: + +Permission\ is\ hereby\ granted,\ free\ of\ charge,\ to\ any\ person\ obtaining +a\ copy\ of\ this\ software\ and\ associated\ documentation\ files\ (the +"Software"),\ to\ deal\ in\ the\ Software\ without\ restriction,\ including +without\ limitation\ the\ rights\ to\ use,\ copy,\ modify,\ merge,\ publish, +distribute,\ sublicense,\ and/or\ sell\ copies\ of\ the\ Software,\ and\ to +permit\ persons\ to\ whom\ the\ Software\ is\ furnished\ to\ do\ so,\ subject\ to +the\ following\ conditions: + +The\ above\ copyright\ notice\ and\ this\ permission\ notice\ shall\ be\ included +in\ all\ copies\ or\ substantial\ portions\ of\ the\ Software. + +THE\ SOFTWARE\ IS\ PROVIDED\ "AS\ IS",\ WITHOUT\ WARRANTY\ OF\ ANY\ KIND, +EXPRESS\ OR\ IMPLIED,\ INCLUDING\ BUT\ NOT\ LIMITED\ TO\ THE\ WARRANTIES\ OF +MERCHANTABILITY,\ FITNESS\ FOR\ A\ PARTICULAR\ PURPOSE\ AND\ NONINFRINGEMENT. +IN\ NO\ EVENT\ SHALL\ THE\ AUTHORS\ OR\ COPYRIGHT\ HOLDERS\ BE\ LIABLE\ FOR\ ANY +CLAIM,\ DAMAGES\ OR\ OTHER\ LIABILITY,\ WHETHER\ IN\ AN\ ACTION\ OF\ CONTRACT, +TORT\ OR\ OTHERWISE,\ ARISING\ FROM,\ OUT\ OF\ OR\ IN\ CONNECTION\ WITH\ THE +SOFTWARE\ OR\ THE\ USE\ OR\ OTHER\ DEALINGS\ IN\ THE\ SOFTWARE. +\f[] +.fi +.SS CxxTest (http://cxxtest.com/) +.RS +.PP +LGPL License (https://github.com/CxxTest/cxxtest/blob/master/COPYING) +.RE +.IP +.nf +\f[C] +\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ GNU\ LESSER\ GENERAL\ PUBLIC\ LICENSE +\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Version\ 3,\ 29\ June\ 2007 + +\ Copyright\ (C)\ 2007\ Free\ Software\ Foundation,\ Inc.\ +\ Everyone\ is\ permitted\ to\ copy\ and\ distribute\ verbatim\ copies +\ of\ this\ license\ document,\ but\ changing\ it\ is\ not\ allowed. + + +\ \ This\ version\ of\ the\ GNU\ Lesser\ General\ Public\ License\ incorporates +the\ terms\ and\ conditions\ of\ version\ 3\ of\ the\ GNU\ General\ Public +License,\ supplemented\ by\ the\ additional\ permissions\ listed\ below. + +\ \ 0.\ Additional\ Definitions. + +\ \ As\ used\ herein,\ "this\ License"\ refers\ to\ version\ 3\ of\ the\ GNU\ Lesser +General\ Public\ License,\ and\ the\ "GNU\ GPL"\ refers\ to\ version\ 3\ of\ the\ GNU +General\ Public\ License. + +\ \ "The\ Library"\ refers\ to\ a\ covered\ work\ governed\ by\ this\ License, +other\ than\ an\ Application\ or\ a\ Combined\ Work\ as\ defined\ below. + +\ \ An\ "Application"\ is\ any\ work\ that\ makes\ use\ of\ an\ interface\ provided +by\ the\ Library,\ but\ which\ is\ not\ otherwise\ based\ on\ the\ Library. +Defining\ a\ subclass\ of\ a\ class\ defined\ by\ the\ Library\ is\ deemed\ a\ mode +of\ using\ an\ interface\ provided\ by\ the\ Library. + +\ \ A\ "Combined\ Work"\ is\ a\ work\ produced\ by\ combining\ or\ linking\ an +Application\ with\ the\ Library.\ \ The\ particular\ version\ of\ the\ Library +with\ which\ the\ Combined\ Work\ was\ made\ is\ also\ called\ the\ "Linked +Version". + +\ \ The\ "Minimal\ Corresponding\ Source"\ for\ a\ Combined\ Work\ means\ the +Corresponding\ Source\ for\ the\ Combined\ Work,\ excluding\ any\ source\ code +for\ portions\ of\ the\ Combined\ Work\ that,\ considered\ in\ isolation,\ are +based\ on\ the\ Application,\ and\ not\ on\ the\ Linked\ Version. + +\ \ The\ "Corresponding\ Application\ Code"\ for\ a\ Combined\ Work\ means\ the +object\ code\ and/or\ source\ code\ for\ the\ Application,\ including\ any\ data +and\ utility\ programs\ needed\ for\ reproducing\ the\ Combined\ Work\ from\ the +Application,\ but\ excluding\ the\ System\ Libraries\ of\ the\ Combined\ Work. + +\ \ 1.\ Exception\ to\ Section\ 3\ of\ the\ GNU\ GPL. + +\ \ You\ may\ convey\ a\ covered\ work\ under\ sections\ 3\ and\ 4\ of\ this\ License +without\ being\ bound\ by\ section\ 3\ of\ the\ GNU\ GPL. + +\ \ 2.\ Conveying\ Modified\ Versions. + +\ \ If\ you\ modify\ a\ copy\ of\ the\ Library,\ and,\ in\ your\ modifications,\ a +facility\ refers\ to\ a\ function\ or\ data\ to\ be\ supplied\ by\ an\ Application +that\ uses\ the\ facility\ (other\ than\ as\ an\ argument\ passed\ when\ the +facility\ is\ invoked),\ then\ you\ may\ convey\ a\ copy\ of\ the\ modified +version: + +\ \ \ a)\ under\ this\ License,\ provided\ that\ you\ make\ a\ good\ faith\ effort\ to +\ \ \ ensure\ that,\ in\ the\ event\ an\ Application\ does\ not\ supply\ the +\ \ \ function\ or\ data,\ the\ facility\ still\ operates,\ and\ performs +\ \ \ whatever\ part\ of\ its\ purpose\ remains\ meaningful,\ or + +\ \ \ b)\ under\ the\ GNU\ GPL,\ with\ none\ of\ the\ additional\ permissions\ of +\ \ \ this\ License\ applicable\ to\ that\ copy. + +\ \ 3.\ Object\ Code\ Incorporating\ Material\ from\ Library\ Header\ Files. + +\ \ The\ object\ code\ form\ of\ an\ Application\ may\ incorporate\ material\ from +a\ header\ file\ that\ is\ part\ of\ the\ Library.\ \ You\ may\ convey\ such\ object +code\ under\ terms\ of\ your\ choice,\ provided\ that,\ if\ the\ incorporated +material\ is\ not\ limited\ to\ numerical\ parameters,\ data\ structure +layouts\ and\ accessors,\ or\ small\ macros,\ inline\ functions\ and\ templates +(ten\ or\ fewer\ lines\ in\ length),\ you\ do\ both\ of\ the\ following: + +\ \ \ a)\ Give\ prominent\ notice\ with\ each\ copy\ of\ the\ object\ code\ that\ the +\ \ \ Library\ is\ used\ in\ it\ and\ that\ the\ Library\ and\ its\ use\ are +\ \ \ covered\ by\ this\ License. + +\ \ \ b)\ Accompany\ the\ object\ code\ with\ a\ copy\ of\ the\ GNU\ GPL\ and\ this\ license +\ \ \ document. + +\ \ 4.\ Combined\ Works. + +\ \ You\ may\ convey\ a\ Combined\ Work\ under\ terms\ of\ your\ choice\ that, +taken\ together,\ effectively\ do\ not\ restrict\ modification\ of\ the +portions\ of\ the\ Library\ contained\ in\ the\ Combined\ Work\ and\ reverse +engineering\ for\ debugging\ such\ modifications,\ if\ you\ also\ do\ each\ of +the\ following: + +\ \ \ a)\ Give\ prominent\ notice\ with\ each\ copy\ of\ the\ Combined\ Work\ that +\ \ \ the\ Library\ is\ used\ in\ it\ and\ that\ the\ Library\ and\ its\ use\ are +\ \ \ covered\ by\ this\ License. + +\ \ \ b)\ Accompany\ the\ Combined\ Work\ with\ a\ copy\ of\ the\ GNU\ GPL\ and\ this\ license +\ \ \ document. + +\ \ \ c)\ For\ a\ Combined\ Work\ that\ displays\ copyright\ notices\ during +\ \ \ execution,\ include\ the\ copyright\ notice\ for\ the\ Library\ among +\ \ \ these\ notices,\ as\ well\ as\ a\ reference\ directing\ the\ user\ to\ the +\ \ \ copies\ of\ the\ GNU\ GPL\ and\ this\ license\ document. + +\ \ \ d)\ Do\ one\ of\ the\ following: + +\ \ \ \ \ \ \ 0)\ Convey\ the\ Minimal\ Corresponding\ Source\ under\ the\ terms\ of\ this +\ \ \ \ \ \ \ License,\ and\ the\ Corresponding\ Application\ Code\ in\ a\ form +\ \ \ \ \ \ \ suitable\ for,\ and\ under\ terms\ that\ permit,\ the\ user\ to +\ \ \ \ \ \ \ recombine\ or\ relink\ the\ Application\ with\ a\ modified\ version\ of +\ \ \ \ \ \ \ the\ Linked\ Version\ to\ produce\ a\ modified\ Combined\ Work,\ in\ the +\ \ \ \ \ \ \ manner\ specified\ by\ section\ 6\ of\ the\ GNU\ GPL\ for\ conveying +\ \ \ \ \ \ \ Corresponding\ Source. + +\ \ \ \ \ \ \ 1)\ Use\ a\ suitable\ shared\ library\ mechanism\ for\ linking\ with\ the +\ \ \ \ \ \ \ Library.\ \ A\ suitable\ mechanism\ is\ one\ that\ (a)\ uses\ at\ run\ time +\ \ \ \ \ \ \ a\ copy\ of\ the\ Library\ already\ present\ on\ the\ user\[aq]s\ computer +\ \ \ \ \ \ \ system,\ and\ (b)\ will\ operate\ properly\ with\ a\ modified\ version +\ \ \ \ \ \ \ of\ the\ Library\ that\ is\ interface\-compatible\ with\ the\ Linked +\ \ \ \ \ \ \ Version. + +\ \ \ e)\ Provide\ Installation\ Information,\ but\ only\ if\ you\ would\ otherwise +\ \ \ be\ required\ to\ provide\ such\ information\ under\ section\ 6\ of\ the +\ \ \ GNU\ GPL,\ and\ only\ to\ the\ extent\ that\ such\ information\ is +\ \ \ necessary\ to\ install\ and\ execute\ a\ modified\ version\ of\ the +\ \ \ Combined\ Work\ produced\ by\ recombining\ or\ relinking\ the +\ \ \ Application\ with\ a\ modified\ version\ of\ the\ Linked\ Version.\ (If +\ \ \ you\ use\ option\ 4d0,\ the\ Installation\ Information\ must\ accompany +\ \ \ the\ Minimal\ Corresponding\ Source\ and\ Corresponding\ Application +\ \ \ Code.\ If\ you\ use\ option\ 4d1,\ you\ must\ provide\ the\ Installation +\ \ \ Information\ in\ the\ manner\ specified\ by\ section\ 6\ of\ the\ GNU\ GPL +\ \ \ for\ conveying\ Corresponding\ Source.) + +\ \ 5.\ Combined\ Libraries. + +\ \ You\ may\ place\ library\ facilities\ that\ are\ a\ work\ based\ on\ the +Library\ side\ by\ side\ in\ a\ single\ library\ together\ with\ other\ library +facilities\ that\ are\ not\ Applications\ and\ are\ not\ covered\ by\ this +License,\ and\ convey\ such\ a\ combined\ library\ under\ terms\ of\ your +choice,\ if\ you\ do\ both\ of\ the\ following: + +\ \ \ a)\ Accompany\ the\ combined\ library\ with\ a\ copy\ of\ the\ same\ work\ based +\ \ \ on\ the\ Library,\ uncombined\ with\ any\ other\ library\ facilities, +\ \ \ conveyed\ under\ the\ terms\ of\ this\ License. + +\ \ \ b)\ Give\ prominent\ notice\ with\ the\ combined\ library\ that\ part\ of\ it +\ \ \ is\ a\ work\ based\ on\ the\ Library,\ and\ explaining\ where\ to\ find\ the +\ \ \ accompanying\ uncombined\ form\ of\ the\ same\ work. + +\ \ 6.\ Revised\ Versions\ of\ the\ GNU\ Lesser\ General\ Public\ License. + +\ \ The\ Free\ Software\ Foundation\ may\ publish\ revised\ and/or\ new\ versions +of\ the\ GNU\ Lesser\ General\ Public\ License\ from\ time\ to\ time.\ Such\ new +versions\ will\ be\ similar\ in\ spirit\ to\ the\ present\ version,\ but\ may +differ\ in\ detail\ to\ address\ new\ problems\ or\ concerns. + +\ \ Each\ version\ is\ given\ a\ distinguishing\ version\ number.\ If\ the +Library\ as\ you\ received\ it\ specifies\ that\ a\ certain\ numbered\ version +of\ the\ GNU\ Lesser\ General\ Public\ License\ "or\ any\ later\ version" +applies\ to\ it,\ you\ have\ the\ option\ of\ following\ the\ terms\ and +conditions\ either\ of\ that\ published\ version\ or\ of\ any\ later\ version +published\ by\ the\ Free\ Software\ Foundation.\ If\ the\ Library\ as\ you +received\ it\ does\ not\ specify\ a\ version\ number\ of\ the\ GNU\ Lesser +General\ Public\ License,\ you\ may\ choose\ any\ version\ of\ the\ GNU\ Lesser +General\ Public\ License\ ever\ published\ by\ the\ Free\ Software\ Foundation. + +\ \ If\ the\ Library\ as\ you\ received\ it\ specifies\ that\ a\ proxy\ can\ decide +whether\ future\ versions\ of\ the\ GNU\ Lesser\ General\ Public\ License\ shall +apply,\ that\ proxy\[aq]s\ public\ statement\ of\ acceptance\ of\ any\ version\ is +permanent\ authorization\ for\ you\ to\ choose\ that\ version\ for\ the +Library. +\f[] +.fi +.SS PartIO (https://www.disneyanimation.com/technology/partio.html) +.RS +.PP +BSD 3\-Clause License (with specific non\-attribution +clause) (https://github.com/wdas/partio/blob/master/src/lib/io/ZIP.h) +.RE +.IP +.nf +\f[C] +Copyright\ 2010\ Disney\ Enterprises,\ Inc.\ All\ rights\ reserved + +Redistribution\ and\ use\ in\ source\ and\ binary\ forms,\ with\ or\ without +modification,\ are\ permitted\ provided\ that\ the\ following\ conditions\ are +met: + +*\ Redistributions\ of\ source\ code\ must\ retain\ the\ above\ copyright +notice,\ this\ list\ of\ conditions\ and\ the\ following\ disclaimer. + +*\ Redistributions\ in\ binary\ form\ must\ reproduce\ the\ above\ copyright +notice,\ this\ list\ of\ conditions\ and\ the\ following\ disclaimer\ in +the\ documentation\ and/or\ other\ materials\ provided\ with\ the +distribution. + +*\ The\ names\ "Disney",\ "Walt\ Disney\ Pictures",\ "Walt\ Disney\ Animation +Studios"\ or\ the\ names\ of\ its\ contributors\ may\ NOT\ be\ used\ to +endorse\ or\ promote\ products\ derived\ from\ this\ software\ without +specific\ prior\ written\ permission\ from\ Walt\ Disney\ Pictures. + +Disclaimer:\ THIS\ SOFTWARE\ IS\ PROVIDED\ BY\ WALT\ DISNEY\ PICTURES\ AND +CONTRIBUTORS\ "AS\ IS"\ AND\ ANY\ EXPRESS\ OR\ IMPLIED\ WARRANTIES,\ INCLUDING, +BUT\ NOT\ LIMITED\ TO,\ THE\ IMPLIED\ WARRANTIES\ OF\ MERCHANTABILITY,\ FITNESS +FOR\ A\ PARTICULAR\ PURPOSE,\ NONINFRINGEMENT\ AND\ TITLE\ ARE\ DISCLAIMED. +IN\ NO\ EVENT\ SHALL\ WALT\ DISNEY\ PICTURES,\ THE\ COPYRIGHT\ HOLDER\ OR +CONTRIBUTORS\ BE\ LIABLE\ FOR\ ANY\ DIRECT,\ INDIRECT,\ INCIDENTAL,\ SPECIAL, +EXEMPLARY,\ OR\ CONSEQUENTIAL\ DAMAGES\ (INCLUDING,\ BUT\ NOT\ LIMITED\ TO, +PROCUREMENT\ OF\ SUBSTITUTE\ GOODS\ OR\ SERVICES;\ LOSS\ OF\ USE,\ DATA,\ OR +PROFITS;\ OR\ BUSINESS\ INTERRUPTION)\ HOWEVER\ CAUSED\ AND\ BASED\ ON\ ANY +THEORY\ OF\ LIABILITY,\ WHETHER\ IN\ CONTRACT,\ STRICT\ LIABILITY,\ OR\ TORT +(INCLUDING\ NEGLIGENCE\ OR\ OTHERWISE)\ ARISING\ IN\ ANY\ WAY\ OUT\ OF\ THE\ USE +OF\ THIS\ SOFTWARE,\ EVEN\ IF\ ADVISED\ OF\ THE\ POSSIBILITY\ OF\ SUCH\ DAMAGES. +\f[] +.fi +.SS miniz (https://github.com/richgel999/miniz) +.RS +.PP +Public Domain/MIT +License (https://github.com/richgel999/miniz/blob/master/LICENSE) +.RE +.IP +.nf +\f[C] +This\ is\ free\ and\ unencumbered\ software\ released\ into\ the\ public\ domain. + +Anyone\ is\ free\ to\ copy,\ modify,\ publish,\ use,\ compile,\ sell,\ or +distribute\ this\ software,\ either\ in\ source\ code\ form\ or\ as\ a\ compiled +binary,\ for\ any\ purpose,\ commercial\ or\ non\-commercial,\ and\ by\ any +means. + +In\ jurisdictions\ that\ recognize\ copyright\ laws,\ the\ author\ or\ authors +of\ this\ software\ dedicate\ any\ and\ all\ copyright\ interest\ in\ the +software\ to\ the\ public\ domain.\ We\ make\ this\ dedication\ for\ the\ benefit +of\ the\ public\ at\ large\ and\ to\ the\ detriment\ of\ our\ heirs\ and +successors.\ We\ intend\ this\ dedication\ to\ be\ an\ overt\ act\ of +relinquishment\ in\ perpetuity\ of\ all\ present\ and\ future\ rights\ to\ this +software\ under\ copyright\ law. + +THE\ SOFTWARE\ IS\ PROVIDED\ "AS\ IS",\ WITHOUT\ WARRANTY\ OF\ ANY\ KIND, +EXPRESS\ OR\ IMPLIED,\ INCLUDING\ BUT\ NOT\ LIMITED\ TO\ THE\ WARRANTIES\ OF +MERCHANTABILITY,\ FITNESS\ FOR\ A\ PARTICULAR\ PURPOSE\ AND\ NONINFRINGEMENT. +IN\ NO\ EVENT\ SHALL\ THE\ AUTHORS\ BE\ LIABLE\ FOR\ ANY\ CLAIM,\ DAMAGES\ OR +OTHER\ LIABILITY,\ WHETHER\ IN\ AN\ ACTION\ OF\ CONTRACT,\ TORT\ OR\ OTHERWISE, +ARISING\ FROM,\ OUT\ OF\ OR\ IN\ CONNECTION\ WITH\ THE\ SOFTWARE\ OR\ THE\ USE\ OR +OTHER\ DEALINGS\ IN\ THE\ SOFTWARE. + +For\ more\ information,\ please\ refer\ to\ + +Copyright\ 2013\-2014\ RAD\ Game\ Tools\ and\ Valve\ Software +Copyright\ 2010\-2014\ Rich\ Geldreich\ and\ Tenacious\ Software\ LLC +All\ Rights\ Reserved. + +Permission\ is\ hereby\ granted,\ free\ of\ charge,\ to\ any\ person\ obtaining\ a\ copy +of\ this\ software\ and\ associated\ documentation\ files\ (the\ "Software"),\ to\ deal +in\ the\ Software\ without\ restriction,\ including\ without\ limitation\ the\ rights +to\ use,\ copy,\ modify,\ merge,\ publish,\ distribute,\ sublicense,\ and/or\ sell +copies\ of\ the\ Software,\ and\ to\ permit\ persons\ to\ whom\ the\ Software\ is +furnished\ to\ do\ so,\ subject\ to\ the\ following\ conditions: + +The\ above\ copyright\ notice\ and\ this\ permission\ notice\ shall\ be\ included\ in +all\ copies\ or\ substantial\ portions\ of\ the\ Software. + +THE\ SOFTWARE\ IS\ PROVIDED\ "AS\ IS",\ WITHOUT\ WARRANTY\ OF\ ANY\ KIND,\ EXPRESS\ OR +IMPLIED,\ INCLUDING\ BUT\ NOT\ LIMITED\ TO\ THE\ WARRANTIES\ OF\ MERCHANTABILITY, +FITNESS\ FOR\ A\ PARTICULAR\ PURPOSE\ AND\ NONINFRINGEMENT.\ IN\ NO\ EVENT\ SHALL\ THE +AUTHORS\ OR\ COPYRIGHT\ HOLDERS\ BE\ LIABLE\ FOR\ ANY\ CLAIM,\ DAMAGES\ OR\ OTHER +LIABILITY,\ WHETHER\ IN\ AN\ ACTION\ OF\ CONTRACT,\ TORT\ OR\ OTHERWISE,\ ARISING\ FROM, +OUT\ OF\ OR\ IN\ CONNECTION\ WITH\ THE\ SOFTWARE\ OR\ THE\ USE\ OR\ OTHER\ DEALINGS\ IN +THE\ SOFTWARE. +\f[] +.fi diff --git a/include/xlnt/cell/cell.hpp b/include/xlnt/cell/cell.hpp index fa83508a..e65eab09 100644 --- a/include/xlnt/cell/cell.hpp +++ b/include/xlnt/cell/cell.hpp @@ -156,11 +156,6 @@ public: /// void value(double float_value); - /// - /// Sets the value of this cell to the given value. - /// - void value(long double float_value); - /// /// Sets the value of this cell to the given value. /// @@ -671,9 +666,6 @@ float cell::value() const; template<> double cell::value() const; -template<> -long double cell::value() const; - template<> date cell::value() const; diff --git a/include/xlnt/styles/number_format.hpp b/include/xlnt/styles/number_format.hpp index 46869540..8d0574a1 100644 --- a/include/xlnt/styles/number_format.hpp +++ b/include/xlnt/styles/number_format.hpp @@ -242,7 +242,7 @@ public: /// Returns number formatted according to this number format's format code /// with the given base date. /// - std::string format(long double number, calendar base_date) const; + std::string format(double number, calendar base_date) const; /// /// Returns true if this format code returns a number formatted as a date. diff --git a/include/xlnt/utils/datetime.hpp b/include/xlnt/utils/datetime.hpp index e8a42f9e..24ca7656 100644 --- a/include/xlnt/utils/datetime.hpp +++ b/include/xlnt/utils/datetime.hpp @@ -54,7 +54,7 @@ struct XLNT_API datetime /// a date and the fractional part into a time according to date::from_number /// and time::from_number. /// - static datetime from_number(long double number, calendar base_date); + static datetime from_number(double number, calendar base_date); /// /// Returns a datetime equivalent to the ISO-formatted string iso_string. @@ -84,7 +84,7 @@ struct XLNT_API datetime /// /// Returns this datetime as a number of seconds since 1900 or 1904 (depending on base_date provided). /// - long double to_number(calendar base_date) const; + double to_number(calendar base_date) const; /// /// Returns true if this datetime is equivalent to comparand. diff --git a/include/xlnt/utils/time.hpp b/include/xlnt/utils/time.hpp index c275f3fb..36d6f429 100644 --- a/include/xlnt/utils/time.hpp +++ b/include/xlnt/utils/time.hpp @@ -46,7 +46,7 @@ struct XLNT_API time /// The integer part of number will be ignored. /// 0.5 would return time(12, 0, 0, 0) or noon, halfway through the day. /// - static time from_number(long double number); + static time from_number(double number); /// /// Constructs a time object from an optional hour, minute, second, and microsecond. @@ -62,7 +62,7 @@ struct XLNT_API time /// Returns a numeric representation of the time in the range 0-1 where the value /// is equal to the fraction of the day elapsed. /// - long double to_number() const; + double to_number() const; /// /// Returns true if this time is equivalent to comparand. diff --git a/include/xlnt/utils/timedelta.hpp b/include/xlnt/utils/timedelta.hpp index 6ea773b1..797e6d95 100644 --- a/include/xlnt/utils/timedelta.hpp +++ b/include/xlnt/utils/timedelta.hpp @@ -38,7 +38,7 @@ struct XLNT_API timedelta /// /// Returns a timedelta from a number representing the factional number of days elapsed. /// - static timedelta from_number(long double number); + static timedelta from_number(double number); /// /// Constructs a timedelta equal to zero. @@ -53,7 +53,7 @@ struct XLNT_API timedelta /// /// Returns a numeric representation of this timedelta as a fractional number of days. /// - long double to_number() const; + double to_number() const; /// /// The days diff --git a/samples/CMakeLists.txt b/samples/CMakeLists.txt index d728283e..0b0d7e50 100644 --- a/samples/CMakeLists.txt +++ b/samples/CMakeLists.txt @@ -1,11 +1,19 @@ -cmake_minimum_required(VERSION 3.2) +cmake_minimum_required(VERSION 3.1) project(xlnt.samples) -set(CMAKE_CXX_STANDARD 14) +# Require C++11 compiler +set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD_REQUIRED ON) if(NOT COMBINED_PROJECT) - add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../source ${CMAKE_CURRENT_BINARY_DIR}/source) + # Include xlnt library + add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../source ${CMAKE_CURRENT_BINARY_DIR}/source) +endif() + +if(MSVC AND STATIC) + # Link with static C runtime + include(${CMAKE_CURRENT_SOURCE_DIR}/../cmake/ucm.cmake) + ucm_set_runtime(STATIC) endif() set(XLNT_SAMPLE_DATA_DIR ${CMAKE_CURRENT_SOURCE_DIR}/data) @@ -13,20 +21,24 @@ set(XLNT_SAMPLE_DATA_DIR ${CMAKE_CURRENT_SOURCE_DIR}/data) file(GLOB SAMPLE_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) foreach(SAMPLE_SOURCE IN ITEMS ${SAMPLE_SOURCES}) - get_filename_component(SAMPLE_NAME ${SAMPLE_SOURCE} NAME_WE) - set(SAMPLE_EXECUTABLE sample-${SAMPLE_NAME}) + # Convert .cpp to sample- + get_filename_component(SAMPLE_NAME ${SAMPLE_SOURCE} NAME_WE) + set(SAMPLE_EXECUTABLE sample-${SAMPLE_NAME}) - add_executable(${SAMPLE_EXECUTABLE} ${SAMPLE_SOURCE}) + add_executable(${SAMPLE_EXECUTABLE} ${SAMPLE_SOURCE}) - target_link_libraries(${SAMPLE_EXECUTABLE} PRIVATE xlnt) - target_include_directories(${SAMPLE_EXECUTABLE} - PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../tests) - target_compile_definitions(${SAMPLE_EXECUTABLE} PRIVATE XLNT_SAMPLE_DATA_DIR=${XLNT_SAMPLE_DATA_DIR}) + target_link_libraries(${SAMPLE_EXECUTABLE} PRIVATE xlnt) + # Need to use some test helpers + target_include_directories(${SAMPLE_EXECUTABLE} + PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../tests) + target_compile_definitions(${SAMPLE_EXECUTABLE} + PRIVATE XLNT_SAMPLE_DATA_DIR=${XLNT_SAMPLE_DATA_DIR}) - if(MSVC AND NOT STATIC) - add_custom_command(TARGET ${SAMPLE_EXECUTABLE} POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy_if_different - $ - $) - endif() + if(MSVC AND NOT STATIC) + # Copy xlnt DLL into samples directory + add_custom_command(TARGET ${SAMPLE_EXECUTABLE} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different + $ + $) + endif() endforeach() diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt index 0404533a..dd21e095 100644 --- a/source/CMakeLists.txt +++ b/source/CMakeLists.txt @@ -1,44 +1,61 @@ -cmake_minimum_required(VERSION 3.2) -project(xlnt VERSION 1.1) +cmake_minimum_required(VERSION 3.1) +project(xlnt VERSION 1.2) -set(CMAKE_CXX_STANDARD 14) +# Require C99 and C++11 compilers +set(CMAKE_C_STANDARD 99) +set(CMAKE_C_STANDARD_REQUIRED ON) +set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD_REQUIRED ON) +# Project metadata set(PROJECT_VENDOR "Thomas Fussell") set(PROJECT_CONTACT "thomas.fussell@gmail.com") set(PROJECT_URL "https://github.com/tfussell/xlnt") -set(PROJECT_DESCRIPTION "cross-platform user-friendly xlsx library for C++14") - -if(APPLE) - option(FRAMEWORK "Set to ON to package dylib and headers into a .framework, OSX only" OFF) -endif() +set(PROJECT_DESCRIPTION "cross-platform user-friendly xlsx library for C++11") +# Commonly used project directories set(XLNT_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/..) - set(XLNT_INCLUDE_DIR ${XLNT_ROOT_DIR}/include) set(XLNT_SOURCE_DIR ${XLNT_ROOT_DIR}/source) set(THIRD_PARTY_DIR ${XLNT_ROOT_DIR}/third-party) -add_subdirectory(${THIRD_PARTY_DIR}/libstudxml ${CMAKE_CURRENT_BINARY_DIR}/third-party/libstudxml) +# Include libstudxml library +add_subdirectory(${THIRD_PARTY_DIR}/libstudxml + ${CMAKE_CURRENT_BINARY_DIR}/third-party/libstudxml) if(COVERAGE) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage") endif() +# Non-target-specific compiler settings if(MSVC) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4 /MP") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4") # level 4 warnings + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP") # multi-processor compilation elseif(CMAKE_CXX_COMPILER_ID MATCHES "GNU") - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wno-unknown-pragmas") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall") # all warnings + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wextra") # extra warnings + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unknown-pragmas") # ignore MSVC and Clang pragmas elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Weverything -Werror -Wno-c++98-compat -Wno-c++98-compat-pedantic -Wno-padded -Wno-documentation-unknown-command -Wno-unknown-pragmas") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Weverything") # all warnings + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror") # warnings are errors + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-c++98-compat") # ignore warnings about C++98 compatibility + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-c++98-compat-pedantic") # ignore pedantic warnings about C++98 compatibility + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-padded") # ignore padding warnings + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-documentation-unknown-command") # ignore unknown commands in Javadoc-style comments + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unknown-pragmas") # ignore Windows and GCC pragmas +endif() + +if(MSVC AND STATIC) + # Link with static C runtime + include(${XLNT_ROOT_DIR}/cmake/ucm.cmake) + ucm_set_runtime(STATIC) endif() if(APPLE) - # Prevent a warning about deployment target not being set - execute_process(COMMAND "sw_vers -productVersion | awk -F'.' '{print $1\".\"$2}'" - OUTPUT_VARIABLE OSX_VERSION) - set(CMAKE_OSX_DEPLOYMENT_TARGET ${OSX_VERSION}) + # Prevent a warning about deployment target not being set by setting it to current OSX version + execute_process(COMMAND "sw_vers -productVersion | awk -F'.' '{print $1\".\"$2}'" + OUTPUT_VARIABLE OSX_VERSION) + set(CMAKE_OSX_DEPLOYMENT_TARGET ${OSX_VERSION}) endif() file(GLOB ROOT_HEADERS ${XLNT_INCLUDE_DIR}/xlnt/*.hpp) @@ -78,99 +95,105 @@ file(GLOB DETAIL_SERIALIZATION_HEADERS ${XLNT_SOURCE_DIR}/detail/serialization/* file(GLOB DETAIL_SERIALIZATION_SOURCES ${XLNT_SOURCE_DIR}/detail/serialization/*.cpp) set(DETAIL_HEADERS ${DETAIL_ROOT_HEADERS} ${DETAIL_CRYPTOGRAPHY_HEADERS} - ${DETAIL_EXTERNAL_HEADERS} ${DETAIL_HEADER_FOOTER_HEADERS} - ${DETAIL_IMPLEMENTATIONS_HEADERS} ${DETAIL_NUMBER_FORMAT_HEADERS} - ${DETAIL_SERIALIZATION_HEADERS}) + ${DETAIL_EXTERNAL_HEADERS} ${DETAIL_HEADER_FOOTER_HEADERS} + ${DETAIL_IMPLEMENTATIONS_HEADERS} ${DETAIL_NUMBER_FORMAT_HEADERS} + ${DETAIL_SERIALIZATION_HEADERS}) set(DETAIL_SOURCES ${DETAIL_ROOT_SOURCES} ${DETAIL_CRYPTOGRAPHY_SOURCES} - ${DETAIL_EXTERNAL_SOURCES} ${DETAIL_HEADER_FOOTER_SOURCES} - ${DETAIL_IMPLEMENTATIONS_SOURCES} ${DETAIL_NUMBER_FORMAT_SOURCES} - ${DETAIL_SERIALIZATION_SOURCES}) + ${DETAIL_EXTERNAL_SOURCES} ${DETAIL_HEADER_FOOTER_SOURCES} + ${DETAIL_IMPLEMENTATIONS_SOURCES} ${DETAIL_NUMBER_FORMAT_SOURCES} + ${DETAIL_SERIALIZATION_SOURCES}) set(XLNT_HEADERS ${ROOT_HEADERS} ${CELL_HEADERS} ${CHARTS_HEADERS} - ${CHARTSHEET_HEADERS} ${DRAWING_HEADERS} ${FORMULA_HEADERS} - ${PACKAGING_HEADERS} ${STYLES_HEADERS} ${UTILS_HEADERS} - ${WORKBOOK_HEADERS} ${WORKSHEET_HEADERS} ${DETAIL_HEADERS} ${DETAIL_CRYPTO_HEADERS}) + ${CHARTSHEET_HEADERS} ${DRAWING_HEADERS} ${FORMULA_HEADERS} + ${PACKAGING_HEADERS} ${STYLES_HEADERS} ${UTILS_HEADERS} + ${WORKBOOK_HEADERS} ${WORKSHEET_HEADERS} ${DETAIL_HEADERS} ${DETAIL_CRYPTO_HEADERS}) set(XLNT_SOURCES ${CELL_SOURCES} ${CHARTS_SOURCES} ${CHARTSHEET_SOURCES} - ${DRAWING_SOURCES} ${FORMULA_SOURCES} ${PACKAGING_SOURCES} - ${STYLES_SOURCES} ${UTILS_SOURCES} ${WORKBOOK_SOURCES} - ${WORKSHEET_SOURCES} ${DETAIL_SOURCES} ${DETAIL_CRYPTO_SOURCES}) + ${DRAWING_SOURCES} ${FORMULA_SOURCES} ${PACKAGING_SOURCES} + ${STYLES_SOURCES} ${UTILS_SOURCES} ${WORKBOOK_SOURCES} + ${WORKSHEET_SOURCES} ${DETAIL_SOURCES} ${DETAIL_CRYPTO_SOURCES}) if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) - if(MSVC) - set(DEFAULT_INSTALL_PREFIX "${CMAKE_BINARY_DIR}/installed") - else() - set(DEFAULT_INSTALL_PREFIX "/usr/local") - endif() + # Set a default CMAKE_INSTALL_PREFIX if one wasn't specified - set(CMAKE_INSTALL_PREFIX ${DEFAULT_INSTALL_PREFIX} - CACHE PATH "default install path" FORCE) + if(MSVC) + # No good place to install on Windows so just install to cmake build directory in /installed + set(DEFAULT_INSTALL_PREFIX "${CMAKE_BINARY_DIR}/installed") + else() + # Install to /usr/local on other platforms + set(DEFAULT_INSTALL_PREFIX "/usr/local") + endif() + + # Apply the variable and save to cache + set(CMAKE_INSTALL_PREFIX ${DEFAULT_INSTALL_PREFIX} + CACHE PATH "default install path" FORCE) endif() -if(NOT INC_DEST_DIR) - set(INC_DEST_DIR ${CMAKE_INSTALL_PREFIX}/include) -endif() - -if(NOT LIB_DEST_DIR) - set(LIB_DEST_DIR ${CMAKE_INSTALL_PREFIX}/lib) -endif() - -if(NOT BIN_DEST_DIR) - set(BIN_DEST_DIR ${CMAKE_INSTALL_PREFIX}/bin) -endif() +# Append "d" to the name of the compiled library +set(CMAKE_DEBUG_POSTFIX "d" CACHE STRING "Set debug library postfix") if(NOT STATIC) - add_library(xlnt SHARED ${XLNT_HEADERS} ${XLNT_SOURCES} $) - target_compile_definitions(xlnt PRIVATE XLNT_SHARED=1) + # Compile shared library + add_library(xlnt SHARED + ${XLNT_HEADERS} + ${XLNT_SOURCES} + $) - if(MSVC) - target_compile_definitions(xlnt PRIVATE XLNT_EXPORT=1 _CRT_SECURE_NO_WARNINGS=1) - endif() + target_compile_definitions(xlnt PRIVATE XLNT_SHARED=1) - set_target_properties(xlnt - PROPERTIES - VERSION ${PROJECT_VERSION} - SOVERSION ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR} - INSTALL_NAME_DIR "${LIB_DEST_DIR}") - - if(FRAMEWORK) - add_custom_command(TARGET xlnt - POST_BUILD - COMMAND mkdir -p "${CMAKE_CURRENT_BINARY_DIR}/xlnt.framework/Versions/${PROJECT_VERSION_FULL}/Headers" - COMMAND cp -R ${XLNT_INCLUDE_DIR}/xlnt/* "${CMAKE_CURRENT_BINARY_DIR}/xlnt.framework/Versions/${PROJECT_VERSION_FULL}/Headers" - COMMAND cp "lib/lib${PROJECT_NAME}.${PROJECT_VERSION_FULL}.dylib" "${CMAKE_CURRENT_BINARY_DIR}/xlnt.framework/Versions/${PROJECT_VERSION_FULL}/xlnt" - COMMAND cd "${CMAKE_CURRENT_BINARY_DIR}/xlnt.framework/Versions" && ln -s "${PROJECT_VERSION_FULL}" Current - COMMAND cd "${CMAKE_CURRENT_BINARY_DIR}/xlnt.framework" && ln -s Versions/Current/* ./ - ) - endif() + # Set SO version (for symbolic links like libxlnt.so.1.2 and libxlnt.so.1) + set_target_properties(xlnt + PROPERTIES + VERSION ${PROJECT_VERSION} + SOVERSION ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR} + INSTALL_NAME_DIR "${LIB_DEST_DIR}") else() - add_library(xlnt STATIC ${XLNT_HEADERS} ${XLNT_SOURCES} $) - target_compile_definitions(xlnt PUBLIC XLNT_STATIC=1) - - if(MSVC) - target_compile_definitions(xlnt PRIVATE _CRT_SECURE_NO_WARNINGS=1) - endif() + # Compile static library + add_library(xlnt STATIC ${XLNT_HEADERS} ${XLNT_SOURCES} $) + target_compile_definitions(xlnt PUBLIC XLNT_STATIC=1) endif() +# Includes target_include_directories(xlnt PUBLIC ${XLNT_INCLUDE_DIR}) target_include_directories(xlnt PRIVATE ${XLNT_SOURCE_DIR}) target_include_directories(xlnt PRIVATE ${XLNT_SOURCE_DIR}/../third-party/libstudxml) target_include_directories(xlnt PRIVATE ${XLNT_SOURCE_DIR}/../third-party/utfcpp) +# Platform- and file-specific settings, MSVC if(MSVC) - set_target_properties(xlnt PROPERTIES COMPILE_FLAGS "/wd\"4251\" /wd\"4275\" /wd\"4068\" /MP") - set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/detail/serialization/miniz.cpp PROPERTIES COMPILE_FLAGS "/wd\"4244\" /wd\"4334\" /wd\"4127\"") - set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/detail/cryptography/aes.cpp PROPERTIES COMPILE_FLAGS "/wd\"4996\"") + target_compile_definitions(xlnt PRIVATE _CRT_SECURE_NO_WARNINGS=1) + + if(NOT STATIC) + target_compile_definitions(xlnt PRIVATE XLNT_EXPORT=1) + endif() + + set_target_properties(xlnt PROPERTIES + COMPILE_FLAGS "/wd\"4251\" /wd\"4275\" /wd\"4068\"") + set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/detail/serialization/miniz.cpp + PROPERTIES + COMPILE_FLAGS "/wd\"4244\" /wd\"4334\" /wd\"4127\"") + set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/detail/cryptography/aes.cpp + PROPERTIES + COMPILE_FLAGS "/wd\"4996\"") endif() +# Platform- and file-specific settings, Clang if(CMAKE_CXX_COMPILER_ID MATCHES "Clang") - set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/detail/serialization/miniz.cpp PROPERTIES COMPILE_FLAGS "-Wno-undef") - set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/detail/serialization/zstream.cpp PROPERTIES COMPILE_FLAGS "-Wno-undef -Wno-shorten-64-to-32") + set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/detail/serialization/miniz.cpp + PROPERTIES + COMPILE_FLAGS "-Wno-undef") + set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/detail/serialization/zstream.cpp + PROPERTIES + COMPILE_FLAGS "-Wno-undef -Wno-shorten-64-to-32") endif() +# Platform- and file-specific settings, GCC if(CMAKE_CXX_COMPILER_ID MATCHES "GNU") - set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/detail/serialization/miniz.cpp PROPERTIES COMPILE_FLAGS "-Wno-strict-aliasing") + set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/detail/serialization/miniz.cpp + PROPERTIES + COMPILE_FLAGS "-Wno-strict-aliasing") endif() +# Group files into pseudo-folders in IDEs source_group(xlnt FILES ${ROOT_HEADERS}) source_group(cell FILES ${CELL_HEADERS} ${CELL_SOURCES}) source_group(detail FILES ${DETAIL_ROOT_HEADERS} ${DETAIL_ROOT_SOURCES}) @@ -186,31 +209,63 @@ source_group(utils FILES ${UTILS_HEADERS} ${UTILS_SOURCES}) source_group(workbook FILES ${WORKBOOK_HEADERS} ${WORKBOOK_SOURCES}) source_group(worksheet FILES ${WORKSHEET_HEADERS} ${WORKSHEET_SOURCES}) -set(PKG_CONFIG_LIBDIR ${LIB_DEST_DIR}) -set(PKG_CONFIG_INCLUDEDIR ${INC_DEST_DIR}) -set(PKG_CONFIG_LIBS "-L\${libdir} -lxlnt") -set(PKG_CONFIG_CFLAGS "-I\${includedir}") - -install(TARGETS xlnt - LIBRARY DESTINATION ${LIB_DEST_DIR} - ARCHIVE DESTINATION ${LIB_DEST_DIR} - RUNTIME DESTINATION ${BIN_DEST_DIR}) - -if(NOT MSVC) - configure_file("${XLNT_ROOT_DIR}/cmake/pkg-config.pc.cmake" - "${CMAKE_CURRENT_BINARY_DIR}/xlnt.pc") - install(FILES "${CMAKE_CURRENT_BINARY_DIR}/xlnt.pc" - DESTINATION ${LIB_DEST_DIR}/pkgconfig) +if(NOT INC_DEST_DIR) + # Default location to install include files + set(INC_DEST_DIR ${CMAKE_INSTALL_PREFIX}/include) endif() +if(NOT LIB_DEST_DIR) + # Default location to install library files + set(LIB_DEST_DIR ${CMAKE_INSTALL_PREFIX}/lib) +endif() + +if(NOT BIN_DEST_DIR) + # Default location to install runtime files + set(BIN_DEST_DIR ${CMAKE_INSTALL_PREFIX}/bin) +endif() + +if(NOT MAN_DEST_DIR) + # Default location to install runtime files + set(MAN_DEST_DIR ${CMAKE_INSTALL_PREFIX}/share/man) +endif() + +# Install library +install(TARGETS xlnt + LIBRARY DESTINATION ${LIB_DEST_DIR} + ARCHIVE DESTINATION ${LIB_DEST_DIR} + RUNTIME DESTINATION ${BIN_DEST_DIR}) + +# Install include directory install(DIRECTORY ${XLNT_INCLUDE_DIR}/xlnt - DESTINATION include - PATTERN ".DS_Store" EXCLUDE) + DESTINATION include + PATTERN ".DS_Store" EXCLUDE) +# Install LICENSE.md +install(FILES ${XLNT_ROOT_DIR}/docs/xlnt.3 +DESTINATION ${MAN_DEST_DIR}/man3) + +# Configure uninstall configure_file("${XLNT_ROOT_DIR}/cmake/cmake_uninstall.cmake.in" - "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" - IMMEDIATE @ONLY) + "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" + IMMEDIATE @ONLY) +# Add uninstall target add_custom_target(uninstall - COMMAND ${CMAKE_COMMAND} -P - ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake) + COMMAND ${CMAKE_COMMAND} -P + ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake) + +if(NOT MSVC) + # Set pkg-config variables + set(PKG_CONFIG_LIBDIR ${LIB_DEST_DIR}) + set(PKG_CONFIG_INCLUDEDIR ${INC_DEST_DIR}) + set(PKG_CONFIG_LIBS "-L\${libdir} -lxlnt") + set(PKG_CONFIG_CFLAGS "-I\${includedir}") + + # Replace variables in pkg-config template + configure_file("${XLNT_ROOT_DIR}/cmake/pkg-config.pc.cmake" + "${CMAKE_CURRENT_BINARY_DIR}/xlnt.pc") + + # pkg-config install + install(FILES "${CMAKE_CURRENT_BINARY_DIR}/xlnt.pc" + DESTINATION ${LIB_DEST_DIR}/pkgconfig) +endif() diff --git a/source/cell/cell.cpp b/source/cell/cell.cpp index 82743ae0..1e47202f 100644 --- a/source/cell/cell.cpp +++ b/source/cell/cell.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -55,17 +56,17 @@ namespace { -std::pair cast_numeric(const std::string &s) +std::pair cast_numeric(const std::string &s) { auto str_end = static_cast(nullptr); - auto result = std::strtold(s.c_str(), &str_end); + auto result = std::strtod(s.c_str(), &str_end); return (str_end != s.c_str() + s.size()) - ? std::make_pair(false, 0.0L) + ? std::make_pair(false, 0.0) : std::make_pair(true, result); } -std::pair cast_percentage(const std::string &s) +std::pair cast_percentage(const std::string &s) { if (s.back() == '%') { @@ -77,7 +78,7 @@ std::pair cast_percentage(const std::string &s) } } - return {false, 0}; + return {false, 0.0}; } std::pair cast_time(const std::string &s) @@ -205,48 +206,42 @@ void cell::value(std::nullptr_t) void cell::value(bool boolean_value) { d_->type_ = type::boolean; - d_->value_numeric_ = boolean_value ? 1.0L : 0.0L; + d_->value_numeric_ = boolean_value ? 1.0 : 0.0; } void cell::value(int int_value) { - d_->value_numeric_ = static_cast(int_value); + d_->value_numeric_ = static_cast(int_value); d_->type_ = type::number; } void cell::value(unsigned int int_value) { - d_->value_numeric_ = static_cast(int_value); + d_->value_numeric_ = static_cast(int_value); d_->type_ = type::number; } void cell::value(long long int int_value) { - d_->value_numeric_ = static_cast(int_value); + d_->value_numeric_ = static_cast(int_value); d_->type_ = type::number; } void cell::value(unsigned long long int int_value) { - d_->value_numeric_ = static_cast(int_value); + d_->value_numeric_ = static_cast(int_value); d_->type_ = type::number; } void cell::value(float float_value) { - d_->value_numeric_ = static_cast(float_value); + d_->value_numeric_ = static_cast(float_value); d_->type_ = type::number; } void cell::value(double float_value) { - d_->value_numeric_ = static_cast(float_value); - d_->type_ = type::number; -} - -void cell::value(long double d) -{ - d_->value_numeric_ = d; + d_->value_numeric_ = static_cast(float_value); d_->type_ = type::number; } @@ -260,7 +255,7 @@ void cell::value(const rich_text &text) check_string(text.plain_text()); d_->type_ = type::shared_string; - d_->value_numeric_ = static_cast(workbook().add_shared_string(text)); + d_->value_numeric_ = static_cast(workbook().add_shared_string(text)); } void cell::value(const char *c) @@ -534,7 +529,7 @@ void cell::clear_value() template <> XLNT_API bool cell::value() const { - return d_->value_numeric_ != 0.L; + return d_->value_numeric_ != 0.0; } template <> @@ -573,12 +568,6 @@ XLNT_API double cell::value() const return static_cast(d_->value_numeric_); } -template <> -XLNT_API long double cell::value() const -{ - return d_->value_numeric_; -} - template <> XLNT_API time cell::value() const { @@ -671,14 +660,14 @@ std::string cell::to_string() const return ""; case cell::type::date: case cell::type::number: - return nf.format(value(), base_date()); + return nf.format(value(), base_date()); case cell::type::inline_string: case cell::type::shared_string: case cell::type::formula_string: case cell::type::error: return nf.format(value()); case cell::type::boolean: - return value() == 0.L ? "FALSE" : "TRUE"; + return value() == 0.0 ? "FALSE" : "TRUE"; } return ""; @@ -878,7 +867,11 @@ bool cell::has_comment() void cell::clear_comment() { - d_->comment_.clear(); + if (has_comment()) + { + d_->parent_->comments_.erase(reference().to_string()); + d_->comment_.clear(); + } } class comment cell::comment() @@ -888,7 +881,7 @@ class comment cell::comment() throw xlnt::exception("cell has no comment"); } - return d_->comment_.get(); + return *d_->comment_.get(); } void cell::comment(const std::string &text, const std::string &author) @@ -904,15 +897,23 @@ void cell::comment(const std::string &text, const class font &comment_font, cons void cell::comment(const class comment &new_comment) { - d_->comment_.set(new_comment); + if (has_comment()) + { + *d_->comment_.get() = new_comment; + } + else + { + d_->parent_->comments_[reference().to_string()] = new_comment; + d_->comment_.set(&d_->parent_->comments_[reference().to_string()]); + } // offset comment 5 pixels down and 5 pixels right of the top right corner of the cell auto cell_position = anchor(); cell_position.first += static_cast(width()) + 5; cell_position.second += 5; - d_->comment_.get().position(cell_position.first, cell_position.second); - d_->comment_.get().size(200, 100); + d_->comment_.get()->position(cell_position.first, cell_position.second); + d_->comment_.get()->size(200, 100); worksheet().register_comments_in_manifest(); } diff --git a/source/cell/cell_reference.cpp b/source/cell/cell_reference.cpp index 15736fdd..159af274 100644 --- a/source/cell/cell_reference.cpp +++ b/source/cell/cell_reference.cpp @@ -122,7 +122,7 @@ std::pair cell_reference::split_reference( for (auto character : reference_string) { - char upper = std::toupper(character); + auto upper = static_cast(std::toupper(static_cast(character))); if (std::isalpha(character)) { diff --git a/source/detail/cryptography/aes.cpp b/source/detail/cryptography/aes.cpp index d37461ae..7569c82f 100644 --- a/source/detail/cryptography/aes.cpp +++ b/source/detail/cryptography/aes.cpp @@ -21,6 +21,10 @@ // @license: http://www.opensource.org/licenses/mit-license.php // @author: see AUTHORS file +// Adapted from LibTomCrypt AES implementation +// https://github.com/libtom/libtomcrypt/blob/develop/src/ciphers/aes/aes_tab.c +// https://github.com/libtom/libtomcrypt/blob/develop/src/ciphers/aes/aes.c + #include #include #include diff --git a/source/detail/cryptography/compound_document.cpp b/source/detail/cryptography/compound_document.cpp index 768fe470..9a48cd27 100644 --- a/source/detail/cryptography/compound_document.cpp +++ b/source/detail/cryptography/compound_document.cpp @@ -113,7 +113,7 @@ public: compound_document_istreambuf(const compound_document_istreambuf &) = delete; compound_document_istreambuf &operator=(const compound_document_istreambuf &) = delete; - virtual ~compound_document_istreambuf(); + ~compound_document_istreambuf() override; private: std::streamsize xsgetn(char *c, std::streamsize count) override @@ -326,7 +326,7 @@ public: compound_document_ostreambuf(const compound_document_ostreambuf &) = delete; compound_document_ostreambuf &operator=(const compound_document_ostreambuf &) = delete; - virtual ~compound_document_ostreambuf(); + ~compound_document_ostreambuf() override; private: int sync() override diff --git a/source/detail/cryptography/xlsx_crypto_consumer.cpp b/source/detail/cryptography/xlsx_crypto_consumer.cpp index be96920b..a614523a 100644 --- a/source/detail/cryptography/xlsx_crypto_consumer.cpp +++ b/source/detail/cryptography/xlsx_crypto_consumer.cpp @@ -283,18 +283,18 @@ encryption_info read_encryption_info(std::istream &info_stream, const std::u16st throw xlnt::exception("unsupported encryption version"); } - if ((encryption_flags & 0b00000011) != 0) // Reserved1 and Reserved2, MUST be 0 + if ((encryption_flags & 0x03) != 0) // Reserved1 and Reserved2, MUST be 0 { throw xlnt::exception("bad header"); } - if ((encryption_flags & 0b00000100) == 0 // fCryptoAPI - || (encryption_flags & 0b00010000) != 0) // fExternal + if ((encryption_flags & 0x04) == 0 // fCryptoAPI + || (encryption_flags & 0x10) != 0) // fExternal { throw xlnt::exception("extensible encryption is not supported"); } - if ((encryption_flags & 0b00100000) == 0) // fAES + if ((encryption_flags & 0x20) == 0) // fAES { throw xlnt::exception("not an OOXML document"); } diff --git a/source/detail/cryptography/xlsx_crypto_producer.cpp b/source/detail/cryptography/xlsx_crypto_producer.cpp index 07448d8b..2916b155 100644 --- a/source/detail/cryptography/xlsx_crypto_producer.cpp +++ b/source/detail/cryptography/xlsx_crypto_producer.cpp @@ -181,7 +181,7 @@ void write_standard_encryption_info(const encryption_info &info, std::ostream &i const auto version_major = std::uint16_t(4); const auto version_minor = std::uint16_t(2); - const auto encryption_flags = std::uint32_t(0b00010000 & 0b00100000); + const auto encryption_flags = std::uint32_t(0x10 & 0x20); writer.write(version_major); writer.write(version_minor); diff --git a/source/detail/implementations/cell_impl.hpp b/source/detail/implementations/cell_impl.hpp index 8bc780dd..fcf4a33c 100644 --- a/source/detail/implementations/cell_impl.hpp +++ b/source/detail/implementations/cell_impl.hpp @@ -51,12 +51,12 @@ struct cell_impl bool is_merged_; rich_text value_text_; - long double value_numeric_; + double value_numeric_; optional formula_; optional hyperlink_; optional format_; - optional comment_; + optional comment_; }; } // namespace detail diff --git a/source/detail/implementations/worksheet_impl.hpp b/source/detail/implementations/worksheet_impl.hpp index e21908a0..9c6ec27b 100644 --- a/source/detail/implementations/worksheet_impl.hpp +++ b/source/detail/implementations/worksheet_impl.hpp @@ -115,6 +115,8 @@ struct worksheet_impl std::vector column_breaks_; std::vector row_breaks_; + + std::unordered_map comments_; }; } // namespace detail diff --git a/source/detail/number_format/number_formatter.cpp b/source/detail/number_format/number_formatter.cpp index 0b799787..eb9f1dc7 100644 --- a/source/detail/number_format/number_formatter.cpp +++ b/source/detail/number_format/number_formatter.cpp @@ -83,7 +83,7 @@ void unhandled_case(bool error) namespace xlnt { namespace detail { -bool format_condition::satisfied_by(long double number) const +bool format_condition::satisfied_by(double number) const { switch (type) { @@ -96,9 +96,9 @@ bool format_condition::satisfied_by(long double number) const case condition_type::less_than: return number < value; case condition_type::not_equal: - return std::fabs(number - value) != 0.0L; + return std::fabs(number - value) != 0.0; case condition_type::equal: - return std::fabs(number - value) == 0.0L; + return std::fabs(number - value) == 0.0; } default_case(false); @@ -221,7 +221,7 @@ void number_format_parser::parse() value = token.string.substr(1); } - section.condition.value = std::stold(value); + section.condition.value = std::stod(value); break; } @@ -1075,7 +1075,7 @@ number_formatter::number_formatter(const std::string &format_string, xlnt::calen format_ = parser_.result(); } -std::string number_formatter::format_number(long double number) +std::string number_formatter::format_number(double number) { if (format_[0].has_condition) { @@ -1154,7 +1154,7 @@ std::string number_formatter::format_text(const std::string &text) return format_text(format_[3], text); } -std::string number_formatter::fill_placeholders(const format_placeholders &p, long double number) +std::string number_formatter::fill_placeholders(const format_placeholders &p, double number) { std::string result; @@ -1230,7 +1230,7 @@ std::string number_formatter::fill_placeholders(const format_placeholders &p, lo else if (p.type == format_placeholders::placeholders_type::fractional_part) { auto fractional_part = number - integer_part; - result = std::fabs(fractional_part) < std::numeric_limits::min() + result = std::fabs(fractional_part) < std::numeric_limits::min() ? std::string(".") : std::to_string(fractional_part).substr(1); @@ -1259,11 +1259,11 @@ std::string number_formatter::fill_placeholders(const format_placeholders &p, lo } std::string number_formatter::fill_scientific_placeholders(const format_placeholders &integer_part, - const format_placeholders &fractional_part, const format_placeholders &exponent_part, long double number) + const format_placeholders &fractional_part, const format_placeholders &exponent_part, double number) { std::size_t logarithm = 0; - if (number != 0.L) + if (number != 0.0) { logarithm = static_cast(std::log10(number)); @@ -1280,7 +1280,7 @@ std::string number_formatter::fill_scientific_placeholders(const format_placehol std::string integer_string = std::to_string(integer); - if (number == 0.L) + if (number == 0.0) { integer_string = std::string(integer_part.num_zeros + integer_part.num_optionals, '0'); } @@ -1312,14 +1312,14 @@ std::string number_formatter::fill_scientific_placeholders(const format_placehol } std::string number_formatter::fill_fraction_placeholders(const format_placeholders & /*numerator*/, - const format_placeholders &denominator, long double number, bool /*improper*/) + const format_placeholders &denominator, double number, bool /*improper*/) { auto fractional_part = number - static_cast(number); auto original_fractional_part = fractional_part; fractional_part *= 10; - while (std::abs(fractional_part - static_cast(fractional_part)) > 0.000001L - && std::abs(fractional_part - static_cast(fractional_part)) < 0.999999L) + while (std::abs(fractional_part - static_cast(fractional_part)) > 0.000001 + && std::abs(fractional_part - static_cast(fractional_part)) < 0.999999) { fractional_part *= 10; } @@ -1331,13 +1331,13 @@ std::string number_formatter::fill_fraction_placeholders(const format_placeholde auto lower = static_cast(std::pow(10, denominator_digits - 1)); auto upper = static_cast(std::pow(10, denominator_digits)); auto best_denominator = lower; - auto best_difference = 1000.0L; + auto best_difference = 1000.0; for (int i = lower; i < upper; ++i) { auto numerator_full = original_fractional_part * i; auto numerator_rounded = static_cast(std::round(numerator_full)); - auto difference = std::fabs(original_fractional_part - (numerator_rounded / static_cast(i))); + auto difference = std::fabs(original_fractional_part - (numerator_rounded / static_cast(i))); if (difference < best_difference) { @@ -1350,7 +1350,7 @@ std::string number_formatter::fill_fraction_placeholders(const format_placeholde return std::to_string(numerator_rounded) + "/" + std::to_string(best_denominator); } -std::string number_formatter::format_number(const format_code &format, long double number) +std::string number_formatter::format_number(const format_code &format, double number) { static const std::vector *month_names = new std::vector{"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"}; @@ -1377,7 +1377,7 @@ std::string number_formatter::format_number(const format_code &format, long doub if (format.is_datetime) { - if (number != 0.L) + if (number != 0.0) { dt = xlnt::datetime::from_number(number, calendar_); } @@ -1434,7 +1434,7 @@ std::string number_formatter::format_number(const format_code &format, long doub auto digits = std::min( static_cast(6), part.placeholders.num_zeros + part.placeholders.num_optionals); auto denominator = static_cast(std::pow(10.0, digits)); - auto fractional_seconds = dt.microsecond / 1.0E6L * denominator; + auto fractional_seconds = dt.microsecond / 1.0E6 * denominator; fractional_seconds = std::round(fractional_seconds) / denominator; result.append(fill_placeholders(part.placeholders, fractional_seconds)); break; @@ -1449,7 +1449,7 @@ std::string number_formatter::format_number(const format_code &format, long doub { i += 2; - if (number == 0.L) + if (number == 0.0) { result.pop_back(); break; diff --git a/source/detail/number_format/number_formatter.hpp b/source/detail/number_format/number_formatter.hpp index de86d405..02ede6b5 100644 --- a/source/detail/number_format/number_formatter.hpp +++ b/source/detail/number_format/number_formatter.hpp @@ -222,9 +222,9 @@ struct XLNT_API format_condition greater_or_equal } type = condition_type::not_equal; - long double value = 0; + double value = 0.0; - bool satisfied_by(long double number) const; + bool satisfied_by(double number) const; }; struct format_placeholders @@ -352,17 +352,17 @@ class XLNT_API number_formatter { public: number_formatter(const std::string &format_string, xlnt::calendar calendar); - std::string format_number(long double number); + std::string format_number(double number); std::string format_text(const std::string &text); private: - std::string fill_placeholders(const format_placeholders &p, long double number); + std::string fill_placeholders(const format_placeholders &p, double number); std::string fill_fraction_placeholders(const format_placeholders &numerator, - const format_placeholders &denominator, long double number, bool improper); + const format_placeholders &denominator, double number, bool improper); std::string fill_scientific_placeholders(const format_placeholders &integer_part, const format_placeholders &fractional_part, const format_placeholders &exponent_part, - long double number); - std::string format_number(const format_code &format, long double number); + double number); + std::string format_number(const format_code &format, double number); std::string format_text(const format_code &format, const std::string &text); number_format_parser parser_; diff --git a/source/detail/serialization/miniz.cpp b/source/detail/serialization/miniz.cpp index fdab680c..290ff88e 100644 --- a/source/detail/serialization/miniz.cpp +++ b/source/detail/serialization/miniz.cpp @@ -57,18 +57,29 @@ mz_ulong mz_adler32(mz_ulong adler, const unsigned char *ptr, size_t buf_len) { for (i = 0; i + 7 < block_len; i += 8, ptr += 8) { - s1 += ptr[0], s2 += s1; - s1 += ptr[1], s2 += s1; - s1 += ptr[2], s2 += s1; - s1 += ptr[3], s2 += s1; - s1 += ptr[4], s2 += s1; - s1 += ptr[5], s2 += s1; - s1 += ptr[6], s2 += s1; - s1 += ptr[7], s2 += s1; + s1 += ptr[0]; + s2 += s1; + s1 += ptr[1]; + s2 += s1; + s1 += ptr[2]; + s2 += s1; + s1 += ptr[3]; + s2 += s1; + s1 += ptr[4]; + s2 += s1; + s1 += ptr[5]; + s2 += s1; + s1 += ptr[6]; + s2 += s1; + s1 += ptr[7]; + s2 += s1; } - for (; i < block_len; ++i) - s1 += *ptr++, s2 += s1; - s1 %= 65521U, s2 %= 65521U; + for (; i < block_len; ++i) { + s1 += *ptr++; + s2 += s1; + } + s1 %= 65521U; + s2 %= 65521U; buf_len -= block_len; block_len = 5552; } @@ -208,7 +219,7 @@ int mz_deflateInit2(mz_streamp pStream, int level, int method, int window_bits, pStream->data_type = 0; pStream->adler = MZ_ADLER32_INIT; - pStream->msg = NULL; + pStream->msg = nullptr; pStream->reserved = 0; pStream->total_in = 0; pStream->total_out = 0; @@ -223,7 +234,7 @@ int mz_deflateInit2(mz_streamp pStream, int level, int method, int window_bits, pStream->state = (struct mz_internal_state *)pComp; - if (tdefl_init(pComp, NULL, NULL, comp_flags) != TDEFL_STATUS_OKAY) + if (tdefl_init(pComp, nullptr, nullptr, comp_flags) != TDEFL_STATUS_OKAY) { mz_deflateEnd(pStream); return MZ_PARAM_ERROR; @@ -237,7 +248,7 @@ int mz_deflateReset(mz_streamp pStream) if ((!pStream) || (!pStream->state) || (!pStream->zalloc) || (!pStream->zfree)) return MZ_STREAM_ERROR; pStream->total_in = pStream->total_out = 0; - tdefl_init((tdefl_compressor *)pStream->state, NULL, NULL, ((tdefl_compressor *)pStream->state)->m_flags); + tdefl_init((tdefl_compressor *)pStream->state, nullptr, nullptr, ((tdefl_compressor *)pStream->state)->m_flags); return MZ_OK; } @@ -306,7 +317,7 @@ int mz_deflateEnd(mz_streamp pStream) if (pStream->state) { pStream->zfree(pStream->opaque, pStream->state); - pStream->state = NULL; + pStream->state = nullptr; } return MZ_OK; } @@ -355,7 +366,7 @@ int mz_compress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char * mz_ulong mz_compressBound(mz_ulong source_len) { - return mz_deflateBound(NULL, source_len); + return mz_deflateBound(nullptr, source_len); } typedef struct @@ -377,7 +388,7 @@ int mz_inflateInit2(mz_streamp pStream, int window_bits) pStream->data_type = 0; pStream->adler = 0; - pStream->msg = NULL; + pStream->msg = nullptr; pStream->total_in = 0; pStream->total_out = 0; pStream->reserved = 0; @@ -527,7 +538,7 @@ int mz_inflateEnd(mz_streamp pStream) if (pStream->state) { pStream->zfree(pStream->opaque, pStream->state); - pStream->state = NULL; + pStream->state = nullptr; } return MZ_OK; } @@ -577,7 +588,7 @@ const char *mz_error(int err) for (i = 0; i < sizeof(s_error_descs) / sizeof(s_error_descs[0]); ++i) if (s_error_descs[i].m_err == err) return s_error_descs[i].m_pDesc; - return NULL; + return nullptr; } #endif /*MINIZ_NO_ZLIB_APIS */ @@ -1221,7 +1232,7 @@ static int tdefl_flush_block(tdefl_compressor *d, int flush) mz_uint8 *pSaved_output_buf; mz_bool comp_block_succeeded = MZ_FALSE; int n, use_raw_block = ((d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS) != 0) && (d->m_lookahead_pos - d->m_lz_code_buf_dict_pos) <= d->m_dict_size; - mz_uint8 *pOutput_buf_start = ((d->m_pPut_buf_func == NULL) && ((*d->m_pOut_buf_size - d->m_out_buf_ofs) >= TDEFL_OUT_BUF_SIZE)) ? ((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs) : d->m_output_buf; + mz_uint8 *pOutput_buf_start = ((d->m_pPut_buf_func == nullptr) && ((*d->m_pOut_buf_size - d->m_out_buf_ofs) >= TDEFL_OUT_BUF_SIZE)) ? ((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs) : d->m_output_buf; d->m_pOutput_buf = pOutput_buf_start; d->m_pOutput_buf_end = d->m_pOutput_buf + TDEFL_OUT_BUF_SIZE - 16; @@ -1254,7 +1265,8 @@ static int tdefl_flush_block(tdefl_compressor *d, int flush) { mz_uint i; d->m_pOutput_buf = pSaved_output_buf; - d->m_bit_buffer = saved_bit_buf, d->m_bits_in = saved_bits_in; + d->m_bit_buffer = saved_bit_buf; + d->m_bits_in = saved_bits_in; TDEFL_PUT_BITS(0, 2); if (d->m_bits_in) { @@ -1273,7 +1285,8 @@ static int tdefl_flush_block(tdefl_compressor *d, int flush) else if (!comp_block_succeeded) { d->m_pOutput_buf = pSaved_output_buf; - d->m_bit_buffer = saved_bit_buf, d->m_bits_in = saved_bits_in; + d->m_bit_buffer = saved_bit_buf; + d->m_bits_in = saved_bits_in; tdefl_compress_block(d, MZ_TRUE); } @@ -1287,7 +1300,8 @@ static int tdefl_flush_block(tdefl_compressor *d, int flush) } if (d->m_flags & TDEFL_WRITE_ZLIB_HEADER) { - mz_uint i, a = d->m_adler32; + mz_uint i; + mz_uint a = d->m_adler32; for (i = 0; i < 4; i++) { TDEFL_PUT_BITS((a >> 24) & 0xFF, 8); @@ -1297,7 +1311,8 @@ static int tdefl_flush_block(tdefl_compressor *d, int flush) } else { - mz_uint i, z = 0; + mz_uint i; + mz_uint z = 0; TDEFL_PUT_BITS(0, 3); if (d->m_bits_in) { @@ -1850,7 +1865,7 @@ tdefl_status tdefl_compress(tdefl_compressor *d, const void *pIn_buf, size_t *pI d->m_out_buf_ofs = 0; d->m_flush = flush; - if (((d->m_pPut_buf_func != NULL) == ((pOut_buf != NULL) || (pOut_buf_size != NULL))) || (d->m_prev_return_status != TDEFL_STATUS_OKAY) || + if (((d->m_pPut_buf_func != nullptr) == ((pOut_buf != nullptr) || (pOut_buf_size != nullptr))) || (d->m_prev_return_status != TDEFL_STATUS_OKAY) || (d->m_wants_to_finish && (flush != TDEFL_FINISH)) || (pIn_buf_size && *pIn_buf_size && !pIn_buf) || (pOut_buf_size && *pOut_buf_size && !pOut_buf)) { if (pIn_buf_size) @@ -1901,7 +1916,7 @@ tdefl_status tdefl_compress(tdefl_compressor *d, const void *pIn_buf, size_t *pI tdefl_status tdefl_compress_buffer(tdefl_compressor *d, const void *pIn_buf, size_t in_buf_size, tdefl_flush flush) { MZ_ASSERT(d->m_pPut_buf_func); - return tdefl_compress(d, pIn_buf, &in_buf_size, NULL, NULL, flush); + return tdefl_compress(d, pIn_buf, &in_buf_size, nullptr, nullptr, flush); } tdefl_status tdefl_init(tdefl_compressor *d, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags) @@ -1924,12 +1939,12 @@ tdefl_status tdefl_init(tdefl_compressor *d, tdefl_put_buf_func_ptr pPut_buf_fun d->m_prev_return_status = TDEFL_STATUS_OKAY; d->m_saved_match_dist = d->m_saved_match_len = d->m_saved_lit = 0; d->m_adler32 = 1; - d->m_pIn_buf = NULL; - d->m_pOut_buf = NULL; - d->m_pIn_buf_size = NULL; - d->m_pOut_buf_size = NULL; + d->m_pIn_buf = nullptr; + d->m_pOut_buf = nullptr; + d->m_pIn_buf_size = nullptr; + d->m_pOut_buf_size = nullptr; d->m_flush = TDEFL_NO_FLUSH; - d->m_pSrc = NULL; + d->m_pSrc = nullptr; d->m_src_buf_left = 0; d->m_out_buf_ofs = 0; memset(&d->m_huff_count[0][0], 0, sizeof(d->m_huff_count[0][0]) * TDEFL_MAX_HUFF_SYMBOLS_0); @@ -1999,12 +2014,12 @@ void *tdefl_compress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_ tdefl_output_buffer out_buf; MZ_CLEAR_OBJ(out_buf); if (!pOut_len) - return MZ_FALSE; + return nullptr; //MZ_FALSE; else *pOut_len = 0; out_buf.m_expandable = MZ_TRUE; if (!tdefl_compress_mem_to_output(pSrc_buf, src_buf_len, tdefl_output_buffer_putter, &out_buf, flags)) - return NULL; + return nullptr; *pOut_len = out_buf.m_size; return out_buf.m_pBuf; } @@ -2063,14 +2078,14 @@ void *tdefl_write_image_to_png_file_in_memory_ex(const void *pImage, int w, int mz_uint32 c; *pLen_out = 0; if (!pComp) - return NULL; + return nullptr; MZ_CLEAR_OBJ(out_buf); out_buf.m_expandable = MZ_TRUE; out_buf.m_capacity = 57 + MZ_MAX(64, (1 + bpl) * h); - if (NULL == (out_buf.m_pBuf = (mz_uint8 *)MZ_MALLOC(out_buf.m_capacity))) + if (nullptr == (out_buf.m_pBuf = (mz_uint8 *)MZ_MALLOC(out_buf.m_capacity))) { MZ_FREE(pComp); - return NULL; + return nullptr; } /* write dummy header */ for (z = 41; z; --z) @@ -2082,11 +2097,11 @@ void *tdefl_write_image_to_png_file_in_memory_ex(const void *pImage, int w, int tdefl_compress_buffer(pComp, &z, 1, TDEFL_NO_FLUSH); tdefl_compress_buffer(pComp, (mz_uint8 *)pImage + (flip ? (h - 1 - y) : y) * bpl, bpl, TDEFL_NO_FLUSH); } - if (tdefl_compress_buffer(pComp, NULL, 0, TDEFL_FINISH) != TDEFL_STATUS_DONE) + if (tdefl_compress_buffer(pComp, nullptr, 0, TDEFL_FINISH) != TDEFL_STATUS_DONE) { MZ_FREE(pComp); MZ_FREE(out_buf.m_pBuf); - return NULL; + return nullptr; } /* write real header */ *pLen_out = out_buf.m_size - 41; @@ -2121,7 +2136,7 @@ void *tdefl_write_image_to_png_file_in_memory_ex(const void *pImage, int w, int *pLen_out = 0; MZ_FREE(pComp); MZ_FREE(out_buf.m_pBuf); - return NULL; + return nullptr; } c = (mz_uint32)mz_crc32(MZ_CRC32_INIT, out_buf.m_pBuf + 41 - 4, *pLen_out + 4); for (i = 0; i < 4; ++i, c <<= 8) @@ -2472,7 +2487,8 @@ tinfl_status tinfl_decompress(tinfl_decompressor *r, const mz_uint8 *pIn_buf_nex MZ_CLEAR_OBJ(pTable->m_tree); for (i = 0; i < r->m_table_sizes[r->m_type]; ++i) total_syms[pTable->m_code_size[i]]++; - used_syms = 0, total = 0; + used_syms = 0; + total = 0; next_code[0] = next_code[1] = 0; for (i = 1; i <= 15; ++i) { @@ -2776,18 +2792,29 @@ common_exit: { for (i = 0; i + 7 < block_len; i += 8, ptr += 8) { - s1 += ptr[0], s2 += s1; - s1 += ptr[1], s2 += s1; - s1 += ptr[2], s2 += s1; - s1 += ptr[3], s2 += s1; - s1 += ptr[4], s2 += s1; - s1 += ptr[5], s2 += s1; - s1 += ptr[6], s2 += s1; - s1 += ptr[7], s2 += s1; + s1 += ptr[0]; + s2 += s1; + s1 += ptr[1]; + s2 += s1; + s1 += ptr[2]; + s2 += s1; + s1 += ptr[3]; + s2 += s1; + s1 += ptr[4]; + s2 += s1; + s1 += ptr[5]; + s2 += s1; + s1 += ptr[6]; + s2 += s1; + s1 += ptr[7]; + s2 += s1; } - for (; i < block_len; ++i) - s1 += *ptr++, s2 += s1; - s1 %= 65521U, s2 %= 65521U; + for (; i < block_len; ++i) { + s1 += *ptr++; + s2 += s1; + } + s1 %= 65521U; + s2 %= 65521U; buf_len -= block_len; block_len = 5552; } @@ -2802,20 +2829,20 @@ common_exit: void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags) { tinfl_decompressor decomp; - void *pBuf = NULL, *pNew_buf; + void *pBuf = nullptr, *pNew_buf; size_t src_buf_ofs = 0, out_buf_capacity = 0; *pOut_len = 0; tinfl_init(&decomp); for (;;) { size_t src_buf_size = src_buf_len - src_buf_ofs, dst_buf_size = out_buf_capacity - *pOut_len, new_out_buf_capacity; - tinfl_status status = tinfl_decompress(&decomp, (const mz_uint8 *)pSrc_buf + src_buf_ofs, &src_buf_size, (mz_uint8 *)pBuf, pBuf ? (mz_uint8 *)pBuf + *pOut_len : NULL, &dst_buf_size, + tinfl_status status = tinfl_decompress(&decomp, (const mz_uint8 *)pSrc_buf + src_buf_ofs, &src_buf_size, (mz_uint8 *)pBuf, pBuf ? (mz_uint8 *)pBuf + *pOut_len : nullptr, &dst_buf_size, (flags & ~TINFL_FLAG_HAS_MORE_INPUT) | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF); if ((status < 0) || (status == TINFL_STATUS_NEEDS_MORE_INPUT)) { MZ_FREE(pBuf); *pOut_len = 0; - return NULL; + return nullptr; } src_buf_ofs += src_buf_size; *pOut_len += dst_buf_size; @@ -2829,7 +2856,7 @@ void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, siz { MZ_FREE(pBuf); *pOut_len = 0; - return NULL; + return nullptr; } pBuf = pNew_buf; out_buf_capacity = new_out_buf_capacity; @@ -2935,15 +2962,15 @@ extern "C" { #if defined(_MSC_VER) || defined(__MINGW64__) static FILE *mz_fopen(const char *pFilename, const char *pMode) { - FILE *pFile = NULL; + FILE *pFile = nullptr; fopen_s(&pFile, pFilename, pMode); return pFile; } static FILE *mz_freopen(const char *pPath, const char *pMode, FILE *pStream) { - FILE *pFile = NULL; + FILE *pFile = nullptr; if (freopen_s(&pFile, pPath, pMode, pStream)) - return NULL; + return nullptr; return pFile; } #ifndef MINIZ_NO_TIME @@ -3207,7 +3234,7 @@ static mz_bool mz_zip_array_ensure_capacity(mz_zip_archive *pZip, mz_zip_array * while (new_capacity < min_new_capacity) new_capacity *= 2; } - if (NULL == (pNew_p = pZip->m_pRealloc(pZip->m_pAlloc_opaque, pArray->m_p, pArray->m_element_size, new_capacity))) + if (nullptr == (pNew_p = pZip->m_pRealloc(pZip->m_pAlloc_opaque, pArray->m_p, pArray->m_element_size, new_capacity))) return MZ_FALSE; pArray->m_p = pNew_p; pArray->m_capacity = new_capacity; @@ -3340,7 +3367,7 @@ static mz_bool mz_zip_reader_init_internal(mz_zip_archive *pZip, mz_uint flags) pZip->m_total_files = 0; pZip->m_last_error = MZ_ZIP_NO_ERROR; - if (NULL == (pZip->m_pState = (mz_zip_internal_state *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_internal_state)))) + if (nullptr == (pZip->m_pState = (mz_zip_internal_state *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_internal_state)))) return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); memset(pZip->m_pState, 0, sizeof(mz_zip_internal_state)); @@ -3731,7 +3758,7 @@ static mz_bool mz_zip_reader_end_internal(mz_zip_archive *pZip, mz_bool set_last if (pZip->m_pState) { mz_zip_internal_state *pState = pZip->m_pState; - pZip->m_pState = NULL; + pZip->m_pState = nullptr; mz_zip_array_clear(pZip, &pState->m_central_dir); mz_zip_array_clear(pZip, &pState->m_central_dir_offsets); @@ -3749,7 +3776,7 @@ static mz_bool mz_zip_reader_end_internal(mz_zip_archive *pZip, mz_bool set_last status = MZ_FALSE; } } - pState->m_pFile = NULL; + pState->m_pFile = nullptr; } #endif /* #ifndef MINIZ_NO_STDIO */ @@ -3807,7 +3834,7 @@ mz_bool mz_zip_reader_init_mem(mz_zip_archive *pZip, const void *pMem, size_t si pZip->m_archive_size = size; pZip->m_pRead = mz_zip_mem_read_func; pZip->m_pIO_opaque = pZip; - pZip->m_pNeeds_keepalive = NULL; + pZip->m_pNeeds_keepalive = nullptr; #ifdef __cplusplus pZip->m_pState->m_pMem = const_cast(pMem); @@ -3941,7 +3968,7 @@ mz_bool mz_zip_reader_init_cfile(mz_zip_archive *pZip, MZ_FILE *pFile, mz_uint64 static MZ_FORCEINLINE const mz_uint8 *mz_zip_get_cdh(mz_zip_archive *pZip, mz_uint file_index) { if ((!pZip) || (!pZip->m_pState) || (file_index >= pZip->m_total_files)) - return NULL; + return nullptr; return &MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index)); } @@ -4378,7 +4405,7 @@ mz_bool mz_zip_reader_extract_to_mem_no_alloc(mz_zip_archive *pZip, mz_uint file if (((sizeof(size_t) == sizeof(mz_uint32))) && (read_buf_size > 0x7FFFFFFF)) return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); - if (NULL == (pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)read_buf_size))) + if (nullptr == (pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)read_buf_size))) return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); read_buf_avail = 0; @@ -4435,19 +4462,19 @@ mz_bool mz_zip_reader_extract_to_mem_no_alloc(mz_zip_archive *pZip, mz_uint file mz_bool mz_zip_reader_extract_file_to_mem_no_alloc(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size) { mz_uint32 file_index; - if (!mz_zip_reader_locate_file_v2(pZip, pFilename, NULL, flags, &file_index)) + if (!mz_zip_reader_locate_file_v2(pZip, pFilename, nullptr, flags, &file_index)) return MZ_FALSE; return mz_zip_reader_extract_to_mem_no_alloc(pZip, file_index, pBuf, buf_size, flags, pUser_read_buf, user_read_buf_size); } mz_bool mz_zip_reader_extract_to_mem(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags) { - return mz_zip_reader_extract_to_mem_no_alloc(pZip, file_index, pBuf, buf_size, flags, NULL, 0); + return mz_zip_reader_extract_to_mem_no_alloc(pZip, file_index, pBuf, buf_size, flags, nullptr, 0); } mz_bool mz_zip_reader_extract_file_to_mem(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags) { - return mz_zip_reader_extract_file_to_mem_no_alloc(pZip, pFilename, pBuf, buf_size, flags, NULL, 0); + return mz_zip_reader_extract_file_to_mem_no_alloc(pZip, pFilename, pBuf, buf_size, flags, nullptr, 0); } void *mz_zip_reader_extract_to_heap(mz_zip_archive *pZip, mz_uint file_index, size_t *pSize, mz_uint flags) @@ -4462,7 +4489,7 @@ void *mz_zip_reader_extract_to_heap(mz_zip_archive *pZip, mz_uint file_index, si if (!p) { mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - return NULL; + return nullptr; } comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); @@ -4472,19 +4499,19 @@ void *mz_zip_reader_extract_to_heap(mz_zip_archive *pZip, mz_uint file_index, si if (((sizeof(size_t) == sizeof(mz_uint32))) && (alloc_size > 0x7FFFFFFF)) { mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); - return NULL; + return nullptr; } - if (NULL == (pBuf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)alloc_size))) + if (nullptr == (pBuf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)alloc_size))) { mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); - return NULL; + return nullptr; } if (!mz_zip_reader_extract_to_mem(pZip, file_index, pBuf, (size_t)alloc_size, flags)) { pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); - return NULL; + return nullptr; } if (pSize) @@ -4495,11 +4522,11 @@ void *mz_zip_reader_extract_to_heap(mz_zip_archive *pZip, mz_uint file_index, si void *mz_zip_reader_extract_file_to_heap(mz_zip_archive *pZip, const char *pFilename, size_t *pSize, mz_uint flags) { mz_uint32 file_index; - if (!mz_zip_reader_locate_file_v2(pZip, pFilename, NULL, flags, &file_index)) + if (!mz_zip_reader_locate_file_v2(pZip, pFilename, nullptr, flags, &file_index)) { if (pSize) *pSize = 0; - return MZ_FALSE; + return nullptr; //MZ_FALSE; } return mz_zip_reader_extract_to_heap(pZip, file_index, pSize, flags); } @@ -4510,8 +4537,8 @@ mz_bool mz_zip_reader_extract_to_callback(mz_zip_archive *pZip, mz_uint file_ind mz_uint file_crc32 = MZ_CRC32_INIT; mz_uint64 read_buf_size, read_buf_ofs = 0, read_buf_avail, comp_remaining, out_buf_ofs = 0, cur_file_ofs; mz_zip_archive_file_stat file_stat; - void *pRead_buf = NULL; - void *pWrite_buf = NULL; + void *pRead_buf = nullptr; + void *pWrite_buf = nullptr; mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; @@ -4555,7 +4582,7 @@ mz_bool mz_zip_reader_extract_to_callback(mz_zip_archive *pZip, mz_uint file_ind else { read_buf_size = MZ_MIN(file_stat.m_comp_size, (mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE); - if (NULL == (pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)read_buf_size))) + if (nullptr == (pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)read_buf_size))) return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); read_buf_avail = 0; @@ -4623,7 +4650,7 @@ mz_bool mz_zip_reader_extract_to_callback(mz_zip_archive *pZip, mz_uint file_ind tinfl_decompressor inflator; tinfl_init(&inflator); - if (NULL == (pWrite_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, TINFL_LZ_DICT_SIZE))) + if (nullptr == (pWrite_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, TINFL_LZ_DICT_SIZE))) { mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); status = TINFL_STATUS_FAILED; @@ -4705,7 +4732,7 @@ mz_bool mz_zip_reader_extract_to_callback(mz_zip_archive *pZip, mz_uint file_ind mz_bool mz_zip_reader_extract_file_to_callback(mz_zip_archive *pZip, const char *pFilename, mz_file_write_func pCallback, void *pOpaque, mz_uint flags) { mz_uint32 file_index; - if (!mz_zip_reader_locate_file_v2(pZip, pFilename, NULL, flags, &file_index)) + if (!mz_zip_reader_locate_file_v2(pZip, pFilename, nullptr, flags, &file_index)) return MZ_FALSE; return mz_zip_reader_extract_to_callback(pZip, file_index, pCallback, pOpaque, flags); @@ -4756,7 +4783,7 @@ mz_bool mz_zip_reader_extract_to_file(mz_zip_archive *pZip, mz_uint file_index, mz_bool mz_zip_reader_extract_file_to_file(mz_zip_archive *pZip, const char *pArchive_filename, const char *pDst_filename, mz_uint flags) { mz_uint32 file_index; - if (!mz_zip_reader_locate_file_v2(pZip, pArchive_filename, NULL, flags, &file_index)) + if (!mz_zip_reader_locate_file_v2(pZip, pArchive_filename, nullptr, flags, &file_index)) return MZ_FALSE; return mz_zip_reader_extract_to_file(pZip, file_index, pDst_filename, flags); @@ -4778,7 +4805,7 @@ mz_bool mz_zip_reader_extract_to_cfile(mz_zip_archive *pZip, mz_uint file_index, mz_bool mz_zip_reader_extract_file_to_cfile(mz_zip_archive *pZip, const char *pArchive_filename, MZ_FILE *pFile, mz_uint flags) { mz_uint32 file_index; - if (!mz_zip_reader_locate_file_v2(pZip, pArchive_filename, NULL, flags, &file_index)) + if (!mz_zip_reader_locate_file_v2(pZip, pArchive_filename, nullptr, flags, &file_index)) return MZ_FALSE; return mz_zip_reader_extract_to_cfile(pZip, file_index, pFile, flags); @@ -5037,7 +5064,7 @@ mz_bool mz_zip_validate_archive(mz_zip_archive *pZip, mz_uint flags) if (!mz_zip_reader_file_stat(pZip, i, &stat)) return MZ_FALSE; - if (!mz_zip_reader_locate_file_v2(pZip, stat.m_filename, NULL, 0, &found_index)) + if (!mz_zip_reader_locate_file_v2(pZip, stat.m_filename, nullptr, 0, &found_index)) return MZ_FALSE; /* This check can fail if there are duplicate filenames in the archive (which we don't check for when writing - that's up to the user) */ @@ -5186,7 +5213,7 @@ static size_t mz_zip_heap_write_func(void *pOpaque, mz_uint64 file_ofs, const vo while (new_capacity < new_size) new_capacity *= 2; - if (NULL == (pNew_block = pZip->m_pRealloc(pZip->m_pAlloc_opaque, pState->m_pMem, 1, new_capacity))) + if (nullptr == (pNew_block = pZip->m_pRealloc(pZip->m_pAlloc_opaque, pState->m_pMem, 1, new_capacity))) { mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); return 0; @@ -5213,7 +5240,7 @@ static mz_bool mz_zip_writer_end_internal(mz_zip_archive *pZip, mz_bool set_last } pState = pZip->m_pState; - pZip->m_pState = NULL; + pZip->m_pState = nullptr; mz_zip_array_clear(pZip, &pState->m_central_dir); mz_zip_array_clear(pZip, &pState->m_central_dir_offsets); mz_zip_array_clear(pZip, &pState->m_sorted_central_dir_offsets); @@ -5231,14 +5258,14 @@ static mz_bool mz_zip_writer_end_internal(mz_zip_archive *pZip, mz_bool set_last } } - pState->m_pFile = NULL; + pState->m_pFile = nullptr; } #endif /* #ifndef MINIZ_NO_STDIO */ if ((pZip->m_pWrite == mz_zip_heap_write_func) && (pState->m_pMem)) { pZip->m_pFree(pZip->m_pAlloc_opaque, pState->m_pMem); - pState->m_pMem = NULL; + pState->m_pMem = nullptr; } pZip->m_pFree(pZip->m_pAlloc_opaque, pState); @@ -5277,7 +5304,7 @@ mz_bool mz_zip_writer_init_v2(mz_zip_archive *pZip, mz_uint64 existing_size, mz_ pZip->m_central_directory_file_ofs = 0; pZip->m_total_files = 0; - if (NULL == (pZip->m_pState = (mz_zip_internal_state *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_internal_state)))) + if (nullptr == (pZip->m_pState = (mz_zip_internal_state *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_internal_state)))) return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); memset(pZip->m_pState, 0, sizeof(mz_zip_internal_state)); @@ -5303,7 +5330,7 @@ mz_bool mz_zip_writer_init(mz_zip_archive *pZip, mz_uint64 existing_size) mz_bool mz_zip_writer_init_heap_v2(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size, mz_uint flags) { pZip->m_pWrite = mz_zip_heap_write_func; - pZip->m_pNeeds_keepalive = NULL; + pZip->m_pNeeds_keepalive = nullptr; if (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING) pZip->m_pRead = mz_zip_mem_read_func; @@ -5317,7 +5344,7 @@ mz_bool mz_zip_writer_init_heap_v2(mz_zip_archive *pZip, size_t size_to_reserve_ if (0 != (initial_allocation_size = MZ_MAX(initial_allocation_size, size_to_reserve_at_beginning))) { - if (NULL == (pZip->m_pState->m_pMem = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, initial_allocation_size))) + if (nullptr == (pZip->m_pState->m_pMem = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, initial_allocation_size))) { mz_zip_writer_end_internal(pZip, MZ_FALSE); return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); @@ -5360,7 +5387,7 @@ mz_bool mz_zip_writer_init_file_v2(mz_zip_archive *pZip, const char *pFilename, MZ_FILE *pFile; pZip->m_pWrite = mz_zip_file_write_func; - pZip->m_pNeeds_keepalive = NULL; + pZip->m_pNeeds_keepalive = nullptr; if (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING) pZip->m_pRead = mz_zip_file_read_func; @@ -5370,7 +5397,7 @@ mz_bool mz_zip_writer_init_file_v2(mz_zip_archive *pZip, const char *pFilename, if (!mz_zip_writer_init_v2(pZip, size_to_reserve_at_beginning, flags)) return MZ_FALSE; - if (NULL == (pFile = MZ_FOPEN(pFilename, (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING) ? "w+b" : "wb"))) + if (nullptr == (pFile = MZ_FOPEN(pFilename, (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING) ? "w+b" : "wb"))) { mz_zip_writer_end(pZip); return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); @@ -5405,7 +5432,7 @@ mz_bool mz_zip_writer_init_file_v2(mz_zip_archive *pZip, const char *pFilename, mz_bool mz_zip_writer_init_cfile(mz_zip_archive *pZip, MZ_FILE *pFile, mz_uint flags) { pZip->m_pWrite = mz_zip_file_write_func; - pZip->m_pNeeds_keepalive = NULL; + pZip->m_pNeeds_keepalive = nullptr; if (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING) pZip->m_pRead = mz_zip_file_read_func; @@ -5469,16 +5496,16 @@ mz_bool mz_zip_writer_init_from_reader_v2(mz_zip_archive *pZip, const char *pFil return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); /* Archive is being read from stdio and was originally opened only for reading. Try to reopen as writable. */ - if (NULL == (pState->m_pFile = MZ_FREOPEN(pFilename, "r+b", pState->m_pFile))) + if (nullptr == (pState->m_pFile = MZ_FREOPEN(pFilename, "r+b", pState->m_pFile))) { - /* The mz_zip_archive is now in a bogus state because pState->m_pFile is NULL, so just close it. */ + /* The mz_zip_archive is now in a bogus state because pState->m_pFile is nullptr, so just close it. */ mz_zip_reader_end_internal(pZip, MZ_FALSE); return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); } } pZip->m_pWrite = mz_zip_file_write_func; - pZip->m_pNeeds_keepalive = NULL; + pZip->m_pNeeds_keepalive = nullptr; #endif /* #ifdef MINIZ_NO_STDIO */ } else if (pState->m_pMem) @@ -5489,7 +5516,7 @@ mz_bool mz_zip_writer_init_from_reader_v2(mz_zip_archive *pZip, const char *pFil pState->m_mem_capacity = pState->m_mem_size; pZip->m_pWrite = mz_zip_heap_write_func; - pZip->m_pNeeds_keepalive = NULL; + pZip->m_pNeeds_keepalive = nullptr; } /* Archive is being read via a user provided read function - make sure the user has specified a write function too. */ else if (!pZip->m_pWrite) @@ -5518,7 +5545,7 @@ mz_bool mz_zip_writer_init_from_reader(mz_zip_archive *pZip, const char *pFilena /* TODO: pArchive_name is a terrible name here! */ mz_bool mz_zip_writer_add_mem(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, mz_uint level_and_flags) { - return mz_zip_writer_add_mem_ex(pZip, pArchive_name, pBuf, buf_size, NULL, 0, level_and_flags, 0, 0); + return mz_zip_writer_add_mem_ex(pZip, pArchive_name, pBuf, buf_size, nullptr, 0, level_and_flags, 0, 0); } typedef struct @@ -5704,7 +5731,7 @@ static mz_bool mz_zip_writer_write_zeros(mz_zip_archive *pZip, mz_uint64 cur_fil mz_bool mz_zip_writer_add_mem_ex(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, mz_uint64 uncomp_size, mz_uint32 uncomp_crc32) { - return mz_zip_writer_add_mem_ex_v2(pZip, pArchive_name, pBuf, buf_size, pComment, comment_size, level_and_flags, uncomp_size, uncomp_crc32, NULL, NULL, 0, NULL, 0); + return mz_zip_writer_add_mem_ex_v2(pZip, pArchive_name, pBuf, buf_size, pComment, comment_size, level_and_flags, uncomp_size, uncomp_crc32, nullptr, nullptr, 0, nullptr, 0); } mz_bool mz_zip_writer_add_mem_ex_v2(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, @@ -5716,10 +5743,10 @@ mz_bool mz_zip_writer_add_mem_ex_v2(mz_zip_archive *pZip, const char *pArchive_n mz_uint64 local_dir_header_ofs = pZip->m_archive_size, cur_archive_file_ofs = pZip->m_archive_size, comp_size = 0; size_t archive_name_size; mz_uint8 local_dir_header[MZ_ZIP_LOCAL_DIR_HEADER_SIZE]; - tdefl_compressor *pComp = NULL; + tdefl_compressor *pComp = nullptr; mz_bool store_data_uncompressed; mz_zip_internal_state *pState; - mz_uint8 *pExtra_data = NULL; + mz_uint8 *pExtra_data = nullptr; mz_uint32 extra_size = 0; mz_uint8 extra_data[MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE]; mz_uint16 bit_flags = 0; @@ -5766,7 +5793,7 @@ mz_bool mz_zip_writer_add_mem_ex_v2(mz_zip_archive *pZip, const char *pArchive_n return mz_zip_set_error(pZip, MZ_ZIP_INVALID_FILENAME); #ifndef MINIZ_NO_TIME - if (last_modified != NULL) + if (last_modified != nullptr) { mz_zip_time_t_to_dos_time(*last_modified, &dos_time, &dos_date); } @@ -5814,7 +5841,7 @@ mz_bool mz_zip_writer_add_mem_ex_v2(mz_zip_archive *pZip, const char *pArchive_n if ((!store_data_uncompressed) && (buf_size)) { - if (NULL == (pComp = (tdefl_compressor *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(tdefl_compressor)))) + if (nullptr == (pComp = (tdefl_compressor *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(tdefl_compressor)))) return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); } @@ -5843,8 +5870,8 @@ mz_bool mz_zip_writer_add_mem_ex_v2(mz_zip_archive *pZip, const char *pArchive_n if (uncomp_size >= MZ_UINT32_MAX || local_dir_header_ofs >= MZ_UINT32_MAX) { pExtra_data = extra_data; - extra_size = mz_zip_writer_create_zip64_extra_data(extra_data, (uncomp_size >= MZ_UINT32_MAX) ? &uncomp_size : NULL, - (uncomp_size >= MZ_UINT32_MAX) ? &comp_size : NULL, (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : NULL); + extra_size = mz_zip_writer_create_zip64_extra_data(extra_data, (uncomp_size >= MZ_UINT32_MAX) ? &uncomp_size : nullptr, + (uncomp_size >= MZ_UINT32_MAX) ? &comp_size : nullptr, (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : nullptr); } if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, extra_size + user_extra_data_len, 0, 0, 0, method, bit_flags, dos_time, dos_date)) @@ -5862,7 +5889,7 @@ mz_bool mz_zip_writer_add_mem_ex_v2(mz_zip_archive *pZip, const char *pArchive_n } cur_archive_file_ofs += archive_name_size; - if (pExtra_data != NULL) + if (pExtra_data != nullptr) { if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, extra_data, extra_size) != extra_size) return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); @@ -5940,7 +5967,7 @@ mz_bool mz_zip_writer_add_mem_ex_v2(mz_zip_archive *pZip, const char *pArchive_n } pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); - pComp = NULL; + pComp = nullptr; if (uncomp_size) { @@ -5951,7 +5978,7 @@ mz_bool mz_zip_writer_add_mem_ex_v2(mz_zip_archive *pZip, const char *pArchive_n MZ_WRITE_LE32(local_dir_footer + 0, MZ_ZIP_DATA_DESCRIPTOR_ID); MZ_WRITE_LE32(local_dir_footer + 4, uncomp_crc32); - if (pExtra_data == NULL) + if (pExtra_data == nullptr) { if ((comp_size > MZ_UINT32_MAX) || (cur_archive_file_ofs > MZ_UINT32_MAX)) return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); @@ -5972,10 +5999,10 @@ mz_bool mz_zip_writer_add_mem_ex_v2(mz_zip_archive *pZip, const char *pArchive_n cur_archive_file_ofs += local_dir_footer_size; } - if (pExtra_data != NULL) + if (pExtra_data != nullptr) { - extra_size = mz_zip_writer_create_zip64_extra_data(extra_data, (uncomp_size >= MZ_UINT32_MAX) ? &uncomp_size : NULL, - (uncomp_size >= MZ_UINT32_MAX) ? &comp_size : NULL, (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : NULL); + extra_size = mz_zip_writer_create_zip64_extra_data(extra_data, (uncomp_size >= MZ_UINT32_MAX) ? &uncomp_size : nullptr, + (uncomp_size >= MZ_UINT32_MAX) ? &comp_size : nullptr, (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : nullptr); } if (!mz_zip_writer_add_to_central_dir(pZip, pArchive_name, (mz_uint16)archive_name_size, pExtra_data, extra_size, pComment, @@ -5999,7 +6026,7 @@ mz_bool mz_zip_writer_add_cfile(mz_zip_archive *pZip, const char *pArchive_name, mz_uint64 local_dir_header_ofs, cur_archive_file_ofs = pZip->m_archive_size, uncomp_size = size_to_add, comp_size = 0; size_t archive_name_size; mz_uint8 local_dir_header[MZ_ZIP_LOCAL_DIR_HEADER_SIZE]; - mz_uint8 *pExtra_data = NULL; + mz_uint8 *pExtra_data = nullptr; mz_uint32 extra_size = 0; mz_uint8 extra_data[MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE]; mz_zip_internal_state *pState; @@ -6099,8 +6126,8 @@ mz_bool mz_zip_writer_add_cfile(mz_zip_archive *pZip, const char *pArchive_name, if (uncomp_size >= MZ_UINT32_MAX || local_dir_header_ofs >= MZ_UINT32_MAX) { pExtra_data = extra_data; - extra_size = mz_zip_writer_create_zip64_extra_data(extra_data, (uncomp_size >= MZ_UINT32_MAX) ? &uncomp_size : NULL, - (uncomp_size >= MZ_UINT32_MAX) ? &comp_size : NULL, (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : NULL); + extra_size = mz_zip_writer_create_zip64_extra_data(extra_data, (uncomp_size >= MZ_UINT32_MAX) ? &uncomp_size : nullptr, + (uncomp_size >= MZ_UINT32_MAX) ? &comp_size : nullptr, (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : nullptr); } if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, extra_size + user_extra_data_len, 0, 0, 0, method, gen_flags, dos_time, dos_date)) @@ -6213,7 +6240,7 @@ mz_bool mz_zip_writer_add_cfile(mz_zip_archive *pZip, const char *pArchive_name, uncomp_crc32 = (mz_uint32)mz_crc32(uncomp_crc32, (const mz_uint8 *)pRead_buf, in_buf_size); uncomp_remaining -= in_buf_size; - if (pZip->m_pNeeds_keepalive != NULL && pZip->m_pNeeds_keepalive(pZip->m_pIO_opaque)) + if (pZip->m_pNeeds_keepalive != nullptr && pZip->m_pNeeds_keepalive(pZip->m_pIO_opaque)) flush = TDEFL_FULL_FLUSH; status = tdefl_compress_buffer(pComp, pRead_buf, in_buf_size, uncomp_remaining ? flush : TDEFL_FINISH); @@ -6250,7 +6277,7 @@ mz_bool mz_zip_writer_add_cfile(mz_zip_archive *pZip, const char *pArchive_name, MZ_WRITE_LE32(local_dir_footer + 0, MZ_ZIP_DATA_DESCRIPTOR_ID); MZ_WRITE_LE32(local_dir_footer + 4, uncomp_crc32); - if (pExtra_data == NULL) + if (pExtra_data == nullptr) { if (comp_size > MZ_UINT32_MAX) return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); @@ -6271,10 +6298,10 @@ mz_bool mz_zip_writer_add_cfile(mz_zip_archive *pZip, const char *pArchive_name, cur_archive_file_ofs += local_dir_footer_size; } - if (pExtra_data != NULL) + if (pExtra_data != nullptr) { - extra_size = mz_zip_writer_create_zip64_extra_data(extra_data, (uncomp_size >= MZ_UINT32_MAX) ? &uncomp_size : NULL, - (uncomp_size >= MZ_UINT32_MAX) ? &comp_size : NULL, (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : NULL); + extra_size = mz_zip_writer_create_zip64_extra_data(extra_data, (uncomp_size >= MZ_UINT32_MAX) ? &uncomp_size : nullptr, + (uncomp_size >= MZ_UINT32_MAX) ? &comp_size : nullptr, (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : nullptr); } if (!mz_zip_writer_add_to_central_dir(pZip, pArchive_name, (mz_uint16)archive_name_size, pExtra_data, extra_size, pComment, comment_size, @@ -6290,10 +6317,10 @@ mz_bool mz_zip_writer_add_cfile(mz_zip_archive *pZip, const char *pArchive_name, mz_bool mz_zip_writer_add_file(mz_zip_archive *pZip, const char *pArchive_name, const char *pSrc_filename, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags) { - MZ_FILE *pSrc_file = NULL; + MZ_FILE *pSrc_file = nullptr; mz_uint64 uncomp_size = 0; MZ_TIME_T file_modified_time; - MZ_TIME_T *pFile_time = NULL; + MZ_TIME_T *pFile_time = nullptr; mz_bool status; memset(&file_modified_time, 0, sizeof(file_modified_time)); @@ -6312,7 +6339,7 @@ mz_bool mz_zip_writer_add_file(mz_zip_archive *pZip, const char *pArchive_name, uncomp_size = MZ_FTELL64(pSrc_file); MZ_FSEEK64(pSrc_file, 0, SEEK_SET); - status = mz_zip_writer_add_cfile(pZip, pArchive_name, pSrc_file, uncomp_size, pFile_time, pComment, comment_size, level_and_flags, NULL, 0, NULL, 0); + status = mz_zip_writer_add_cfile(pZip, pArchive_name, pSrc_file, uncomp_size, pFile_time, pComment, comment_size, level_and_flags, nullptr, 0, nullptr, 0); MZ_FCLOSE(pSrc_file); @@ -6429,7 +6456,7 @@ mz_bool mz_zip_writer_add_from_zip_reader(mz_zip_archive *pZip, mz_zip_archive * return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); /* Get pointer to the source central dir header and crack it */ - if (NULL == (pSrc_central_header = mz_zip_get_cdh(pSource_zip, src_file_index))) + if (nullptr == (pSrc_central_header = mz_zip_get_cdh(pSource_zip, src_file_index))) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); if (MZ_READ_LE32(pSrc_central_header + MZ_ZIP_CDH_SIG_OFS) != MZ_ZIP_CENTRAL_DIR_HEADER_SIG) @@ -6458,7 +6485,7 @@ mz_bool mz_zip_writer_add_from_zip_reader(mz_zip_archive *pZip, mz_zip_archive * return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); } - if (!mz_zip_file_stat_internal(pSource_zip, src_file_index, pSrc_central_header, &src_file_stat, NULL)) + if (!mz_zip_file_stat_internal(pSource_zip, src_file_index, pSrc_central_header, &src_file_stat, nullptr)) return MZ_FALSE; cur_src_file_ofs = src_file_stat.m_local_header_ofs; @@ -6575,7 +6602,7 @@ mz_bool mz_zip_writer_add_from_zip_reader(mz_zip_archive *pZip, mz_zip_archive * cur_dst_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE; /* Copy over the source archive bytes to the dest archive, also ensure we have enough buf space to handle optional data descriptor */ - if (NULL == (pBuf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)MZ_MAX(32U, MZ_MIN((mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE, src_archive_bytes_remaining))))) + if (nullptr == (pBuf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)MZ_MAX(32U, MZ_MIN((mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE, src_archive_bytes_remaining))))) return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); while (src_archive_bytes_remaining) @@ -6683,7 +6710,7 @@ mz_bool mz_zip_writer_add_from_zip_reader(mz_zip_archive *pZip, mz_zip_archive * MZ_WRITE_LE32(new_central_header + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS, MZ_UINT32_MAX); MZ_WRITE_LE32(new_central_header + MZ_ZIP_CDH_LOCAL_HEADER_OFS, MZ_UINT32_MAX); - if (!mz_zip_writer_update_zip64_extension_block(&new_ext_block, pZip, pSrc_ext, src_ext_len, &src_file_stat.m_comp_size, &src_file_stat.m_uncomp_size, &local_dir_header_ofs, NULL)) + if (!mz_zip_writer_update_zip64_extension_block(&new_ext_block, pZip, pSrc_ext, src_ext_len, &src_file_stat.m_comp_size, &src_file_stat.m_uncomp_size, &local_dir_header_ofs, nullptr)) { mz_zip_array_clear(pZip, &new_ext_block); return MZ_FALSE; @@ -6855,7 +6882,7 @@ mz_bool mz_zip_writer_finalize_heap_archive(mz_zip_archive *pZip, void **ppBuf, if ((!ppBuf) || (!pSize)) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - *ppBuf = NULL; + *ppBuf = nullptr; *pSize = 0; if ((!pZip) || (!pZip->m_pState)) @@ -6869,7 +6896,7 @@ mz_bool mz_zip_writer_finalize_heap_archive(mz_zip_archive *pZip, void **ppBuf, *ppBuf = pZip->m_pState->m_pMem; *pSize = pZip->m_pState->m_mem_size; - pZip->m_pState->m_pMem = NULL; + pZip->m_pState->m_pMem = nullptr; pZip->m_pState->m_mem_size = pZip->m_pState->m_mem_capacity = 0; return MZ_TRUE; @@ -6883,7 +6910,7 @@ mz_bool mz_zip_writer_end(mz_zip_archive *pZip) #ifndef MINIZ_NO_STDIO mz_bool mz_zip_add_mem_to_archive_file_in_place(const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags) { - return mz_zip_add_mem_to_archive_file_in_place_v2(pZip_filename, pArchive_name, pBuf, buf_size, pComment, comment_size, level_and_flags, NULL); + return mz_zip_add_mem_to_archive_file_in_place_v2(pZip_filename, pArchive_name, pBuf, buf_size, pComment, comment_size, level_and_flags, nullptr); } mz_bool mz_zip_add_mem_to_archive_file_in_place_v2(const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, mz_zip_error *pErr) @@ -6983,7 +7010,7 @@ void *mz_zip_extract_archive_file_to_heap_v2(const char *pZip_filename, const ch { mz_uint32 file_index; mz_zip_archive zip_archive; - void *p = NULL; + void *p = nullptr; if (pSize) *pSize = 0; @@ -6993,7 +7020,7 @@ void *mz_zip_extract_archive_file_to_heap_v2(const char *pZip_filename, const ch if (pErr) *pErr = MZ_ZIP_INVALID_PARAMETER; - return NULL; + return nullptr; } mz_zip_zero_struct(&zip_archive); @@ -7002,7 +7029,7 @@ void *mz_zip_extract_archive_file_to_heap_v2(const char *pZip_filename, const ch if (pErr) *pErr = zip_archive.m_last_error; - return NULL; + return nullptr; } if (mz_zip_reader_locate_file_v2(&zip_archive, pArchive_name, pComment, flags, &file_index)) @@ -7010,7 +7037,7 @@ void *mz_zip_extract_archive_file_to_heap_v2(const char *pZip_filename, const ch p = mz_zip_reader_extract_to_heap(&zip_archive, file_index, pSize, flags); } - mz_zip_reader_end_internal(&zip_archive, p != NULL); + mz_zip_reader_end_internal(&zip_archive, p != nullptr); if (pErr) *pErr = zip_archive.m_last_error; @@ -7020,7 +7047,7 @@ void *mz_zip_extract_archive_file_to_heap_v2(const char *pZip_filename, const ch void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const char *pArchive_name, size_t *pSize, mz_uint flags) { - return mz_zip_extract_archive_file_to_heap_v2(pZip_filename, pArchive_name, NULL, pSize, flags, NULL); + return mz_zip_extract_archive_file_to_heap_v2(pZip_filename, pArchive_name, nullptr, pSize, flags, nullptr); } #endif /* #ifndef MINIZ_NO_STDIO */ @@ -7192,7 +7219,7 @@ mz_uint64 mz_zip_get_archive_file_start_offset(mz_zip_archive *pZip) MZ_FILE *mz_zip_get_cfile(mz_zip_archive *pZip) { if ((!pZip) || (!pZip->m_pState)) - return 0; + return nullptr; return pZip->m_pState->m_pFile; } @@ -7227,7 +7254,7 @@ mz_uint mz_zip_reader_get_filename(mz_zip_archive *pZip, mz_uint file_index, cha mz_bool mz_zip_reader_file_stat(mz_zip_archive *pZip, mz_uint file_index, mz_zip_archive_file_stat *pStat) { - return mz_zip_file_stat_internal(pZip, file_index, mz_zip_get_cdh(pZip, file_index), pStat, NULL); + return mz_zip_file_stat_internal(pZip, file_index, mz_zip_get_cdh(pZip, file_index), pStat, nullptr); } mz_bool mz_zip_end(mz_zip_archive *pZip) diff --git a/source/detail/serialization/xlsx_consumer.cpp b/source/detail/serialization/xlsx_consumer.cpp index f306aee2..cf64aecc 100644 --- a/source/detail/serialization/xlsx_consumer.cpp +++ b/source/detail/serialization/xlsx_consumer.cpp @@ -23,6 +23,8 @@ #include #include // for std::accumulate +#include +#include #include #include @@ -58,14 +60,20 @@ struct hash namespace { -xml::qname qn(const std::string &namespace_, const std::string &name) +xml::qname &qn(const std::string &namespace_, const std::string &name) { - return xml::qname(xlnt::constants::ns(namespace_), name); -} + using qname_map = std::unordered_map; + static auto &memo = *new std::unordered_map(); -#ifndef NDEBUG -#define THROW_ON_INVALID_XML -#endif + auto &ns_memo = memo[namespace_]; + + if (ns_memo.find(name) == ns_memo.end()) + { + return ns_memo.emplace(name, xml::qname(xlnt::constants::ns(namespace_), name)).first->second; + } + + return ns_memo[name]; +} #ifdef THROW_ON_INVALID_XML #define unexpected_element(element) throw xlnt::exception(element.string()); @@ -96,14 +104,24 @@ bool is_true(const std::string &bool_string) #endif } -/// -/// Helper template function that returns true if element is in container. -/// -template -bool contains(const std::vector &container, const T &element) +struct number_converter { - return std::find(container.begin(), container.end(), element) != container.end(); -} + number_converter() + { + stream.imbue(std::locale("C")); + } + + double stold(const std::string &s) + { + stream.str(s); + stream.clear(); + stream >> result; + return result; + } + + std::istringstream stream; + double result; +}; } // namespace @@ -149,12 +167,6 @@ void xlsx_consumer::open(std::istream &source) populate_workbook(true); } -// caching frequently used names -static const auto sheetData_el = qn("spreadsheetml", "sheetData"); -static const auto row_el = qn("spreadsheetml", "row"); -static const auto cell_el = qn("spreadsheetml", "c"); -static const auto val_el = qn("spreadsheetml", "v"); - cell xlsx_consumer::read_cell() { if (!has_cell()) @@ -164,9 +176,9 @@ cell xlsx_consumer::read_cell() auto ws = worksheet(current_worksheet_); - if (in_element(sheetData_el)) + if (in_element(qn("spreadsheetml", "sheetData"))) { - expect_start_element(row_el, xml::content::complex); // CT_Row + expect_start_element(qn("spreadsheetml", "row"), xml::content::complex); // CT_Row auto row_index = static_cast(std::stoul(parser().attribute("r"))); if (parser().attribute_present("ht")) @@ -189,12 +201,12 @@ cell xlsx_consumer::read_cell() "ph", "spans" }); } - if (!in_element(row_el)) + if (!in_element(qn("spreadsheetml", "row"))) { return cell(nullptr); - } + } - expect_start_element(cell_el, xml::content::complex); + expect_start_element(qn("spreadsheetml", "c"), xml::content::complex); auto cell = streaming_ ? xlnt::cell(streaming_cell_.get()) : ws.cell(cell_reference(parser().attribute("r"))); @@ -206,8 +218,10 @@ cell xlsx_consumer::read_cell() auto has_type = parser().attribute_present("t"); auto type = has_type ? parser().attribute("t") : "n"; - if (parser().attribute_present("s")) - cell.format(target_.format(std::stoull(parser().attribute("s")))); + if (parser().attribute_present("s")) + { + cell.format(target_.format(std::stoull(parser().attribute("s")))); + } auto has_value = false; auto value_string = std::string(); @@ -216,11 +230,11 @@ cell xlsx_consumer::read_cell() auto has_shared_formula = false; auto formula_value_string = std::string(); - while (in_element(cell_el)) + while (in_element(qn("spreadsheetml", "c"))) { auto current_element = expect_start_element(xml::content::mixed); - if (current_element == val_el) // s:ST_Xstring + if (current_element == qn("spreadsheetml", "v")) // s:ST_Xstring { has_value = true; value_string = read_text(); @@ -253,13 +267,15 @@ cell xlsx_consumer::read_cell() expect_end_element(current_element); } - expect_end_element(cell_el); + expect_end_element(qn("spreadsheetml", "c")); if (has_formula && !has_shared_formula) { cell.formula(formula_value_string); } + number_converter converter; + if (has_value) { if (type == "str") @@ -274,7 +290,7 @@ cell xlsx_consumer::read_cell() } else if (type == "s") { - cell.d_->value_numeric_ = std::stold(value_string); + cell.d_->value_numeric_ = converter.stold(value_string); cell.data_type(cell::type::shared_string); } else if (type == "b") // boolean @@ -283,7 +299,7 @@ cell xlsx_consumer::read_cell() } else if (type == "n") // numeric { - cell.value(std::stold(value_string)); + cell.value(converter.stold(value_string)); } else if (!value_string.empty() && value_string[0] == '#') { @@ -291,13 +307,13 @@ cell xlsx_consumer::read_cell() } } - if (!in_element(row_el)) + if (!in_element(qn("spreadsheetml", "row"))) { - expect_end_element(row_el); + expect_end_element(qn("spreadsheetml", "row")); - if (!in_element(sheetData_el)) + if (!in_element(qn("spreadsheetml", "sheetData"))) { - expect_end_element(sheetData_el); + expect_end_element(qn("spreadsheetml", "sheetData")); } } @@ -332,7 +348,6 @@ std::string xlsx_consumer::read_worksheet_begin(const std::string &rel_id) expect_start_element(qn("spreadsheetml", "worksheet"), xml::content::complex); // CT_Worksheet skip_attributes({ qn("mc", "Ignorable") }); - read_namespaces(); while (in_element(qn("spreadsheetml", "worksheet"))) { @@ -547,6 +562,8 @@ void xlsx_consumer::read_worksheet_sheetdata() return; } + number_converter converter; + while (in_element(qn("spreadsheetml", "sheetData"))) { expect_start_element(qn("spreadsheetml", "row"), xml::content::complex); // CT_Row @@ -580,8 +597,10 @@ void xlsx_consumer::read_worksheet_sheetdata() auto has_type = parser().attribute_present("t"); auto type = has_type ? parser().attribute("t") : "n"; - if (parser().attribute_present("s")) - cell.format(target_.format(std::stoull(parser().attribute("s")))); + if (parser().attribute_present("s")) + { + cell.format(target_.format(std::stoull(parser().attribute("s")))); + } auto has_value = false; auto value_string = std::string(); @@ -648,7 +667,7 @@ void xlsx_consumer::read_worksheet_sheetdata() } else if (type == "s") { - cell.d_->value_numeric_ = std::stold(value_string); + cell.d_->value_numeric_ = converter.stold(value_string); cell.data_type(cell::type::shared_string); } else if (type == "b") // boolean @@ -657,7 +676,7 @@ void xlsx_consumer::read_worksheet_sheetdata() } else if (type == "n") // numeric { - cell.value(std::stold(value_string)); + cell.value(converter.stold(value_string)); } else if (!value_string.empty() && value_string[0] == '#') { @@ -1020,8 +1039,8 @@ xml::parser &xlsx_consumer::parser() bool xlsx_consumer::has_cell() { - return in_element(row_el) - || in_element(sheetData_el); + return in_element(qn("spreadsheetml", "row")) + || in_element(qn("spreadsheetml", "sheetData")); } std::vector xlsx_consumer::read_relationships(const path &part) @@ -1343,7 +1362,6 @@ void xlsx_consumer::read_office_document(const std::string &content_type) // CT_ expect_start_element(qn("workbook", "workbook"), xml::content::complex); skip_attribute(qn("mc", "Ignorable")); - read_namespaces(); while (in_element(qn("workbook", "workbook"))) { @@ -1668,7 +1686,6 @@ void xlsx_consumer::read_stylesheet() expect_start_element(qn("spreadsheetml", "styleSheet"), xml::content::complex); skip_attributes({qn("mc", "Ignorable")}); - read_namespaces(); std::vector> styles; std::vector> format_records; @@ -2499,7 +2516,6 @@ void xlsx_consumer::skip_remaining_content(const xml::qname &name) // start by assuming we've already parsed the opening tag skip_attributes(); - read_namespaces(); read_text(); // continue until the closing tag is reached @@ -2512,24 +2528,6 @@ void xlsx_consumer::skip_remaining_content(const xml::qname &name) } } -std::vector xlsx_consumer::read_namespaces() -{ - std::vector namespaces; - - while (parser().peek() == xml::parser::event_type::start_namespace_decl) - { - parser().next_expect(xml::parser::event_type::start_namespace_decl); - namespaces.push_back(parser().namespace_()); - - if (parser().peek() == xml::parser::event_type::end_namespace_decl) - { - parser().next_expect(xml::parser::event_type::end_namespace_decl); - } - } - - return namespaces; -} - bool xlsx_consumer::in_element(const xml::qname &name) { return parser().peek() != xml::parser::event_type::end_element @@ -2561,12 +2559,6 @@ void xlsx_consumer::expect_start_element(const xml::qname &name, xml::content co void xlsx_consumer::expect_end_element(const xml::qname &name) { parser().next_expect(xml::parser::event_type::end_element, name); - - while (parser().peek() == xml::parser::event_type::end_namespace_decl) - { - parser().next_expect(xml::parser::event_type::end_namespace_decl); - } - stack_.pop_back(); } diff --git a/source/detail/serialization/xlsx_consumer.hpp b/source/detail/serialization/xlsx_consumer.hpp index 76475e17..4729c941 100644 --- a/source/detail/serialization/xlsx_consumer.hpp +++ b/source/detail/serialization/xlsx_consumer.hpp @@ -357,12 +357,6 @@ private: /// bool in_element(const xml::qname &name); - /// - /// Handles all start and end namespace events from the current parser - /// and returns a vector of strings containing the URL for each namespace. - /// - std::vector read_namespaces(); - // Properties /// diff --git a/source/detail/serialization/xlsx_producer.cpp b/source/detail/serialization/xlsx_producer.cpp index 9904274b..e181960e 100644 --- a/source/detail/serialization/xlsx_producer.cpp +++ b/source/detail/serialization/xlsx_producer.cpp @@ -47,9 +47,9 @@ namespace { /// /// Returns true if d is exactly equal to an integer. /// -bool is_integral(long double d) +bool is_integral(double d) { - return std::fabs(d - static_cast(static_cast(d))) == 0.L; + return std::fabs(d - static_cast(static_cast(d))) == 0.0; } std::vector> core_property_namespace(xlnt::core_property type) @@ -2330,15 +2330,15 @@ void xlsx_producer::write_worksheet(const relationship &rel) case cell::type::number: write_start_element(xmlns, "v"); - if (is_integral(cell.value())) + if (is_integral(cell.value())) { - write_characters(static_cast(cell.value())); + write_characters(static_cast(cell.value())); } else { std::stringstream ss; ss.precision(20); - ss << cell.value(); + ss << cell.value(); write_characters(ss.str()); } diff --git a/source/detail/serialization/zstream.cpp b/source/detail/serialization/zstream.cpp index 737e0300..9888d316 100644 --- a/source/detail/serialization/zstream.cpp +++ b/source/detail/serialization/zstream.cpp @@ -194,14 +194,14 @@ public: in.fill(0); out.fill(0); - strm.zalloc = Z_NULL; - strm.zfree = Z_NULL; - strm.opaque = Z_NULL; + strm.zalloc = nullptr; + strm.zfree = nullptr; + strm.opaque = nullptr; strm.avail_in = 0; - strm.next_in = Z_NULL; + strm.next_in = nullptr; setg(in.data(), in.data(), in.data()); - setp(0, 0); + setp(nullptr, nullptr); // skip the header read_header(istream, false); @@ -329,9 +329,9 @@ public: zip_streambuf_compress(zheader *central_header, std::ostream &stream) : ostream(stream), header(central_header), valid(true) { - strm.zalloc = Z_NULL; - strm.zfree = Z_NULL; - strm.opaque = Z_NULL; + strm.zalloc = nullptr; + strm.zfree = nullptr; + strm.opaque = nullptr; #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wold-style-cast" @@ -345,7 +345,7 @@ public: return; } - setg(0, 0, 0); + setg(nullptr, nullptr, nullptr); setp(in.data(), in.data() + buffer_size - 4); // we want to be 4 aligned // Write appropriate header diff --git a/source/styles/color.cpp b/source/styles/color.cpp index a5c32c3d..f776c9df 100644 --- a/source/styles/color.cpp +++ b/source/styles/color.cpp @@ -32,7 +32,7 @@ namespace { std::array decode_hex_string(const std::string &hex_string) { - auto x = std::strtoul(hex_string.c_str(), NULL, 16); + auto x = std::strtoul(hex_string.c_str(), nullptr, 16); auto a = static_cast(x >> 24); auto r = static_cast((x >> 16) & 0xff); diff --git a/source/styles/number_format.cpp b/source/styles/number_format.cpp index df0bbcc3..270a6875 100644 --- a/source/styles/number_format.cpp +++ b/source/styles/number_format.cpp @@ -344,7 +344,7 @@ std::string number_format::format(const std::string &text) const return detail::number_formatter(format_string_, calendar::windows_1900).format_text(text); } -std::string number_format::format(long double number, calendar base_date) const +std::string number_format::format(double number, calendar base_date) const { return detail::number_formatter(format_string_, base_date).format_number(number); } diff --git a/source/utils/date.cpp b/source/utils/date.cpp index a21d343d..80dfccda 100644 --- a/source/utils/date.cpp +++ b/source/utils/date.cpp @@ -120,7 +120,7 @@ int date::to_number(calendar base_date) const date date::today() { - std::tm now = safe_localtime(std::time(0)); + std::tm now = safe_localtime(std::time(nullptr)); return date(1900 + now.tm_year, now.tm_mon + 1, now.tm_mday); } diff --git a/source/utils/datetime.cpp b/source/utils/datetime.cpp index 1f85487b..c4955f4f 100644 --- a/source/utils/datetime.cpp +++ b/source/utils/datetime.cpp @@ -43,7 +43,7 @@ std::string fill(const std::string &string, std::size_t length = 2) namespace xlnt { -datetime datetime::from_number(long double raw_time, calendar base_date) +datetime datetime::from_number(double raw_time, calendar base_date) { auto date_part = date::from_number(static_cast(raw_time), base_date); auto time_part = time::from_number(raw_time); @@ -54,13 +54,19 @@ datetime datetime::from_number(long double raw_time, calendar base_date) bool datetime::operator==(const datetime &comparand) const { - return year == comparand.year && month == comparand.month && day == comparand.day && hour == comparand.hour - && minute == comparand.minute && second == comparand.second && microsecond == comparand.microsecond; + return year == comparand.year + && month == comparand.month + && day == comparand.day + && hour == comparand.hour + && minute == comparand.minute + && second == comparand.second + && microsecond == comparand.microsecond; } -long double datetime::to_number(calendar base_date) const +double datetime::to_number(calendar base_date) const { - return date(year, month, day).to_number(base_date) + time(hour, minute, second, microsecond).to_number(); + return date(year, month, day).to_number(base_date) + + time(hour, minute, second, microsecond).to_number(); } std::string datetime::to_string() const diff --git a/source/utils/time.cpp b/source/utils/time.cpp index 810f404f..147e41f0 100644 --- a/source/utils/time.cpp +++ b/source/utils/time.cpp @@ -43,7 +43,7 @@ std::tm safe_localtime(std::time_t raw_time) namespace xlnt { -time time::from_number(long double raw_time) +time time::from_number(double raw_time) { time result; @@ -110,23 +110,23 @@ time::time(const std::string &time_string) } } -long double time::to_number() const +double time::to_number() const { std::uint64_t microseconds = static_cast(microsecond); microseconds += static_cast(second * 1e6); microseconds += static_cast(minute * 1e6 * 60); auto microseconds_per_hour = static_cast(1e6) * 60 * 60; microseconds += static_cast(hour) * microseconds_per_hour; - auto number = microseconds / (24.0L * microseconds_per_hour); + auto number = microseconds / (24.0 * microseconds_per_hour); auto hundred_billion = static_cast(1e9) * 100; - number = std::floor(number * hundred_billion + 0.5L) / hundred_billion; + number = std::floor(number * hundred_billion + 0.5) / hundred_billion; return number; } time time::now() { - std::tm now = safe_localtime(std::time(0)); + std::tm now = safe_localtime(std::time(nullptr)); return time(now.tm_hour, now.tm_min, now.tm_sec); } diff --git a/source/utils/timedelta.cpp b/source/utils/timedelta.cpp index 53e8ca27..88391a01 100644 --- a/source/utils/timedelta.cpp +++ b/source/utils/timedelta.cpp @@ -37,27 +37,27 @@ timedelta::timedelta(int days_, int hours_, int minutes_, int seconds_, int micr { } -long double timedelta::to_number() const +double timedelta::to_number() const { std::uint64_t total_microseconds = static_cast(microseconds); total_microseconds += static_cast(seconds * 1e6); total_microseconds += static_cast(minutes * 1e6 * 60); auto microseconds_per_hour = static_cast(1e6) * 60 * 60; total_microseconds += static_cast(hours) * microseconds_per_hour; - auto number = total_microseconds / (24.0L * microseconds_per_hour); + auto number = total_microseconds / (24.0 * microseconds_per_hour); auto hundred_billion = static_cast(1e9) * 100; - number = std::floor(number * hundred_billion + 0.5L) / hundred_billion; + number = std::floor(number * hundred_billion + 0.5) / hundred_billion; number += days; return number; } -timedelta timedelta::from_number(long double raw_time) +timedelta timedelta::from_number(double raw_time) { timedelta result; result.days = static_cast(raw_time); - long double fractional_part = raw_time - result.days; + double fractional_part = raw_time - result.days; fractional_part *= 24; result.hours = static_cast(fractional_part); @@ -68,7 +68,7 @@ timedelta timedelta::from_number(long double raw_time) fractional_part = 1000000 * (fractional_part - result.seconds); result.microseconds = static_cast(fractional_part); - if (result.microseconds == 999999 && fractional_part - result.microseconds > 0.5L) + if (result.microseconds == 999999 && fractional_part - result.microseconds > 0.5) { result.microseconds = 0; result.seconds += 1; diff --git a/source/worksheet/cell_vector.cpp b/source/worksheet/cell_vector.cpp index a6468661..6698d3ca 100644 --- a/source/worksheet/cell_vector.cpp +++ b/source/worksheet/cell_vector.cpp @@ -109,7 +109,7 @@ const cell cell_vector::back() const std::size_t cell_vector::length() const { - return order_ == major_order::row ? bounds_.width() + 1 : bounds_.height() + 1; + return order_ == major_order::row ? bounds_.width() : bounds_.height(); } cell_vector::const_iterator cell_vector::begin() const diff --git a/source/worksheet/range_reference.cpp b/source/worksheet/range_reference.cpp index 8137c708..8fe9eb99 100644 --- a/source/worksheet/range_reference.cpp +++ b/source/worksheet/range_reference.cpp @@ -90,17 +90,17 @@ range_reference range_reference::make_offset(int column_offset, int row_offset) std::size_t range_reference::height() const { - return bottom_right_.row() - top_left_.row(); + return 1 + bottom_right_.row() - top_left_.row(); } std::size_t range_reference::width() const { - return (bottom_right_.column() - top_left_.column()).index; + return 1 + (bottom_right_.column() - top_left_.column()).index; } bool range_reference::is_single_cell() const { - return width() == 0 && height() == 0; + return width() == 1 && height() == 1; } std::string range_reference::to_string() const diff --git a/source/worksheet/worksheet.cpp b/source/worksheet/worksheet.cpp index fae7f258..30e3cc0d 100644 --- a/source/worksheet/worksheet.cpp +++ b/source/worksheet/worksheet.cpp @@ -352,22 +352,20 @@ void worksheet::unfreeze_panes() cell worksheet::cell(const cell_reference &reference) { - if (d_->cell_map_.find(reference.row()) == d_->cell_map_.end()) - { - d_->cell_map_[reference.row()] = std::unordered_map(); - } - auto &row = d_->cell_map_[reference.row()]; + auto match = row.find(reference.column_index()); - if (row.find(reference.column_index()) == row.end()) + if (match == row.end()) { - auto &impl = row[reference.column_index()] = detail::cell_impl(); + match = row.emplace(reference.column_index(), detail::cell_impl()).first; + auto &impl = match->second; + impl.parent_ = d_; impl.column_ = reference.column_index(); impl.row_ = reference.row(); } - return xlnt::cell(&row[reference.column_index()]); + return xlnt::cell(&match->second); } const cell worksheet::cell(const cell_reference &reference) const @@ -673,7 +671,7 @@ bool worksheet::compare(const worksheet &other, bool reference) const } if (this_cell.data_type() == xlnt::cell::type::number - && std::fabs(this_cell.value() - other_cell.value()) > 0.L) + && std::fabs(this_cell.value() - other_cell.value()) > 0.0) { return false; } diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 2fc088c6..ffd025b7 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,11 +1,18 @@ -cmake_minimum_required(VERSION 3.2) +cmake_minimum_required(VERSION 3.1) project(xlnt.test) -set(CMAKE_CXX_STANDARD 14) +# Require C++11 compiler +set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD_REQUIRED ON) if(NOT COMBINED_PROJECT) - add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../source ${CMAKE_CURRENT_BINARY_DIR}/source) + add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../source ${CMAKE_CURRENT_BINARY_DIR}/source) +endif() + +if(MSVC AND STATIC) + # Link with static C runtime + include(${CMAKE_CURRENT_SOURCE_DIR}/../cmake/ucm.cmake) + ucm_set_runtime(STATIC) endif() file(GLOB CELL_TESTS ${CMAKE_CURRENT_SOURCE_DIR}/cell/*.hpp) @@ -16,12 +23,12 @@ file(GLOB WORKBOOK_TESTS ${CMAKE_CURRENT_SOURCE_DIR}/workbook/*.hpp) file(GLOB WORKSHEET_TESTS ${CMAKE_CURRENT_SOURCE_DIR}/worksheet/*.hpp) set(TESTS - ${CELL_TESTS} - ${PACKAGING_TESTS} - ${STYLES_TESTS} - ${UTILS_TESTS} - ${WORKBOOK_TESTS} - ${WORKSHEET_TESTS}) + ${CELL_TESTS} + ${PACKAGING_TESTS} + ${STYLES_TESTS} + ${UTILS_TESTS} + ${WORKBOOK_TESTS} + ${WORKSHEET_TESTS}) file(GLOB HELPERS_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/helpers/*.hpp) file(GLOB HELPERS_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/helpers/*.cpp) @@ -30,21 +37,22 @@ set(HELPERS ${HELPERS_HEADERS} ${HELPERS_SOURCES}) set(RUNNER ${CMAKE_CURRENT_SOURCE_DIR}/runner.cpp) if(COVERAGE) - set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fprofile-arcs -ftest-coverage") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fprofile-arcs -ftest-coverage") endif() add_executable(xlnt.test ${RUNNER} ${TESTS} ${HELPERS} $) target_link_libraries(xlnt.test PRIVATE xlnt) target_include_directories(xlnt.test - PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} - PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../source - PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../third-party/libstudxml) + PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} + PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../source + PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../third-party/libstudxml) set(XLNT_TEST_DATA_DIR ${CMAKE_CURRENT_SOURCE_DIR}/data) target_compile_definitions(xlnt.test PRIVATE XLNT_TEST_DATA_DIR=${XLNT_TEST_DATA_DIR}) if(MSVC) - set_target_properties(xlnt.test PROPERTIES COMPILE_FLAGS "/wd\"4068\" /bigobj") + # bigobj because there are so many headers in one source file + set_target_properties(xlnt.test PROPERTIES COMPILE_FLAGS "/wd\"4068\" /bigobj") endif() source_group(helpers FILES ${HELPERS}) @@ -58,8 +66,9 @@ source_group(tests\\workbook FILES ${WORKBOOK_TESTS}) source_group(tests\\worksheet FILES ${WORKSHEET_TESTS}) if(MSVC AND NOT STATIC) - add_custom_command(TARGET xlnt.test POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy_if_different - $ - $) + # copy xlnt DLL into xlnt.test directory + add_custom_command(TARGET xlnt.test POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different + $ + $) endif() diff --git a/tests/cell/cell_test_suite.hpp b/tests/cell/cell_test_suite.hpp index e7611ab5..0c72645f 100644 --- a/tests/cell/cell_test_suite.hpp +++ b/tests/cell/cell_test_suite.hpp @@ -76,7 +76,7 @@ private: auto cell = ws.cell("A1"); cell.value("4.2", true); - xlnt_assert_delta(cell.value(), 4.2L, 1E-9); + xlnt_assert_delta(cell.value(), 4.2, 1E-9); cell.value("-42.000", true); xlnt_assert(cell.value() == -42); @@ -85,10 +85,10 @@ private: xlnt_assert(cell.value() == 0); cell.value("0.9999", true); - xlnt_assert(cell.value() == 0.9999L); + xlnt_assert(cell.value() == 0.9999); cell.value("99E-02", true); - xlnt_assert(cell.value() == 0.99L); + xlnt_assert(cell.value() == 0.99); cell.value("4", true); xlnt_assert(cell.value() == 4); @@ -100,7 +100,7 @@ private: xlnt_assert(cell.value() == 200); cell.value("3.1%", true); - xlnt_assert_delta(cell.value(), 0.031L, 1E-9); + xlnt_assert_delta(cell.value(), 0.031, 1E-9); cell.value("03:40:16", true); xlnt_assert(cell.value() == xlnt::time(3, 40, 16)); @@ -256,7 +256,7 @@ private: cell.value(xlnt::datetime(2010, 7, 13, 6, 37, 41)); xlnt_assert(cell.data_type() == xlnt::cell::type::number); - xlnt_assert_delta(cell.value(), 40372.27616898148L, 1E-9); + xlnt_assert_delta(cell.value(), 40372.27616898148, 1E-9); xlnt_assert(cell.is_date()); xlnt_assert(cell.number_format().format_string() == "yyyy-mm-dd h:mm:ss"); } @@ -269,7 +269,7 @@ private: cell.value(xlnt::date(2010, 7, 13)); xlnt_assert(cell.data_type() == xlnt::cell::type::number); - xlnt_assert(cell.value() == 40372.L); + xlnt_assert(cell.value() == 40372.0); xlnt_assert(cell.is_date()); xlnt_assert(cell.number_format().format_string() == "yyyy-mm-dd"); } @@ -282,7 +282,7 @@ private: cell.value(xlnt::time(1, 3)); xlnt_assert(cell.data_type() == xlnt::cell::type::number); - xlnt_assert_delta(cell.value(), 0.04375L, 1E-9); + xlnt_assert_delta(cell.value(), 0.04375, 1E-9); xlnt_assert(cell.is_date()); xlnt_assert(cell.number_format().format_string() == "h:mm:ss"); } @@ -356,7 +356,7 @@ private: cell.value(xlnt::timedelta(1, 3, 0, 0, 0)); - xlnt_assert(cell.value() == 1.125); + xlnt_assert(cell.value() == 1.125); xlnt_assert(cell.data_type() == xlnt::cell::type::number); xlnt_assert(!cell.is_date()); xlnt_assert(cell.number_format().format_string() == "[hh]:mm:ss"); @@ -612,11 +612,8 @@ private: cell.value(static_cast(3.14)); xlnt_assert_delta(cell.value(), 3.14, 0.001); - cell.value(static_cast(4.1415)); - xlnt_assert_equals(cell.value(), 4.1415); - - cell.value(static_cast(3.141592)); - xlnt_assert_equals(cell.value(), 3.141592); + cell.value(static_cast(3.141592)); + xlnt_assert_equals(cell.value(), 3.141592); auto cell2 = ws.cell("A2"); cell2.value(std::string(100000, 'a')); diff --git a/tests/styles/number_format_test_suite.hpp b/tests/styles/number_format_test_suite.hpp index 3d5a37cc..ca378ddb 100644 --- a/tests/styles/number_format_test_suite.hpp +++ b/tests/styles/number_format_test_suite.hpp @@ -769,9 +769,9 @@ public: void format_and_test(const xlnt::number_format &nf, const std::array &expect) { - long double positive = 42503.1234; - long double negative = -1 * positive; - long double zero = 0; + double positive = 42503.1234; + double negative = -1 * positive; + double zero = 0; const std::string text = "text"; xlnt::calendar calendar = xlnt::calendar::windows_1900; diff --git a/tests/utils/timedelta_test_suite.hpp b/tests/utils/timedelta_test_suite.hpp index de77af7f..4828b0eb 100644 --- a/tests/utils/timedelta_test_suite.hpp +++ b/tests/utils/timedelta_test_suite.hpp @@ -51,7 +51,7 @@ public: void test_round_trip() { - long double time = 3.14159265359L; + double time = 3.14159265359; auto td = xlnt::timedelta::from_number(time); auto time_rt = td.to_number(); xlnt_assert_delta(time, time_rt, 1E-9); @@ -59,8 +59,8 @@ public: void test_to_number() { - xlnt::timedelta td(1, 1, 1, 1, 1); - xlnt_assert_delta(td.to_number(), 1.0423726852L, 1E-9); + xlnt::timedelta td(1, 1, 1, 1, 1); + xlnt_assert_delta(td.to_number(), 1.0423726852L, 1E-9); } void test_carry() diff --git a/tests/workbook/serialization_test_suite.hpp b/tests/workbook/serialization_test_suite.hpp index abd6a642..88c4f9cb 100644 --- a/tests/workbook/serialization_test_suite.hpp +++ b/tests/workbook/serialization_test_suite.hpp @@ -120,9 +120,6 @@ public: ws.cell("A14").value("number (double)"); ws.cell("B14").value(std::numeric_limits::max()); - ws.cell("A15").value("number (long double)"); - ws.cell("B15").value(std::numeric_limits::max()); - ws.cell("A16").value("text (char *)"); ws.cell("B16").value("string"); @@ -479,11 +476,10 @@ public: while (reader.has_cell()) { - const auto cell = reader.read_cell(); - std::cout << cell.reference().to_string() << " " << cell.to_string() << std::endl; + reader.read_cell(); } - const auto ws = reader.end_worksheet(); + reader.end_worksheet(); } } diff --git a/tests/worksheet/worksheet_test_suite.hpp b/tests/worksheet/worksheet_test_suite.hpp index 9998ba3d..e915d357 100644 --- a/tests/worksheet/worksheet_test_suite.hpp +++ b/tests/worksheet/worksheet_test_suite.hpp @@ -93,6 +93,7 @@ public: register_test(test_get_point_pos); register_test(test_named_range_named_cell_reference); register_test(test_iteration_skip_empty); + register_test(test_dimensions); } void test_new_worksheet() @@ -1088,4 +1089,17 @@ public: xlnt_assert_equals(cells[1].value(), "F6"); } } + + void test_dimensions() + { + xlnt::workbook workbook; + workbook.load(path_helper::test_file("4_every_style.xlsx")); + + auto active_sheet = workbook.active_sheet(); + auto sheet_range = active_sheet.calculate_dimension(); + + xlnt_assert(!sheet_range.is_single_cell()); + xlnt_assert_equals(sheet_range.width(), 4); + xlnt_assert_equals(sheet_range.height(), 35); + } }; diff --git a/third-party/libstudxml/CMakeLists.txt b/third-party/libstudxml/CMakeLists.txt index 2cdf1f58..ab6d3a6a 100644 --- a/third-party/libstudxml/CMakeLists.txt +++ b/third-party/libstudxml/CMakeLists.txt @@ -1,73 +1,79 @@ -cmake_minimum_required(VERSION 3.2) +cmake_minimum_required(VERSION 3.1) project(libstudxml) -set(CMAKE_CXX_STANDARD 14) +# Require C++11 compiler +set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(LIBSTUDXML_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}) set(LIBSTUDXML_INCLUDE_DIR ${LIBSTUDXML_ROOT_DIR}) +if(STATIC) + include(${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/ucm.cmake) + ucm_set_runtime(STATIC) +endif() + set(LIBSTUDXML - ${LIBSTUDXML_ROOT_DIR}/xml/parser.cxx - ${LIBSTUDXML_ROOT_DIR}/xml/qname.cxx - ${LIBSTUDXML_ROOT_DIR}/xml/serializer.cxx - ${LIBSTUDXML_ROOT_DIR}/xml/value-traits.cxx - ${LIBSTUDXML_ROOT_DIR}/xml/content - ${LIBSTUDXML_ROOT_DIR}/xml/exception - ${LIBSTUDXML_ROOT_DIR}/xml/forward - ${LIBSTUDXML_ROOT_DIR}/xml/parser - ${LIBSTUDXML_ROOT_DIR}/xml/qname - ${LIBSTUDXML_ROOT_DIR}/xml/serializer - ${LIBSTUDXML_ROOT_DIR}/xml/value-traits) + ${LIBSTUDXML_ROOT_DIR}/xml/parser.cxx + ${LIBSTUDXML_ROOT_DIR}/xml/qname.cxx + ${LIBSTUDXML_ROOT_DIR}/xml/serializer.cxx + ${LIBSTUDXML_ROOT_DIR}/xml/value-traits.cxx + ${LIBSTUDXML_ROOT_DIR}/xml/content + ${LIBSTUDXML_ROOT_DIR}/xml/exception + ${LIBSTUDXML_ROOT_DIR}/xml/forward + ${LIBSTUDXML_ROOT_DIR}/xml/parser + ${LIBSTUDXML_ROOT_DIR}/xml/qname + ${LIBSTUDXML_ROOT_DIR}/xml/serializer + ${LIBSTUDXML_ROOT_DIR}/xml/value-traits) set(GENX - ${LIBSTUDXML_ROOT_DIR}/xml/details/genx/char-props.c - ${LIBSTUDXML_ROOT_DIR}/xml/details/genx/genx.c - ${LIBSTUDXML_ROOT_DIR}/xml/details/genx/genx.h) + ${LIBSTUDXML_ROOT_DIR}/xml/details/genx/char-props.c + ${LIBSTUDXML_ROOT_DIR}/xml/details/genx/genx.c + ${LIBSTUDXML_ROOT_DIR}/xml/details/genx/genx.h) set(EXPAT - ${LIBSTUDXML_ROOT_DIR}/xml/details/expat/xmlparse.c - ${LIBSTUDXML_ROOT_DIR}/xml/details/expat/xmlrole.c - ${LIBSTUDXML_ROOT_DIR}/xml/details/expat/xmltok.c - ${LIBSTUDXML_ROOT_DIR}/xml/details/expat/ascii.h - ${LIBSTUDXML_ROOT_DIR}/xml/details/expat/asciitab.h - ${LIBSTUDXML_ROOT_DIR}/xml/details/expat/config.h - ${LIBSTUDXML_ROOT_DIR}/xml/details/expat/expat_external.h - ${LIBSTUDXML_ROOT_DIR}/xml/details/expat/expat.h - ${LIBSTUDXML_ROOT_DIR}/xml/details/expat/iasciitab.h - ${LIBSTUDXML_ROOT_DIR}/xml/details/expat/internal.h - ${LIBSTUDXML_ROOT_DIR}/xml/details/expat/latin1tab.h - ${LIBSTUDXML_ROOT_DIR}/xml/details/expat/nametab.h - ${LIBSTUDXML_ROOT_DIR}/xml/details/expat/utf8tab.h - ${LIBSTUDXML_ROOT_DIR}/xml/details/expat/xmlrole.h - ${LIBSTUDXML_ROOT_DIR}/xml/details/expat/xmltok_impl.h - ${LIBSTUDXML_ROOT_DIR}/xml/details/expat/xmltok.h) + ${LIBSTUDXML_ROOT_DIR}/xml/details/expat/xmlparse.c + ${LIBSTUDXML_ROOT_DIR}/xml/details/expat/xmlrole.c + ${LIBSTUDXML_ROOT_DIR}/xml/details/expat/xmltok.c + ${LIBSTUDXML_ROOT_DIR}/xml/details/expat/ascii.h + ${LIBSTUDXML_ROOT_DIR}/xml/details/expat/asciitab.h + ${LIBSTUDXML_ROOT_DIR}/xml/details/expat/config.h + ${LIBSTUDXML_ROOT_DIR}/xml/details/expat/expat_external.h + ${LIBSTUDXML_ROOT_DIR}/xml/details/expat/expat.h + ${LIBSTUDXML_ROOT_DIR}/xml/details/expat/iasciitab.h + ${LIBSTUDXML_ROOT_DIR}/xml/details/expat/internal.h + ${LIBSTUDXML_ROOT_DIR}/xml/details/expat/latin1tab.h + ${LIBSTUDXML_ROOT_DIR}/xml/details/expat/nametab.h + ${LIBSTUDXML_ROOT_DIR}/xml/details/expat/utf8tab.h + ${LIBSTUDXML_ROOT_DIR}/xml/details/expat/xmlrole.h + ${LIBSTUDXML_ROOT_DIR}/xml/details/expat/xmltok_impl.h + ${LIBSTUDXML_ROOT_DIR}/xml/details/expat/xmltok.h) add_library(libstudxml OBJECT ${LIBSTUDXML} ${GENX} ${EXPAT}) target_compile_definitions(libstudxml PUBLIC LIBSTUDXML_STATIC_LIB=1) target_include_directories(libstudxml - PUBLIC ${LIBSTUDXML_ROOT_DIR} - PUBLIC ${EXPAT_INCLUDE_DIRS}) + PUBLIC ${LIBSTUDXML_ROOT_DIR} + PUBLIC ${EXPAT_INCLUDE_DIRS}) if(STATIC) - target_compile_definitions(libstudxml PUBLIC XML_STATIC=1) + target_compile_definitions(libstudxml PUBLIC XML_STATIC=1) endif() # Prevent warning C4996 caused by strcpy, strncpy, sprintf in genx # TODO: would it be better to define this only in genx.c? if(MSVC) - target_compile_definitions(libstudxml PRIVATE _CRT_SECURE_NO_WARNINGS=1) + target_compile_definitions(libstudxml PRIVATE _CRT_SECURE_NO_WARNINGS=1) endif() # Build with -fPIC when xlnt is a shared library # TODO: is this still necessary? try removing if(NOT STATIC) - set_target_properties(libstudxml PROPERTIES POSITION_INDEPENDENT_CODE 1) + set_target_properties(libstudxml PROPERTIES POSITION_INDEPENDENT_CODE 1) endif() # When xlnt is a static library, assume expat will be linked statically too # TODO: is this a valid assumption? if(STATIC) - target_compile_definitions(libstudxml PUBLIC XML_STATIC=1) + target_compile_definitions(libstudxml PUBLIC XML_STATIC=1) endif() diff --git a/third-party/libstudxml/xml/parser b/third-party/libstudxml/xml/parser index 32c49bc6..6d508f12 100644 --- a/third-party/libstudxml/xml/parser +++ b/third-party/libstudxml/xml/parser @@ -325,7 +325,7 @@ namespace xml { typedef event_type value_type; - iterator (parser* p = 0, event_type e = eof): p_ (p), e_ (e) {} + iterator (parser* p = nullptr, event_type e = eof): p_ (p), e_ (e) {} value_type operator* () const {return e_;} iterator& operator++ () {e_ = p_->next (); return *this;} diff --git a/third-party/libstudxml/xml/parser.ixx b/third-party/libstudxml/xml/parser.ixx index 093f90f2..a62fbbcb 100644 --- a/third-party/libstudxml/xml/parser.ixx +++ b/third-party/libstudxml/xml/parser.ixx @@ -47,7 +47,7 @@ namespace xml feature_type f) : size_ (size), iname_ (iname), feature_ (f) { - assert (data != 0 && size != 0); + assert (data != nullptr && size != 0); data_.buf = data; init (); @@ -76,7 +76,7 @@ namespace xml inline const parser::element_entry* parser:: get_element () const { - return element_state_.empty () ? 0 : get_element_ (); + return element_state_.empty () ? nullptr : get_element_ (); } inline const std::string& parser::