初始化内容
This commit is contained in:
Vendored
+322
@@ -0,0 +1,322 @@
|
||||
#=======================================================================================================================
|
||||
# Preamble
|
||||
#=======================================================================================================================
|
||||
cmake_minimum_required(VERSION 3.15 FATAL_ERROR)
|
||||
set(OPENXLSX_MAJOR_VERSION 0)
|
||||
set(OPENXLSX_MINOR_VERSION 3)
|
||||
set(OPENXLSX_MICRO_VERSION 1)
|
||||
project(OpenXLSX.Library VERSION 0.3.2 LANGUAGES CXX)
|
||||
set(CMAKE_DEBUG_POSTFIX d)
|
||||
set(CMAKE_CXX_VISIBILITY_PRESET hidden)
|
||||
set(CMAKE_VISIBILITY_INLINES_HIDDEN YES)
|
||||
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
||||
|
||||
#=======================================================================================================================
|
||||
# Set project metadata
|
||||
#=======================================================================================================================
|
||||
set(OPENXLSX_PROJECT_VENDOR "Kenneth Troldal Balslev")
|
||||
set(OPENXLSX_PROJECT_CONTACT "kenneth.balslev@gmail.com")
|
||||
set(OPENXLSX_PROJECT_URL "https://github.com/troldal/OpenXLSX")
|
||||
set(PROJECT_DESCRIPTION "A C++17 library for reading, writing and modifying Excel spreadsheets")
|
||||
|
||||
#=======================================================================================================================
|
||||
# Set C/C++ compiler version
|
||||
#=======================================================================================================================
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
set(CMAKE_CXX_EXTENSIONS OFF)
|
||||
set(IGNORE_ME ${CMAKE_C_COMPILER}) # Suppress CMake warning message
|
||||
|
||||
#=======================================================================================================================
|
||||
# Add build options
|
||||
#=======================================================================================================================
|
||||
option(OPENXLSX_COMPACT_MODE "Build library in compact mode (slower, but uses less memory)" OFF)
|
||||
set(OPENXLSX_LIBRARY_TYPE "STATIC" CACHE STRING "Set the library type to SHARED or STATIC")
|
||||
|
||||
#=======================================================================================================================
|
||||
# EXTERNAL LIBRARIES
|
||||
# Define external libraries used by OpenXLSX. The libraries (Zippy, PugiXML, and NoWide) are header-only, so
|
||||
# INTERFACE libraries should be defined.
|
||||
#=======================================================================================================================
|
||||
add_library(NoWide INTERFACE IMPORTED)
|
||||
target_include_directories(NoWide SYSTEM INTERFACE $<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/external/nowide/>)
|
||||
|
||||
add_library(Zippy INTERFACE IMPORTED)
|
||||
target_include_directories(Zippy SYSTEM INTERFACE $<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/external/zippy/>)
|
||||
|
||||
add_library(PugiXML INTERFACE IMPORTED)
|
||||
target_include_directories(PugiXML SYSTEM INTERFACE $<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/external/pugixml/>)
|
||||
|
||||
if (${OPENXLSX_COMPACT_MODE})
|
||||
target_compile_definitions(PugiXML INTERFACE PUGIXML_COMPACT)
|
||||
endif ()
|
||||
|
||||
#=======================================================================================================================
|
||||
# COMPILER FEATURES
|
||||
# Some older C++17 compilers don't support the char_conv features. If the compiler doesn't support it,
|
||||
# a less optimal work-around will be used.
|
||||
#=======================================================================================================================
|
||||
include(CheckCXXSourceCompiles)
|
||||
check_cxx_source_compiles("
|
||||
#include <array>
|
||||
#include <string>
|
||||
#include <charconv>
|
||||
|
||||
int main() {
|
||||
std::array<char, 7> str {};
|
||||
auto p = std::to_chars(str.data(), str.data() + str.size(), 12345).ptr;
|
||||
auto strResult = std::string(str.data(), p - str.data());
|
||||
|
||||
unsigned long value = 0;
|
||||
std::from_chars(strResult.data(), strResult.data() + strResult.size(), value);
|
||||
|
||||
return 0;
|
||||
}" CHARCONV_RESULT)
|
||||
|
||||
if (CHARCONV_RESULT)
|
||||
add_compile_definitions(CHARCONV_ENABLED)
|
||||
endif ()
|
||||
|
||||
#=======================================================================================================================
|
||||
# PROJECT FILES
|
||||
# List of project source files
|
||||
#=======================================================================================================================
|
||||
set(OPENXLSX_SOURCES
|
||||
${CMAKE_CURRENT_LIST_DIR}/sources/XLCell.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/sources/XLCellIterator.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/sources/XLCellRange.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/sources/XLCellReference.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/sources/XLCellValue.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/sources/XLColor.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/sources/XLColumn.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/sources/XLContentTypes.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/sources/XLDateTime.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/sources/XLDocument.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/sources/XLFormula.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/sources/XLProperties.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/sources/XLRelationships.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/sources/XLRow.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/sources/XLRowData.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/sources/XLSharedStrings.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/sources/XLSheet.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/sources/XLWorkbook.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/sources/XLXmlData.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/sources/XLXmlFile.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/sources/XLZipArchive.cpp
|
||||
)
|
||||
|
||||
|
||||
#=======================================================================================================================
|
||||
# STATIC AND SHARED LIBRARY
|
||||
# Check that the input is valid
|
||||
#=======================================================================================================================
|
||||
if(NOT ${OPENXLSX_LIBRARY_TYPE} STREQUAL "STATIC" AND NOT ${OPENXLSX_LIBRARY_TYPE} STREQUAL "SHARED")
|
||||
message( FATAL_ERROR "Invalid library type. Must be SHARED or STATIC." )
|
||||
endif()
|
||||
|
||||
#=======================================================================================================================
|
||||
# STATIC LIBRARY
|
||||
# Define the static library
|
||||
#=======================================================================================================================
|
||||
if (${OPENXLSX_LIBRARY_TYPE} STREQUAL "STATIC")
|
||||
add_library(OpenXLSX STATIC "")
|
||||
add_library(OpenXLSX::OpenXLSX ALIAS OpenXLSX)
|
||||
target_sources(OpenXLSX PRIVATE ${OPENXLSX_SOURCES})
|
||||
target_include_directories(OpenXLSX
|
||||
PUBLIC
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}>
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/headers>
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>) # For export header
|
||||
target_link_libraries(OpenXLSX
|
||||
PRIVATE
|
||||
$<BUILD_INTERFACE:Zippy>
|
||||
$<BUILD_INTERFACE:PugiXML>
|
||||
$<BUILD_INTERFACE:NoWide>)
|
||||
|
||||
target_compile_definitions(OpenXLSX PUBLIC OPENXLSX_STATIC_DEFINE)
|
||||
|
||||
endif ()
|
||||
|
||||
#=======================================================================================================================
|
||||
# SHARED LIBRARY
|
||||
# Define the shared library
|
||||
#=======================================================================================================================
|
||||
if (${OPENXLSX_LIBRARY_TYPE} STREQUAL "SHARED")
|
||||
add_library(OpenXLSX SHARED "")
|
||||
add_library(OpenXLSX::OpenXLSX ALIAS OpenXLSX)
|
||||
target_sources(OpenXLSX PRIVATE ${OPENXLSX_SOURCES})
|
||||
target_include_directories(OpenXLSX
|
||||
PUBLIC
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}>
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/headers>
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>) # For export header
|
||||
target_link_libraries(OpenXLSX
|
||||
PRIVATE
|
||||
$<BUILD_INTERFACE:Zippy>
|
||||
$<BUILD_INTERFACE:PugiXML>
|
||||
$<BUILD_INTERFACE:NoWide>)
|
||||
|
||||
# Enable Link-Time Optimization (LTO)
|
||||
include(CheckIPOSupported)
|
||||
check_ipo_supported(RESULT result OUTPUT output)
|
||||
if (result)
|
||||
set_property(TARGET OpenXLSX PROPERTY INTERPROCEDURAL_OPTIMIZATION TRUE)
|
||||
endif ()
|
||||
|
||||
endif()
|
||||
|
||||
# Generate export header
|
||||
include(GenerateExportHeader)
|
||||
generate_export_header(OpenXLSX
|
||||
BASE_NAME openxlsx
|
||||
EXPORT_FILE_NAME OpenXLSX-Exports.hpp
|
||||
EXPORT_MACRO_NAME OPENXLSX_EXPORT
|
||||
NO_EXPORT_MACRO_NAME OPENXLSX_HIDDEN)
|
||||
|
||||
#=======================================================================================================================
|
||||
# COMPILER FLAGS
|
||||
# Set compiler debug flags for GCC, Clang and MSVC.
|
||||
#=======================================================================================================================
|
||||
list(APPEND OPENXLSX_DEBUG_FLAGS_GNU
|
||||
"-Wmisleading-indentation"
|
||||
"-Wduplicated-cond"
|
||||
"-Wduplicated-branches"
|
||||
"-Wlogical-op"
|
||||
"-Wnull-dereference")
|
||||
list(APPEND OPENXLSX_DEBUG_FLAGS_GNUCLANG
|
||||
"-Wall"
|
||||
"-Wextra"
|
||||
"-Wshadow"
|
||||
"-Wnon-virtual-dtor"
|
||||
"-Wold-style-cast"
|
||||
"-Wcast-align"
|
||||
"-Wunused"
|
||||
"-Woverloaded-virtual"
|
||||
"-Wpedantic"
|
||||
"-Wconversion"
|
||||
"-Wdouble-promotion"
|
||||
"-Wformat=2"
|
||||
"-Weffc++"
|
||||
"-Wno-unknown-pragmas")
|
||||
list(APPEND OPENXLSX_DEBUG_FLAGS_MSVC
|
||||
"/permissive"
|
||||
"/W4"
|
||||
"/w14242"
|
||||
"/w14254"
|
||||
"/w14263"
|
||||
"/w14265"
|
||||
"/w14287"
|
||||
"/we4289"
|
||||
"/w14296"
|
||||
"/w14311"
|
||||
"/w14545"
|
||||
"/w14546"
|
||||
"/w14547"
|
||||
"/w14549"
|
||||
"/w14555"
|
||||
"/w14619"
|
||||
"/w14640"
|
||||
"/w14826"
|
||||
"/w14905"
|
||||
"/w14906"
|
||||
"/w14928"
|
||||
"/wd4251"
|
||||
"/wd4275")
|
||||
list(APPEND OPENXLSX_RELEASE_FLAGS_MSVC
|
||||
"/wd4251"
|
||||
"/wd4275")
|
||||
|
||||
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
|
||||
target_compile_options(OpenXLSX PRIVATE $<$<CONFIG:Debug>:${OPENXLSX_DEBUG_FLAGS_GNU}>)
|
||||
|
||||
elseif (("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") OR
|
||||
("${CMAKE_CXX_COMPILER_ID}" STREQUAL "AppleClang") OR
|
||||
("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU"))
|
||||
target_compile_options(OpenXLSX PRIVATE $<$<CONFIG:Debug>:${OPENXLSX_DEBUG_FLAGS_GNUCLANG}>)
|
||||
|
||||
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
|
||||
string(REGEX REPLACE "/W[3|4]" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
|
||||
target_compile_options(OpenXLSX PRIVATE $<$<CONFIG:Debug>:${OPENXLSX_DEBUG_FLAGS_MSVC}>)
|
||||
target_compile_options(OpenXLSX PRIVATE $<$<CONFIG:Release>:${OPENXLSX_RELEASE_FLAGS_MSVC}>)
|
||||
endif ()
|
||||
|
||||
#=======================================================================================================================
|
||||
# Install
|
||||
#=======================================================================================================================
|
||||
# Some basic stuff we'll need in this section
|
||||
include(GNUInstallDirs)
|
||||
include(CMakePackageConfigHelpers)
|
||||
set(ConfigPackageLocation ${CMAKE_INSTALL_LIBDIR}/cmake/OpenXLSX)
|
||||
|
||||
# Install interface headers
|
||||
install(
|
||||
FILES ${OPENXLSX_CXX_INTERFACE_HEADERS}
|
||||
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/OpenXLSX/${dir}
|
||||
)
|
||||
|
||||
# Install export header
|
||||
install(
|
||||
FILES ${CMAKE_CURRENT_BINARY_DIR}/OpenXLSX-Exports.hpp
|
||||
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/OpenXLSX/headers
|
||||
)
|
||||
|
||||
file(GLOB OPENXLSX_HEADER_LIST ${CMAKE_CURRENT_LIST_DIR}/headers/*.hpp)
|
||||
install(
|
||||
FILES ${OPENXLSX_HEADER_LIST}
|
||||
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/OpenXLSX/headers
|
||||
)
|
||||
|
||||
install(
|
||||
FILES ${CMAKE_CURRENT_LIST_DIR}/OpenXLSX.hpp
|
||||
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/OpenXLSX
|
||||
)
|
||||
|
||||
# Targets
|
||||
install(
|
||||
TARGETS OpenXLSX
|
||||
EXPORT OpenXLSXTargets
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
COMPONENT lib
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
COMPONENT lib
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
COMPONENT bin
|
||||
INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/OpenXLSX
|
||||
)
|
||||
|
||||
set_target_properties(OpenXLSX PROPERTIES FOLDER libs VERSION ${OPENXLSX_MAJOR_VERSION}.${OPENXLSX_MINOR_VERSION}.${OPENXLSX_MICRO_VERSION} SOVERSION ${OPENXLSX_MAJOR_VERSION})
|
||||
|
||||
# Package version
|
||||
write_basic_package_version_file(
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/OpenXLSX/OpenXLSXConfigVersion.cmake"
|
||||
VERSION ${OpenXLSX_VERSION}
|
||||
COMPATIBILITY AnyNewerVersion
|
||||
)
|
||||
install(
|
||||
FILES
|
||||
OpenXLSXConfig.cmake
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/OpenXLSX/OpenXLSXConfigVersion.cmake"
|
||||
DESTINATION ${ConfigPackageLocation}
|
||||
)
|
||||
|
||||
# Package configuration
|
||||
configure_file(OpenXLSXConfig.cmake
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/OpenXLSX/OpenXLSXConfig.cmake"
|
||||
COPYONLY
|
||||
)
|
||||
|
||||
# Package export targets
|
||||
export(
|
||||
EXPORT OpenXLSXTargets
|
||||
FILE "${CMAKE_CURRENT_BINARY_DIR}/OpenXLSX/OpenXLSXTargets.cmake"
|
||||
NAMESPACE OpenXLSX::
|
||||
)
|
||||
install(
|
||||
EXPORT OpenXLSXTargets
|
||||
FILE OpenXLSXTargets.cmake
|
||||
NAMESPACE OpenXLSX::
|
||||
DESTINATION ${ConfigPackageLocation}
|
||||
)
|
||||
|
||||
|
||||
|
||||
Vendored
+63
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
|
||||
____ ____ ___ ____ ____ ____ ___
|
||||
6MMMMb `MM( )M' `MM' 6MMMMb\`MM( )M'
|
||||
8P Y8 `MM. d' MM 6M' ` `MM. d'
|
||||
6M Mb __ ____ ____ ___ __ `MM. d' MM MM `MM. d'
|
||||
MM MM `M6MMMMb 6MMMMb `MM 6MMb `MM. d' MM YM. `MM. d'
|
||||
MM MM MM' `Mb 6M' `Mb MMM9 `Mb `MMd MM YMMMMb `MMd
|
||||
MM MM MM MM MM MM MM' MM dMM. MM `Mb dMM.
|
||||
MM MM MM MM MMMMMMMM MM MM d'`MM. MM MM d'`MM.
|
||||
YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM.
|
||||
8b d8 MM. ,M9 YM d9 MM MM d' `MM. MM / L ,M9 d' `MM.
|
||||
YMMMM9 MMYMMM9 YMMMM9 _MM_ _MM_M(_ _)MM_ _MMMMMMM MYMMMM9 _M(_ _)MM_
|
||||
MM
|
||||
MM
|
||||
_MM_
|
||||
|
||||
Copyright (c) 2018, Kenneth Troldal Balslev
|
||||
|
||||
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.
|
||||
- Neither the name of the author nor the
|
||||
names of any 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 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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef OPENXLSX_OPENXLSX_HPP
|
||||
#define OPENXLSX_OPENXLSX_HPP
|
||||
|
||||
#include "headers/XLCell.hpp"
|
||||
#include "headers/XLCellRange.hpp"
|
||||
#include "headers/XLCellReference.hpp"
|
||||
#include "headers/XLCellValue.hpp"
|
||||
#include "headers/XLColumn.hpp"
|
||||
#include "headers/XLDateTime.hpp"
|
||||
#include "headers/XLDocument.hpp"
|
||||
#include "headers/XLException.hpp"
|
||||
#include "headers/XLFormula.hpp"
|
||||
#include "headers/XLRow.hpp"
|
||||
#include "headers/XLSheet.hpp"
|
||||
#include "headers/XLWorkbook.hpp"
|
||||
#include "headers/XLZipArchive.hpp"
|
||||
|
||||
#endif // OPENXLSX_OPENXLSX_HPP
|
||||
Vendored
+1
@@ -0,0 +1 @@
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/OpenXLSXTargets.cmake")
|
||||
+162
@@ -0,0 +1,162 @@
|
||||
//
|
||||
// Copyright (c) 2012 Artyom Beilis (Tonkikh)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
#ifndef NOWIDE_ARGS_HPP_INCLUDED
|
||||
# define NOWIDE_ARGS_HPP_INCLUDED
|
||||
|
||||
# include <nowide/config.hpp>
|
||||
# include <nowide/stackstring.hpp>
|
||||
# include <vector>
|
||||
# ifdef NOWIDE_WINDOWS
|
||||
# include <nowide/windows.hpp>
|
||||
# endif
|
||||
|
||||
namespace nowide
|
||||
{
|
||||
# if !defined(NOWIDE_WINDOWS) && !defined(NOWIDE_DOXYGEN)
|
||||
class args
|
||||
{
|
||||
public:
|
||||
args(int&, char**&) {}
|
||||
args(int&, char**&, char**&) {}
|
||||
~args() {}
|
||||
};
|
||||
|
||||
# else
|
||||
|
||||
///
|
||||
/// \brief args is a class that fixes standard main() function arguments and changes them to UTF-8 under
|
||||
/// Microsoft Windows.
|
||||
///
|
||||
/// The class uses \c GetCommandLineW(), \c CommandLineToArgvW() and \c GetEnvironmentStringsW()
|
||||
/// in order to obtain the information. It does not relates to actual values of argc,argv and env
|
||||
/// under Windows.
|
||||
///
|
||||
/// It restores the original values in its destructor
|
||||
///
|
||||
/// \note the class owns the memory of the newly allocated strings
|
||||
///
|
||||
class args
|
||||
{
|
||||
public:
|
||||
///
|
||||
/// Fix command line agruments
|
||||
///
|
||||
args(int& argc, char**& argv)
|
||||
: old_argc_(argc),
|
||||
old_argv_(argv),
|
||||
old_env_(0),
|
||||
old_argc_ptr_(&argc),
|
||||
old_argv_ptr_(&argv),
|
||||
old_env_ptr_(0)
|
||||
{
|
||||
fix_args(argc, argv);
|
||||
}
|
||||
///
|
||||
/// Fix command line agruments and environment
|
||||
///
|
||||
args(int& argc, char**& argv, char**& en)
|
||||
: old_argc_(argc),
|
||||
old_argv_(argv),
|
||||
old_env_(en),
|
||||
old_argc_ptr_(&argc),
|
||||
old_argv_ptr_(&argv),
|
||||
old_env_ptr_(&en)
|
||||
{
|
||||
fix_args(argc, argv);
|
||||
fix_env(en);
|
||||
}
|
||||
///
|
||||
/// Restore original argc,argv,env values, if changed
|
||||
///
|
||||
~args()
|
||||
{
|
||||
if (old_argc_ptr_) *old_argc_ptr_ = old_argc_;
|
||||
if (old_argv_ptr_) *old_argv_ptr_ = old_argv_;
|
||||
if (old_env_ptr_) *old_env_ptr_ = old_env_;
|
||||
}
|
||||
|
||||
private:
|
||||
void fix_args(int& argc, char**& argv)
|
||||
{
|
||||
int wargc;
|
||||
wchar_t** wargv = CommandLineToArgvW(GetCommandLineW(), &wargc);
|
||||
if (!wargv) {
|
||||
argc = 0;
|
||||
static char* dummy = 0;
|
||||
argv = &dummy;
|
||||
return;
|
||||
}
|
||||
try {
|
||||
args_.resize(wargc + 1, 0);
|
||||
arg_values_.resize(wargc);
|
||||
for (int i = 0; i < wargc; i++) {
|
||||
if (!arg_values_[i].convert(wargv[i])) {
|
||||
wargc = i;
|
||||
break;
|
||||
}
|
||||
args_[i] = arg_values_[i].c_str();
|
||||
}
|
||||
argc = wargc;
|
||||
argv = &args_[0];
|
||||
}
|
||||
catch (...) {
|
||||
LocalFree(wargv);
|
||||
throw;
|
||||
}
|
||||
LocalFree(wargv);
|
||||
}
|
||||
void fix_env(char**& en)
|
||||
{
|
||||
static char* dummy = 0;
|
||||
en = &dummy;
|
||||
wchar_t* wstrings = GetEnvironmentStringsW();
|
||||
if (!wstrings) return;
|
||||
try {
|
||||
wchar_t* wstrings_end = 0;
|
||||
int count = 0;
|
||||
for (wstrings_end = wstrings; *wstrings_end; wstrings_end += wcslen(wstrings_end) + 1) count++;
|
||||
if (env_.convert(wstrings, wstrings_end)) {
|
||||
envp_.resize(count + 1, 0);
|
||||
char* p = env_.c_str();
|
||||
int pos = 0;
|
||||
for (int i = 0; i < count; i++) {
|
||||
if (*p != '=') envp_[pos++] = p;
|
||||
p += strlen(p) + 1;
|
||||
}
|
||||
en = &envp_[0];
|
||||
}
|
||||
}
|
||||
catch (...) {
|
||||
FreeEnvironmentStringsW(wstrings);
|
||||
throw;
|
||||
}
|
||||
FreeEnvironmentStringsW(wstrings);
|
||||
}
|
||||
|
||||
std::vector<char*> args_;
|
||||
std::vector<short_stackstring> arg_values_;
|
||||
stackstring env_;
|
||||
std::vector<char*> envp_;
|
||||
|
||||
int old_argc_;
|
||||
char** old_argv_;
|
||||
char** old_env_;
|
||||
|
||||
int* old_argc_ptr_;
|
||||
char*** old_argv_ptr_;
|
||||
char*** old_env_ptr_;
|
||||
};
|
||||
|
||||
# endif
|
||||
|
||||
} // namespace nowide
|
||||
|
||||
#endif
|
||||
|
||||
///
|
||||
// vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4
|
||||
+112
@@ -0,0 +1,112 @@
|
||||
//
|
||||
// Copyright (c) 2012 Artyom Beilis (Tonkikh)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
#ifndef NOWIDE_CENV_H_INCLUDED
|
||||
# define NOWIDE_CENV_H_INCLUDED
|
||||
|
||||
# include <nowide/config.hpp>
|
||||
# include <nowide/stackstring.hpp>
|
||||
# include <stdexcept>
|
||||
# include <stdlib.h>
|
||||
# include <string>
|
||||
# include <vector>
|
||||
|
||||
# ifdef NOWIDE_WINDOWS
|
||||
# include <nowide/windows.hpp>
|
||||
# endif
|
||||
|
||||
namespace nowide
|
||||
{
|
||||
# if !defined(NOWIDE_WINDOWS) && !defined(NOWIDE_DOXYGEN)
|
||||
using ::getenv;
|
||||
using ::putenv;
|
||||
using ::setenv;
|
||||
using ::unsetenv;
|
||||
# else
|
||||
///
|
||||
/// \brief UTF-8 aware getenv. Returns 0 if the variable is not set.
|
||||
///
|
||||
/// This function is not thread safe or reenterable as defined by the standard library
|
||||
///
|
||||
inline char* getenv(char const* key)
|
||||
{
|
||||
static stackstring value;
|
||||
|
||||
wshort_stackstring name;
|
||||
if (!name.convert(key)) return 0;
|
||||
|
||||
static const size_t buf_size = 64;
|
||||
wchar_t buf[buf_size];
|
||||
std::vector<wchar_t> tmp;
|
||||
wchar_t* ptr = buf;
|
||||
size_t n = GetEnvironmentVariableW(name.c_str(), buf, buf_size);
|
||||
if (n == 0 && GetLastError() == 203) // ERROR_ENVVAR_NOT_FOUND
|
||||
return 0;
|
||||
if (n >= buf_size) {
|
||||
tmp.resize(n + 1, L'\0');
|
||||
n = GetEnvironmentVariableW(name.c_str(), &tmp[0], static_cast<unsigned>(tmp.size() - 1));
|
||||
// The size may have changed
|
||||
if (n >= tmp.size() - 1) return 0;
|
||||
ptr = &tmp[0];
|
||||
}
|
||||
if (!value.convert(ptr)) return 0;
|
||||
return value.c_str();
|
||||
}
|
||||
///
|
||||
/// \brief UTF-8 aware setenv, \a key - the variable name, \a value is a new UTF-8 value,
|
||||
///
|
||||
/// if override is not 0, that the old value is always overridded, otherwise,
|
||||
/// if the variable exists it remains unchanged
|
||||
///
|
||||
inline int setenv(char const* key, char const* value, int override)
|
||||
{
|
||||
wshort_stackstring name;
|
||||
if (!name.convert(key)) return -1;
|
||||
if (!override) {
|
||||
wchar_t unused[2];
|
||||
if (!(GetEnvironmentVariableW(name.c_str(), unused, 2) == 0 && GetLastError() == 203)) // ERROR_ENVVAR_NOT_FOUND
|
||||
return 0;
|
||||
}
|
||||
wstackstring wval;
|
||||
if (!wval.convert(getValue)) return -1;
|
||||
if (SetEnvironmentVariableW(name.c_str(), wval.c_str())) return 0;
|
||||
return -1;
|
||||
}
|
||||
///
|
||||
/// \brief Remove enviroment variable \a key
|
||||
///
|
||||
inline int unsetenv(char const* key)
|
||||
{
|
||||
wshort_stackstring name;
|
||||
if (!name.convert(key)) return -1;
|
||||
if (SetEnvironmentVariableW(name.c_str(), 0)) return 0;
|
||||
return -1;
|
||||
}
|
||||
///
|
||||
/// \brief UTF-8 aware putenv implementation, expects string in format KEY=VALUE
|
||||
///
|
||||
inline int putenv(char* string)
|
||||
{
|
||||
char const* key = string;
|
||||
char const* key_end = string;
|
||||
while (*key_end != '=' && key_end != '\0') key_end++;
|
||||
if (*key_end == '\0') return -1;
|
||||
wshort_stackstring wkey;
|
||||
if (!wkey.convert(key, key_end)) return -1;
|
||||
|
||||
wstackstring wvalue;
|
||||
if (!wvalue.convert(key_end + 1)) return -1;
|
||||
|
||||
if (SetEnvironmentVariableW(wkey.c_str(), wvalue.c_str())) return 0;
|
||||
return -1;
|
||||
}
|
||||
# endif
|
||||
} // namespace nowide
|
||||
|
||||
#endif
|
||||
///
|
||||
// vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4
|
||||
@@ -0,0 +1,35 @@
|
||||
//
|
||||
// Copyright (c) 2012 Artyom Beilis (Tonkikh)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
#ifndef NOWIDE_CONFIG_H_INCLUDED
|
||||
# define NOWIDE_CONFIG_H_INCLUDED
|
||||
|
||||
# if (defined(__WIN32) || defined(_WIN32) || defined(WIN32)) && !defined(__CYGWIN__)
|
||||
# define NOWIDE_WINDOWS
|
||||
# endif
|
||||
|
||||
# ifdef _MSC_VER
|
||||
# define NOWIDE_MSVC
|
||||
# endif
|
||||
|
||||
# ifdef NOWIDE_WINDOWS
|
||||
# if defined(DLL_EXPORT) || defined(NOWIDE_EXPORT)
|
||||
# ifdef NOWIDE_SOURCE
|
||||
# define NOWIDE_DECL __declspec(dllexport)
|
||||
# else
|
||||
# define NOWIDE_DECL __declspec(dllimport)
|
||||
# endif // NOWIDE_SOURCE
|
||||
# endif // DYN_LINK
|
||||
# endif
|
||||
|
||||
# ifndef NOWIDE_DECL
|
||||
# define NOWIDE_DECL
|
||||
# endif
|
||||
|
||||
#endif
|
||||
///
|
||||
// vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4
|
||||
+151
@@ -0,0 +1,151 @@
|
||||
//
|
||||
// Copyright (c) 2012 Artyom Beilis (Tonkikh)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
#ifndef NOWIDE_CONVERT_H_INCLUDED
|
||||
# define NOWIDE_CONVERT_H_INCLUDED
|
||||
|
||||
# include <nowide/encoding_utf.hpp>
|
||||
# include <string>
|
||||
|
||||
namespace nowide
|
||||
{
|
||||
///
|
||||
/// \brief Template function that converts a buffer of UTF sequences in range [source_begin,source_end)
|
||||
/// to the output \a buffer of size \a buffer_size.
|
||||
///
|
||||
/// In case of success a NULL terminated string is returned (buffer), otherwise 0 is returned.
|
||||
///
|
||||
/// If there is not enough room in the buffer or the source sequence contains invalid UTF,
|
||||
/// 0 is returned, and the contents of the buffer are undefined.
|
||||
///
|
||||
template<typename CharOut, typename CharIn>
|
||||
CharOut* basic_convert(CharOut* buffer, size_t buffer_size, CharIn const* source_begin, CharIn const* source_end)
|
||||
{
|
||||
CharOut* rv = buffer;
|
||||
if (buffer_size == 0) return 0;
|
||||
buffer_size--;
|
||||
while (source_begin != source_end) {
|
||||
using namespace nowide::utf;
|
||||
code_point c = utf_traits<CharIn>::template decode<CharIn const*>(source_begin, source_end);
|
||||
if (c == illegal || c == incomplete) {
|
||||
rv = 0;
|
||||
break;
|
||||
}
|
||||
size_t width = utf_traits<CharOut>::width(c);
|
||||
if (buffer_size < width) {
|
||||
rv = 0;
|
||||
break;
|
||||
}
|
||||
buffer = utf_traits<CharOut>::template encode<CharOut*>(c, buffer);
|
||||
buffer_size -= width;
|
||||
}
|
||||
*buffer++ = 0;
|
||||
return rv;
|
||||
}
|
||||
|
||||
/// \cond INTERNAL
|
||||
namespace details
|
||||
{
|
||||
//
|
||||
// wcslen defined only in C99... So we will not use it
|
||||
//
|
||||
template<typename Char>
|
||||
Char const* basic_strend(Char const* s)
|
||||
{
|
||||
while (*s) s++;
|
||||
return s;
|
||||
}
|
||||
} // namespace details
|
||||
/// \endcond
|
||||
|
||||
///
|
||||
/// Convert NULL terminated UTF source string to NULL terminated \a output string of size at
|
||||
/// most output_size (including NULL)
|
||||
///
|
||||
/// In case of success output is returned, if the input sequence is illegal,
|
||||
/// or there is not enough room NULL is returned
|
||||
///
|
||||
inline char* narrow(char* output, size_t output_size, wchar_t const* source)
|
||||
{
|
||||
return basic_convert(output, output_size, source, details::basic_strend(source));
|
||||
}
|
||||
///
|
||||
/// Convert UTF text in range [begin,end) to NULL terminated \a output string of size at
|
||||
/// most output_size (including NULL)
|
||||
///
|
||||
/// In case of success output is returned, if the input sequence is illegal,
|
||||
/// or there is not enough room NULL is returned
|
||||
///
|
||||
inline char* narrow(char* output, size_t output_size, wchar_t const* begin, wchar_t const* end)
|
||||
{
|
||||
return basic_convert(output, output_size, begin, end);
|
||||
}
|
||||
///
|
||||
/// Convert NULL terminated UTF source string to NULL terminated \a output string of size at
|
||||
/// most output_size (including NULL)
|
||||
///
|
||||
/// In case of success output is returned, if the input sequence is illegal,
|
||||
/// or there is not enough room NULL is returned
|
||||
///
|
||||
inline wchar_t* widen(wchar_t* output, size_t output_size, char const* source)
|
||||
{
|
||||
return basic_convert(output, output_size, source, details::basic_strend(source));
|
||||
}
|
||||
///
|
||||
/// Convert UTF text in range [begin,end) to NULL terminated \a output string of size at
|
||||
/// most output_size (including NULL)
|
||||
///
|
||||
/// In case of success output is returned, if the input sequence is illegal,
|
||||
/// or there is not enough room NULL is returned
|
||||
///
|
||||
inline wchar_t* widen(wchar_t* output, size_t output_size, char const* begin, char const* end)
|
||||
{
|
||||
return basic_convert(output, output_size, begin, end);
|
||||
}
|
||||
|
||||
///
|
||||
/// Convert between Wide - UTF-16/32 string and UTF-8 string.
|
||||
///
|
||||
/// nowide::conv::conversion_error is thrown in a case of a error
|
||||
///
|
||||
inline std::string narrow(wchar_t const* s)
|
||||
{
|
||||
return nowide::conv::utf_to_utf<char>(s);
|
||||
}
|
||||
///
|
||||
/// Convert between UTF-8 and UTF-16 string, implemented only on Windows platform
|
||||
///
|
||||
/// nowide::conv::conversion_error is thrown in a case of a error
|
||||
///
|
||||
inline std::wstring widen(char const* s)
|
||||
{
|
||||
return nowide::conv::utf_to_utf<wchar_t>(s);
|
||||
}
|
||||
///
|
||||
/// Convert between Wide - UTF-16/32 string and UTF-8 string
|
||||
///
|
||||
/// nowide::conv::conversion_error is thrown in a case of a error
|
||||
///
|
||||
inline std::string narrow(std::wstring const& s)
|
||||
{
|
||||
return nowide::conv::utf_to_utf<char>(s);
|
||||
}
|
||||
///
|
||||
/// Convert between UTF-8 and UTF-16 string, implemented only on Windows platform
|
||||
///
|
||||
/// nowide::conv::conversion_error is thrown in a case of a error
|
||||
///
|
||||
inline std::wstring widen(std::string const& s)
|
||||
{
|
||||
return nowide::conv::utf_to_utf<wchar_t>(s);
|
||||
}
|
||||
|
||||
} // namespace nowide
|
||||
|
||||
#endif
|
||||
///
|
||||
// vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4
|
||||
@@ -0,0 +1,99 @@
|
||||
//
|
||||
// Copyright (c) 2012 Artyom Beilis (Tonkikh)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
#ifndef NOWIDE_CSTDIO_H_INCLUDED
|
||||
# define NOWIDE_CSTDIO_H_INCLUDED
|
||||
|
||||
# include <cstdio>
|
||||
# include <errno.h>
|
||||
# include <nowide/config.hpp>
|
||||
# include <nowide/convert.hpp>
|
||||
# include <nowide/stackstring.hpp>
|
||||
# include <stdio.h>
|
||||
|
||||
# ifdef NOWIDE_MSVC
|
||||
# pragma warning(push)
|
||||
# pragma warning(disable : 4996)
|
||||
# endif
|
||||
|
||||
namespace nowide
|
||||
{
|
||||
# if !defined(NOWIDE_WINDOWS) && !defined(NOWIDE_DOXYGEN)
|
||||
using std::fopen;
|
||||
using std::freopen;
|
||||
using std::remove;
|
||||
using std::rename;
|
||||
# else
|
||||
|
||||
///
|
||||
/// \brief Same as freopen but file_name and mode are UTF-8 strings
|
||||
///
|
||||
/// If invalid UTF-8 given, NULL is returned and errno is set to EINVAL
|
||||
///
|
||||
inline FILE* freopen(char const* file_name, char const* mode, FILE* stream)
|
||||
{
|
||||
wstackstring wname;
|
||||
wshort_stackstring wmode;
|
||||
if (!wname.convert(file_name) || !wmode.convert(mode)) {
|
||||
errno = EINVAL;
|
||||
return 0;
|
||||
}
|
||||
return _wfreopen(wname.c_str(), wmode.c_str(), stream);
|
||||
}
|
||||
///
|
||||
/// \brief Same as fopen but file_name and mode are UTF-8 strings
|
||||
///
|
||||
/// If invalid UTF-8 given, NULL is returned and errno is set to EINVAL
|
||||
///
|
||||
inline FILE* fopen(char const* file_name, char const* mode)
|
||||
{
|
||||
wstackstring wname;
|
||||
wshort_stackstring wmode;
|
||||
if (!wname.convert(file_name) || !wmode.convert(mode)) {
|
||||
errno = EINVAL;
|
||||
return 0;
|
||||
}
|
||||
return _wfopen(wname.c_str(), wmode.c_str());
|
||||
}
|
||||
///
|
||||
/// \brief Same as rename but old_name and new_name are UTF-8 strings
|
||||
///
|
||||
/// If invalid UTF-8 given, -1 is returned and errno is set to EINVAL
|
||||
///
|
||||
inline int rename(char const* old_name, char const* new_name)
|
||||
{
|
||||
wstackstring wold, wnew;
|
||||
if (!wold.convert(old_name) || !wnew.convert(new_name)) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
return _wrename(wold.c_str(), wnew.c_str());
|
||||
}
|
||||
///
|
||||
/// \brief Same as rename but name is UTF-8 string
|
||||
///
|
||||
/// If invalid UTF-8 given, -1 is returned and errno is set to EINVAL
|
||||
///
|
||||
inline int remove(char const* name)
|
||||
{
|
||||
wstackstring wname;
|
||||
if (!wname.convert(name)) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
return _wremove(wname.c_str());
|
||||
}
|
||||
# endif
|
||||
} // namespace nowide
|
||||
|
||||
# ifdef NOWIDE_MSVC
|
||||
# pragma warning(pop)
|
||||
# endif
|
||||
|
||||
#endif
|
||||
///
|
||||
// vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4
|
||||
@@ -0,0 +1,16 @@
|
||||
//
|
||||
// Copyright (c) 2012 Artyom Beilis (Tonkikh)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
#ifndef NOWIDE_CSTDLIB_HPP_INCLUDED
|
||||
# define NOWIDE_CSTDLIB_HPP_INCLUDED
|
||||
|
||||
# include <nowide/cenv.hpp>
|
||||
# include <nowide/system.hpp>
|
||||
|
||||
#endif
|
||||
///
|
||||
// vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4
|
||||
@@ -0,0 +1,57 @@
|
||||
//
|
||||
// Copyright (c) 2009-2011 Artyom Beilis (Tonkikh)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
#ifndef NOWIDE_ENCODING_ERRORS_HPP_INCLUDED
|
||||
# define NOWIDE_ENCODING_ERRORS_HPP_INCLUDED
|
||||
|
||||
# include <nowide/config.hpp>
|
||||
# ifdef NOWIDE_MSVC
|
||||
# pragma warning(push)
|
||||
# pragma warning(disable : 4242 4619 4275 4251 4231 4660)
|
||||
# endif
|
||||
# include <stdexcept>
|
||||
|
||||
namespace nowide
|
||||
{
|
||||
namespace conv
|
||||
{
|
||||
///
|
||||
/// \addtogroup codepage
|
||||
///
|
||||
/// @{
|
||||
|
||||
///
|
||||
/// \brief The excepton that is thrown in case of conversion error
|
||||
///
|
||||
class conversion_error : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
conversion_error() : std::runtime_error("Conversion failed") {}
|
||||
};
|
||||
|
||||
///
|
||||
/// enum that defines conversion policy
|
||||
///
|
||||
typedef enum {
|
||||
skip = 0, ///< Skip illegal/unconvertable characters
|
||||
stop = 1, ///< Stop conversion and throw conversion_error
|
||||
default_method = skip ///< Default method - skip
|
||||
} method_type;
|
||||
|
||||
/// @}
|
||||
|
||||
} // namespace conv
|
||||
|
||||
} // namespace nowide
|
||||
|
||||
# ifdef NOWIDE_MSVC
|
||||
# pragma warning(pop)
|
||||
# endif
|
||||
|
||||
#endif
|
||||
|
||||
// vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4
|
||||
@@ -0,0 +1,76 @@
|
||||
//
|
||||
// Copyright (c) 2009-2011 Artyom Beilis (Tonkikh)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
#ifndef NOWIDE_ENCODING_UTF_HPP_INCLUDED
|
||||
# define NOWIDE_ENCODING_UTF_HPP_INCLUDED
|
||||
|
||||
# include <iterator>
|
||||
# include <nowide/encoding_errors.hpp>
|
||||
# include <nowide/utf.hpp>
|
||||
# include <string>
|
||||
# ifdef NOWIDE_MSVC
|
||||
# pragma warning(push)
|
||||
# pragma warning(disable : 4619 4275 4251 4231 4660)
|
||||
# endif
|
||||
|
||||
namespace nowide
|
||||
{
|
||||
namespace conv
|
||||
{
|
||||
///
|
||||
/// Convert a Unicode text in range [begin,end) to other Unicode encoding
|
||||
///
|
||||
template<typename CharOut, typename CharIn>
|
||||
std::basic_string<CharOut> utf_to_utf(CharIn const* begin, CharIn const* end, method_type how = default_method)
|
||||
{
|
||||
std::basic_string<CharOut> result;
|
||||
result.reserve(end - begin);
|
||||
typedef std::back_insert_iterator<std::basic_string<CharOut>> inserter_type;
|
||||
inserter_type inserter(result);
|
||||
utf::code_point c;
|
||||
while (begin != end) {
|
||||
c = utf::utf_traits<CharIn>::template decode<CharIn const*>(begin, end);
|
||||
if (c == utf::illegal || c == utf::incomplete) {
|
||||
if (how == stop) throw conversion_error();
|
||||
}
|
||||
else {
|
||||
utf::utf_traits<CharOut>::template encode<inserter_type>(c, inserter);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
///
|
||||
/// Convert a Unicode NULL terminated string \a str other Unicode encoding
|
||||
///
|
||||
template<typename CharOut, typename CharIn>
|
||||
std::basic_string<CharOut> utf_to_utf(CharIn const* str, method_type how = default_method)
|
||||
{
|
||||
CharIn const* end = str;
|
||||
while (*end) end++;
|
||||
return utf_to_utf<CharOut, CharIn>(str, end, how);
|
||||
}
|
||||
|
||||
///
|
||||
/// Convert a Unicode string \a str other Unicode encoding
|
||||
///
|
||||
template<typename CharOut, typename CharIn>
|
||||
std::basic_string<CharOut> utf_to_utf(std::basic_string<CharIn> const& str, method_type how = default_method)
|
||||
{
|
||||
return utf_to_utf<CharOut, CharIn>(str.c_str(), str.c_str() + str.size(), how);
|
||||
}
|
||||
|
||||
} // namespace conv
|
||||
} // namespace nowide
|
||||
|
||||
# ifdef NOWIDE_MSVC
|
||||
# pragma warning(pop)
|
||||
# endif
|
||||
|
||||
#endif
|
||||
|
||||
// vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4
|
||||
+363
@@ -0,0 +1,363 @@
|
||||
//
|
||||
// Copyright (c) 2012 Artyom Beilis (Tonkikh)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
#ifndef NOWIDE_FILEBUF_HPP
|
||||
# define NOWIDE_FILEBUF_HPP
|
||||
|
||||
# include <fstream>
|
||||
# include <iosfwd>
|
||||
# include <nowide/config.hpp>
|
||||
# include <nowide/stackstring.hpp>
|
||||
# include <stdio.h>
|
||||
# include <streambuf>
|
||||
|
||||
# ifdef NOWIDE_MSVC
|
||||
# pragma warning(push)
|
||||
# pragma warning(disable : 4996 4242 4244 4800)
|
||||
# endif
|
||||
|
||||
namespace nowide
|
||||
{
|
||||
# if !defined(NOWIDE_WINDOWS) && !defined(NOWIDE_FSTREAM_TESTS) && !defined(NOWIDE_DOXYGEN)
|
||||
using std::basic_filebuf;
|
||||
using std::filebuf;
|
||||
# else // Windows
|
||||
|
||||
///
|
||||
/// \brief This forward declaration defined the basic_filebuf type.
|
||||
///
|
||||
/// it is implemented and specialized for CharType = char, it behaves
|
||||
/// implements std::filebuf over standard C I/O
|
||||
///
|
||||
template<typename CharType, typename Traits = std::char_traits<CharType>>
|
||||
class basic_filebuf;
|
||||
|
||||
///
|
||||
/// \brief This is implementation of std::filebuf
|
||||
///
|
||||
/// it is implemented and specialized for CharType = char, it behaves
|
||||
/// implements std::filebuf over standard C I/O
|
||||
///
|
||||
template<>
|
||||
class basic_filebuf<char> : public std::basic_streambuf<char>
|
||||
{
|
||||
public:
|
||||
///
|
||||
/// Creates new filebuf
|
||||
///
|
||||
basic_filebuf() : buffer_size_(4), buffer_(0), file_(0), own_(true), mode_(std::ios::in | std::ios::out)
|
||||
{
|
||||
setg(0, 0, 0);
|
||||
setp(0, 0);
|
||||
}
|
||||
|
||||
virtual ~basic_filebuf()
|
||||
{
|
||||
if (file_) {
|
||||
::fclose(file_);
|
||||
file_ = 0;
|
||||
}
|
||||
if (own_ && buffer_) delete[] buffer_;
|
||||
}
|
||||
|
||||
///
|
||||
/// Same as std::filebuf::open but s is UTF-8 string
|
||||
///
|
||||
basic_filebuf* open(std::string const& s, std::ios_base::openmode mode)
|
||||
{
|
||||
return open(s.c_str(), mode);
|
||||
}
|
||||
///
|
||||
/// Same as std::filebuf::open but s is UTF-8 string
|
||||
///
|
||||
basic_filebuf* open(char const* s, std::ios_base::openmode mode)
|
||||
{
|
||||
if (file_) {
|
||||
sync();
|
||||
::fclose(file_);
|
||||
file_ = 0;
|
||||
}
|
||||
bool ate = bool(mode & std::ios_base::ate);
|
||||
if (ate) mode = mode ^ std::ios_base::ate;
|
||||
wchar_t const* smode = get_mode(mode);
|
||||
if (!smode) return 0;
|
||||
wstackstring name;
|
||||
if (!name.convert(s)) return 0;
|
||||
# ifdef NOWIDE_FSTREAM_TESTS
|
||||
FILE* f = ::fopen(s, nowide::convert(smode).c_str());
|
||||
# else
|
||||
FILE* f = ::_wfopen(name.c_str(), smode);
|
||||
# endif
|
||||
if (!f) return 0;
|
||||
if (ate && fseek(f, 0, SEEK_END) != 0) {
|
||||
fclose(f);
|
||||
return 0;
|
||||
}
|
||||
file_ = f;
|
||||
return this;
|
||||
}
|
||||
///
|
||||
/// Same as std::filebuf::close()
|
||||
///
|
||||
basic_filebuf* close()
|
||||
{
|
||||
bool res = sync() == 0;
|
||||
if (file_) {
|
||||
if (::fclose(file_) != 0) res = false;
|
||||
file_ = 0;
|
||||
}
|
||||
return res ? this : 0;
|
||||
}
|
||||
///
|
||||
/// Same as std::filebuf::is_open()
|
||||
///
|
||||
bool is_open() const
|
||||
{
|
||||
return file_ != 0;
|
||||
}
|
||||
|
||||
private:
|
||||
void make_buffer()
|
||||
{
|
||||
if (buffer_) return;
|
||||
if (buffer_size_ > 0) {
|
||||
buffer_ = new char[buffer_size_];
|
||||
own_ = true;
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual std::streambuf* setbuf(char* s, std::streamsize n)
|
||||
{
|
||||
if (!buffer_ && n >= 0) {
|
||||
buffer_ = s;
|
||||
buffer_size_ = n;
|
||||
own_ = false;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
# ifdef NOWIDE_DEBUG_FILEBUF
|
||||
|
||||
void print_buf(char* b, char* p, char* e)
|
||||
{
|
||||
std::cerr << "-- Is Null: " << (b == 0) << std::endl;
|
||||
;
|
||||
if (b == 0) return;
|
||||
if (e != 0)
|
||||
std::cerr << "-- Total: " << e - b << " offset from start " << p - b << std::endl;
|
||||
else
|
||||
std::cerr << "-- Total: " << p - b << std::endl;
|
||||
|
||||
std::cerr << "-- [";
|
||||
for (char* ptr = b; ptr < p; ptr++) std::cerr << *ptr;
|
||||
if (e != 0) {
|
||||
std::cerr << "|";
|
||||
for (char* ptr = p; ptr < e; ptr++) std::cerr << *ptr;
|
||||
}
|
||||
std::cerr << "]" << std::endl;
|
||||
}
|
||||
|
||||
void print_state()
|
||||
{
|
||||
std::cerr << "- Output:" << std::endl;
|
||||
print_buf(pbase(), pptr(), 0);
|
||||
std::cerr << "- Input:" << std::endl;
|
||||
print_buf(eback(), gptr(), egptr());
|
||||
std::cerr << "- fpos: " << (file_ ? ftell(file_) : -1L) << std::endl;
|
||||
}
|
||||
|
||||
struct print_guard
|
||||
{
|
||||
print_guard(basic_filebuf* p, char const* func)
|
||||
{
|
||||
self = p;
|
||||
f = func;
|
||||
std::cerr << "In: " << f << std::endl;
|
||||
self->print_state();
|
||||
}
|
||||
~print_guard()
|
||||
{
|
||||
std::cerr << "Out: " << f << std::endl;
|
||||
self->print_state();
|
||||
}
|
||||
basic_filebuf* self;
|
||||
char const* f;
|
||||
};
|
||||
# else
|
||||
# endif
|
||||
|
||||
int overflow(int c)
|
||||
{
|
||||
# ifdef NOWIDE_DEBUG_FILEBUF
|
||||
print_guard g(this, __FUNCTION__);
|
||||
# endif
|
||||
if (!file_) return EOF;
|
||||
|
||||
if (fixg() < 0) return EOF;
|
||||
|
||||
size_t n = pptr() - pbase();
|
||||
if (n > 0) {
|
||||
if (::fwrite(pbase(), 1, n, file_) < n) return -1;
|
||||
fflush(file_);
|
||||
}
|
||||
|
||||
if (buffer_size_ > 0) {
|
||||
make_buffer();
|
||||
setp(buffer_, buffer_ + buffer_size_);
|
||||
if (c != EOF) sputc(c);
|
||||
}
|
||||
else if (c != EOF) {
|
||||
if (::fputc(c, file_) == EOF) return EOF;
|
||||
fflush(file_);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sync()
|
||||
{
|
||||
return overflow(EOF);
|
||||
}
|
||||
|
||||
int underflow()
|
||||
{
|
||||
# ifdef NOWIDE_DEBUG_FILEBUF
|
||||
print_guard g(this, __FUNCTION__);
|
||||
# endif
|
||||
if (!file_) return EOF;
|
||||
if (fixp() < 0) return EOF;
|
||||
if (buffer_size_ == 0) {
|
||||
int c = ::fgetc(file_);
|
||||
if (c == EOF) {
|
||||
return EOF;
|
||||
}
|
||||
last_char_ = c;
|
||||
setg(&last_char_, &last_char_, &last_char_ + 1);
|
||||
return c;
|
||||
}
|
||||
make_buffer();
|
||||
size_t n = ::fread(buffer_, 1, buffer_size_, file_);
|
||||
setg(buffer_, buffer_, buffer_ + n);
|
||||
if (n == 0) return EOF;
|
||||
return std::char_traits<char>::to_int_type(*gptr());
|
||||
}
|
||||
|
||||
int pbackfail(int)
|
||||
{
|
||||
return pubseekoff(-1, std::ios::cur);
|
||||
}
|
||||
|
||||
std::streampos seekoff(std::streamoff off, std::ios_base::seekdir seekdir, std::ios_base::openmode /*m*/)
|
||||
{
|
||||
# ifdef NOWIDE_DEBUG_FILEBUF
|
||||
print_guard g(this, __FUNCTION__);
|
||||
# endif
|
||||
if (!file_) return EOF;
|
||||
if (fixp() < 0 || fixg() < 0) return EOF;
|
||||
if (seekdir == std::ios_base::cur) {
|
||||
if (::fseek(file_, off, SEEK_CUR) < 0) return EOF;
|
||||
}
|
||||
else if (seekdir == std::ios_base::beg) {
|
||||
if (::fseek(file_, off, SEEK_SET) < 0) return EOF;
|
||||
}
|
||||
else if (seekdir == std::ios_base::end) {
|
||||
if (::fseek(file_, off, SEEK_END) < 0) return EOF;
|
||||
}
|
||||
else
|
||||
return -1;
|
||||
return ftell(file_);
|
||||
}
|
||||
std::streampos seekpos(std::streampos off, std::ios_base::openmode m)
|
||||
{
|
||||
return seekoff(std::streamoff(off), std::ios_base::beg, m);
|
||||
}
|
||||
|
||||
private:
|
||||
int fixg()
|
||||
{
|
||||
if (gptr() != egptr()) {
|
||||
std::streamsize off = gptr() - egptr();
|
||||
setg(0, 0, 0);
|
||||
if (fseek(file_, off, SEEK_CUR) != 0) return -1;
|
||||
}
|
||||
setg(0, 0, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fixp()
|
||||
{
|
||||
if (pptr() != 0) {
|
||||
int r = sync();
|
||||
setp(0, 0);
|
||||
return r;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void reset(FILE* f = 0)
|
||||
{
|
||||
sync();
|
||||
if (file_) {
|
||||
fclose(file_);
|
||||
file_ = 0;
|
||||
}
|
||||
file_ = f;
|
||||
}
|
||||
|
||||
static wchar_t const* get_mode(std::ios_base::openmode mode)
|
||||
{
|
||||
//
|
||||
// done according to n2914 table 106 27.9.1.4
|
||||
//
|
||||
|
||||
// note can't use switch case as overload operator can't be used
|
||||
// in constant expression
|
||||
if (mode == (std::ios_base::out)) return L"w";
|
||||
if (mode == (std::ios_base::out | std::ios_base::app)) return L"a";
|
||||
if (mode == (std::ios_base::app)) return L"a";
|
||||
if (mode == (std::ios_base::out | std::ios_base::trunc)) return L"w";
|
||||
if (mode == (std::ios_base::in)) return L"r";
|
||||
if (mode == (std::ios_base::in | std::ios_base::out)) return L"r+";
|
||||
if (mode == (std::ios_base::in | std::ios_base::out | std::ios_base::trunc)) return L"w+";
|
||||
if (mode == (std::ios_base::in | std::ios_base::out | std::ios_base::app)) return L"a+";
|
||||
if (mode == (std::ios_base::in | std::ios_base::app)) return L"a+";
|
||||
if (mode == (std::ios_base::binary | std::ios_base::out)) return L"wb";
|
||||
if (mode == (std::ios_base::binary | std::ios_base::out | std::ios_base::app)) return L"ab";
|
||||
if (mode == (std::ios_base::binary | std::ios_base::app)) return L"ab";
|
||||
if (mode == (std::ios_base::binary | std::ios_base::out | std::ios_base::trunc)) return L"wb";
|
||||
if (mode == (std::ios_base::binary | std::ios_base::in)) return L"rb";
|
||||
if (mode == (std::ios_base::binary | std::ios_base::in | std::ios_base::out)) return L"r+b";
|
||||
if (mode == (std::ios_base::binary | std::ios_base::in | std::ios_base::out | std::ios_base::trunc)) return L"w+b";
|
||||
if (mode == (std::ios_base::binary | std::ios_base::in | std::ios_base::out | std::ios_base::app)) return L"a+b";
|
||||
if (mode == (std::ios_base::binary | std::ios_base::in | std::ios_base::app)) return L"a+b";
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t buffer_size_;
|
||||
char* buffer_;
|
||||
FILE* file_;
|
||||
bool own_;
|
||||
char last_char_;
|
||||
std::ios::openmode mode_;
|
||||
};
|
||||
|
||||
///
|
||||
/// \brief Convinience typedef
|
||||
///
|
||||
typedef basic_filebuf<char> filebuf;
|
||||
|
||||
# endif // windows
|
||||
|
||||
} // namespace nowide
|
||||
|
||||
# ifdef NOWIDE_MSVC
|
||||
# pragma warning(pop)
|
||||
# endif
|
||||
|
||||
#endif
|
||||
|
||||
// vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4
|
||||
+271
@@ -0,0 +1,271 @@
|
||||
//
|
||||
// Copyright (c) 2012 Artyom Beilis (Tonkikh)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
#ifndef NOWIDE_FSTREAM_INCLUDED_HPP
|
||||
# define NOWIDE_FSTREAM_INCLUDED_HPP
|
||||
|
||||
# include <fstream>
|
||||
# include <iosfwd>
|
||||
# include <memory>
|
||||
# include <nowide/config.hpp>
|
||||
# include <nowide/convert.hpp>
|
||||
# include <nowide/filebuf.hpp>
|
||||
# include <nowide/scoped_ptr.hpp>
|
||||
|
||||
///
|
||||
/// \brief This namespace includes implementation of the standard library functios
|
||||
/// such that they accept UTF-8 strings on Windows. On other platforms it is just an alias
|
||||
/// of std namespace (i.e. not on Windows)
|
||||
///
|
||||
namespace nowide
|
||||
{
|
||||
# if !defined(NOWIDE_WINDOWS) && !defined(NOWIDE_FSTREAM_TESTS) && !defined(NOWIDE_DOXYGEN)
|
||||
|
||||
using std::basic_fstream;
|
||||
using std::basic_ifstream;
|
||||
using std::basic_ofstream;
|
||||
using std::fstream;
|
||||
using std::ifstream;
|
||||
using std::ofstream;
|
||||
|
||||
# else
|
||||
///
|
||||
/// \brief Same as std::basic_ifstream<char> but accepts UTF-8 strings under Windows
|
||||
///
|
||||
template<typename CharType, typename Traits = std::char_traits<CharType>>
|
||||
class basic_ifstream : public std::basic_istream<CharType, Traits>
|
||||
{
|
||||
public:
|
||||
typedef basic_filebuf<CharType, Traits> internal_buffer_type;
|
||||
typedef std::basic_istream<CharType, Traits> internal_stream_type;
|
||||
|
||||
basic_ifstream() : internal_stream_type(0)
|
||||
{
|
||||
buf_.reset(new internal_buffer_type());
|
||||
std::ios::rdbuf(buf_.get());
|
||||
}
|
||||
|
||||
explicit basic_ifstream(char const* file_name, std::ios_base::openmode mode = std::ios_base::in) : internal_stream_type(0)
|
||||
{
|
||||
buf_.reset(new internal_buffer_type());
|
||||
std::ios::rdbuf(buf_.get());
|
||||
open(file_name, mode);
|
||||
}
|
||||
|
||||
explicit basic_ifstream(std::string const& file_name, std::ios_base::openmode mode = std::ios_base::in) : internal_stream_type(0)
|
||||
{
|
||||
buf_.reset(new internal_buffer_type());
|
||||
std::ios::rdbuf(buf_.get());
|
||||
open(file_name, mode);
|
||||
}
|
||||
|
||||
void open(std::string const& file_name, std::ios_base::openmode mode = std::ios_base::in)
|
||||
{
|
||||
open(file_name.c_str(), mode);
|
||||
}
|
||||
void open(char const* file_name, std::ios_base::openmode mode = std::ios_base::in)
|
||||
{
|
||||
if (!buf_->open(file_name, mode | std::ios_base::in)) {
|
||||
this->setstate(std::ios_base::failbit);
|
||||
}
|
||||
else {
|
||||
this->clear();
|
||||
}
|
||||
}
|
||||
bool is_open()
|
||||
{
|
||||
return buf_->is_open();
|
||||
}
|
||||
bool is_open() const
|
||||
{
|
||||
return buf_->is_open();
|
||||
}
|
||||
void close()
|
||||
{
|
||||
if (!buf_->close())
|
||||
this->setstate(std::ios_base::failbit);
|
||||
else
|
||||
this->clear();
|
||||
}
|
||||
|
||||
internal_buffer_type* rdbuf() const
|
||||
{
|
||||
return buf_.get();
|
||||
}
|
||||
~basic_ifstream()
|
||||
{
|
||||
buf_->close();
|
||||
}
|
||||
|
||||
private:
|
||||
nowide::scoped_ptr<internal_buffer_type> buf_;
|
||||
};
|
||||
|
||||
///
|
||||
/// \brief Same as std::basic_ofstream<char> but accepts UTF-8 strings under Windows
|
||||
///
|
||||
|
||||
template<typename CharType, typename Traits = std::char_traits<CharType>>
|
||||
class basic_ofstream : public std::basic_ostream<CharType, Traits>
|
||||
{
|
||||
public:
|
||||
typedef basic_filebuf<CharType, Traits> internal_buffer_type;
|
||||
typedef std::basic_ostream<CharType, Traits> internal_stream_type;
|
||||
|
||||
basic_ofstream() : internal_stream_type(0)
|
||||
{
|
||||
buf_.reset(new internal_buffer_type());
|
||||
std::ios::rdbuf(buf_.get());
|
||||
}
|
||||
explicit basic_ofstream(char const* file_name, std::ios_base::openmode mode = std::ios_base::out) : internal_stream_type(0)
|
||||
{
|
||||
buf_.reset(new internal_buffer_type());
|
||||
std::ios::rdbuf(buf_.get());
|
||||
open(file_name, mode);
|
||||
}
|
||||
explicit basic_ofstream(std::string const& file_name, std::ios_base::openmode mode = std::ios_base::out) : internal_stream_type(0)
|
||||
{
|
||||
buf_.reset(new internal_buffer_type());
|
||||
std::ios::rdbuf(buf_.get());
|
||||
open(file_name, mode);
|
||||
}
|
||||
void open(std::string const& file_name, std::ios_base::openmode mode = std::ios_base::out)
|
||||
{
|
||||
open(file_name.c_str(), mode);
|
||||
}
|
||||
void open(char const* file_name, std::ios_base::openmode mode = std::ios_base::out)
|
||||
{
|
||||
if (!buf_->open(file_name, mode | std::ios_base::out)) {
|
||||
this->setstate(std::ios_base::failbit);
|
||||
}
|
||||
else {
|
||||
this->clear();
|
||||
}
|
||||
}
|
||||
bool is_open()
|
||||
{
|
||||
return buf_->is_open();
|
||||
}
|
||||
bool is_open() const
|
||||
{
|
||||
return buf_->is_open();
|
||||
}
|
||||
void close()
|
||||
{
|
||||
if (!buf_->close())
|
||||
this->setstate(std::ios_base::failbit);
|
||||
else
|
||||
this->clear();
|
||||
}
|
||||
|
||||
internal_buffer_type* rdbuf() const
|
||||
{
|
||||
return buf_.get();
|
||||
}
|
||||
~basic_ofstream()
|
||||
{
|
||||
buf_->close();
|
||||
}
|
||||
|
||||
private:
|
||||
nowide::scoped_ptr<internal_buffer_type> buf_;
|
||||
};
|
||||
|
||||
///
|
||||
/// \brief Same as std::basic_fstream<char> but accepts UTF-8 strings under Windows
|
||||
///
|
||||
|
||||
template<typename CharType, typename Traits = std::char_traits<CharType>>
|
||||
class basic_fstream : public std::basic_iostream<CharType, Traits>
|
||||
{
|
||||
public:
|
||||
typedef basic_filebuf<CharType, Traits> internal_buffer_type;
|
||||
typedef std::basic_iostream<CharType, Traits> internal_stream_type;
|
||||
|
||||
basic_fstream() : internal_stream_type(0)
|
||||
{
|
||||
buf_.reset(new internal_buffer_type());
|
||||
std::ios::rdbuf(buf_.get());
|
||||
}
|
||||
explicit basic_fstream(char const* file_name, std::ios_base::openmode mode = std::ios_base::out | std::ios_base::in)
|
||||
: internal_stream_type(0)
|
||||
{
|
||||
buf_.reset(new internal_buffer_type());
|
||||
std::ios::rdbuf(buf_.get());
|
||||
open(file_name, mode);
|
||||
}
|
||||
explicit basic_fstream(std::string const& file_name, std::ios_base::openmode mode = std::ios_base::out | std::ios_base::in)
|
||||
: internal_stream_type(0)
|
||||
{
|
||||
buf_.reset(new internal_buffer_type());
|
||||
std::ios::rdbuf(buf_.get());
|
||||
open(file_name, mode);
|
||||
}
|
||||
void open(std::string const& file_name, std::ios_base::openmode mode = std::ios_base::out | std::ios_base::out)
|
||||
{
|
||||
open(file_name.c_str(), mode);
|
||||
}
|
||||
void open(char const* file_name, std::ios_base::openmode mode = std::ios_base::out | std::ios_base::out)
|
||||
{
|
||||
if (!buf_->open(file_name, mode)) {
|
||||
this->setstate(std::ios_base::failbit);
|
||||
}
|
||||
else {
|
||||
this->clear();
|
||||
}
|
||||
}
|
||||
bool is_open()
|
||||
{
|
||||
return buf_->is_open();
|
||||
}
|
||||
bool is_open() const
|
||||
{
|
||||
return buf_->is_open();
|
||||
}
|
||||
void close()
|
||||
{
|
||||
if (!buf_->close())
|
||||
this->setstate(std::ios_base::failbit);
|
||||
else
|
||||
this->clear();
|
||||
}
|
||||
|
||||
internal_buffer_type* rdbuf() const
|
||||
{
|
||||
return buf_.get();
|
||||
}
|
||||
~basic_fstream()
|
||||
{
|
||||
buf_->close();
|
||||
}
|
||||
|
||||
private:
|
||||
nowide::scoped_ptr<internal_buffer_type> buf_;
|
||||
};
|
||||
|
||||
///
|
||||
/// \brief Same as std::filebuf but accepts UTF-8 strings under Windows
|
||||
///
|
||||
typedef basic_filebuf<char> filebuf;
|
||||
///
|
||||
/// Same as std::ifstream but accepts UTF-8 strings under Windows
|
||||
///
|
||||
typedef basic_ifstream<char> ifstream;
|
||||
///
|
||||
/// Same as std::ofstream but accepts UTF-8 strings under Windows
|
||||
///
|
||||
typedef basic_ofstream<char> ofstream;
|
||||
///
|
||||
/// Same as std::fstream but accepts UTF-8 strings under Windows
|
||||
///
|
||||
typedef basic_fstream<char> fstream;
|
||||
|
||||
# endif
|
||||
} // namespace nowide
|
||||
|
||||
#endif
|
||||
// vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4
|
||||
+102
@@ -0,0 +1,102 @@
|
||||
//
|
||||
// Copyright (c) 2012 Artyom Beilis (Tonkikh)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
#ifndef NOWIDE_IOSTREAM_HPP_INCLUDED
|
||||
# define NOWIDE_IOSTREAM_HPP_INCLUDED
|
||||
|
||||
# include <iostream>
|
||||
# include <istream>
|
||||
# include <nowide/config.hpp>
|
||||
# include <nowide/scoped_ptr.hpp>
|
||||
# include <ostream>
|
||||
|
||||
# ifdef NOWIDE_MSVC
|
||||
# pragma warning(push)
|
||||
# pragma warning(disable : 4251)
|
||||
# endif
|
||||
|
||||
namespace nowide
|
||||
{
|
||||
# if !defined(NOWIDE_WINDOWS) && !defined(NOWIDE_DOXYGEN)
|
||||
using std::cerr;
|
||||
using std::cin;
|
||||
using std::clog;
|
||||
using std::cout;
|
||||
# else
|
||||
|
||||
/// \cond INTERNAL
|
||||
namespace details
|
||||
{
|
||||
class console_output_buffer;
|
||||
class console_input_buffer;
|
||||
|
||||
class NOWIDE_DECL winconsole_ostream : public std::ostream
|
||||
{
|
||||
winconsole_ostream(winconsole_ostream const&);
|
||||
void operator=(winconsole_ostream const&);
|
||||
|
||||
public:
|
||||
winconsole_ostream(int fd);
|
||||
~winconsole_ostream();
|
||||
|
||||
private:
|
||||
nowide::scoped_ptr<console_output_buffer> d;
|
||||
};
|
||||
|
||||
class NOWIDE_DECL winconsole_istream : public std::istream
|
||||
{
|
||||
winconsole_istream(winconsole_istream const&);
|
||||
void operator=(winconsole_istream const&);
|
||||
|
||||
public:
|
||||
winconsole_istream();
|
||||
~winconsole_istream();
|
||||
|
||||
private:
|
||||
struct data;
|
||||
nowide::scoped_ptr<console_input_buffer> d;
|
||||
};
|
||||
} // namespace details
|
||||
|
||||
/// \endcond
|
||||
|
||||
///
|
||||
/// \brief Same as std::cin, but uses UTF-8
|
||||
///
|
||||
/// Note, the stream is not synchronized with stdio and not affected by std::ios::sync_with_stdio
|
||||
///
|
||||
extern NOWIDE_DECL details::winconsole_istream cin;
|
||||
///
|
||||
/// \brief Same as std::cout, but uses UTF-8
|
||||
///
|
||||
/// Note, the stream is not synchronized with stdio and not affected by std::ios::sync_with_stdio
|
||||
///
|
||||
extern NOWIDE_DECL details::winconsole_ostream cout;
|
||||
///
|
||||
/// \brief Same as std::cerr, but uses UTF-8
|
||||
///
|
||||
/// Note, the stream is not synchronized with stdio and not affected by std::ios::sync_with_stdio
|
||||
///
|
||||
extern NOWIDE_DECL details::winconsole_ostream cerr;
|
||||
///
|
||||
/// \brief Same as std::clog, but uses UTF-8
|
||||
///
|
||||
/// Note, the stream is not synchronized with stdio and not affected by std::ios::sync_with_stdio
|
||||
///
|
||||
extern NOWIDE_DECL details::winconsole_ostream clog;
|
||||
|
||||
# endif
|
||||
|
||||
} // namespace nowide
|
||||
|
||||
# ifdef NOWIDE_MSVC
|
||||
# pragma warning(pop)
|
||||
# endif
|
||||
|
||||
#endif
|
||||
///
|
||||
// vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4
|
||||
@@ -0,0 +1,88 @@
|
||||
#ifndef NOWIDE_SCOPED_PTR_HPP
|
||||
# define NOWIDE_SCOPED_PTR_HPP
|
||||
|
||||
// (C) Copyright Greg Colvin and Beman Dawes 1998, 1999.
|
||||
// Copyright (c) 2001, 2002 Peter Dimov,
|
||||
// Copyright (C) 2012 Artyom Beilis
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// http://www.boost.org/libs/smart_ptr/scoped_ptr.htm
|
||||
//
|
||||
|
||||
# include <assert.h>
|
||||
|
||||
namespace nowide
|
||||
{
|
||||
// scoped_ptr mimics a built-in pointer except that it guarantees deletion
|
||||
// of the object pointed to, either on destruction of the scoped_ptr or via
|
||||
// an explicit reset(). scoped_ptr is a simple solution for simple needs;
|
||||
// use shared_ptr or std::auto_ptr if your needs are more complex.
|
||||
|
||||
template<class T>
|
||||
class scoped_ptr // noncopyable
|
||||
{
|
||||
private:
|
||||
T* px;
|
||||
|
||||
scoped_ptr(scoped_ptr const&);
|
||||
scoped_ptr& operator=(scoped_ptr const&);
|
||||
|
||||
typedef scoped_ptr<T> this_type;
|
||||
|
||||
void operator==(scoped_ptr const&) const;
|
||||
void operator!=(scoped_ptr const&) const;
|
||||
|
||||
public:
|
||||
typedef T element_type;
|
||||
|
||||
explicit scoped_ptr(T* p = 0) : px(p) // never throws
|
||||
{}
|
||||
|
||||
~scoped_ptr() // never throws
|
||||
{
|
||||
delete px;
|
||||
}
|
||||
|
||||
void reset(T* p = 0) // never throws
|
||||
{
|
||||
assert(p == 0 || p != px); // catch self-reset errors
|
||||
this_type(p).swap(*this);
|
||||
}
|
||||
|
||||
T& operator*() const // never throws
|
||||
{
|
||||
assert(px != 0);
|
||||
return *px;
|
||||
}
|
||||
|
||||
T* operator->() const // never throws
|
||||
{
|
||||
assert(px != 0);
|
||||
return px;
|
||||
}
|
||||
|
||||
T* get() const // never throws
|
||||
{
|
||||
return px;
|
||||
}
|
||||
|
||||
operator bool() const
|
||||
{
|
||||
return px != 0;
|
||||
}
|
||||
|
||||
void swap(scoped_ptr& b) // never throws
|
||||
{
|
||||
T* tmp = b.px;
|
||||
b.px = px;
|
||||
px = tmp;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace nowide
|
||||
|
||||
#endif
|
||||
// vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4
|
||||
@@ -0,0 +1,143 @@
|
||||
//
|
||||
// Copyright (c) 2012 Artyom Beilis (Tonkikh)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
#ifndef NOWIDE_DETAILS_WIDESTR_H_INCLUDED
|
||||
# define NOWIDE_DETAILS_WIDESTR_H_INCLUDED
|
||||
# include <algorithm>
|
||||
# include <nowide/convert.hpp>
|
||||
# include <string.h>
|
||||
|
||||
namespace nowide
|
||||
{
|
||||
///
|
||||
/// \brief A class that allows to create a temporary wide or narrow UTF strings from
|
||||
/// wide or narrow UTF source.
|
||||
///
|
||||
/// It uses on stack buffer of the string is short enough
|
||||
/// and allocated a buffer on the heap if the size of the buffer is too small
|
||||
///
|
||||
template<typename CharOut = wchar_t, typename CharIn = char, size_t BufferSize = 256>
|
||||
class basic_stackstring
|
||||
{
|
||||
public:
|
||||
static const size_t buffer_size = BufferSize;
|
||||
typedef CharOut output_char;
|
||||
typedef CharIn input_char;
|
||||
|
||||
basic_stackstring(basic_stackstring const& other) : mem_buffer_(0)
|
||||
{
|
||||
clear();
|
||||
if (other.mem_buffer_) {
|
||||
size_t len = 0;
|
||||
while (other.mem_buffer_[len]) len++;
|
||||
mem_buffer_ = new output_char[len + 1];
|
||||
memcpy(mem_buffer_, other.mem_buffer_, sizeof(output_char) * (len + 1));
|
||||
}
|
||||
else {
|
||||
memcpy(buffer_, other.buffer_, buffer_size * sizeof(output_char));
|
||||
}
|
||||
}
|
||||
|
||||
void swap(basic_stackstring& other)
|
||||
{
|
||||
std::swap(mem_buffer_, other.mem_buffer_);
|
||||
for (size_t i = 0; i < buffer_size; i++) std::swap(buffer_[i], other.buffer_[i]);
|
||||
}
|
||||
basic_stackstring& operator=(basic_stackstring const& other)
|
||||
{
|
||||
if (this != &other) {
|
||||
basic_stackstring tmp(other);
|
||||
swap(tmp);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
basic_stackstring() : mem_buffer_(0) {}
|
||||
bool convert(input_char const* input)
|
||||
{
|
||||
return convert(input, details::basic_strend(input));
|
||||
}
|
||||
bool convert(input_char const* begin, input_char const* end)
|
||||
{
|
||||
clear();
|
||||
|
||||
size_t space = get_space(sizeof(input_char), sizeof(output_char), end - begin) + 1;
|
||||
if (space <= buffer_size) {
|
||||
if (basic_convert(buffer_, buffer_size, begin, end)) return true;
|
||||
clear();
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
mem_buffer_ = new output_char[space];
|
||||
if (!basic_convert(mem_buffer_, space, begin, end)) {
|
||||
clear();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
output_char* c_str()
|
||||
{
|
||||
if (mem_buffer_) return mem_buffer_;
|
||||
return buffer_;
|
||||
}
|
||||
output_char const* c_str() const
|
||||
{
|
||||
if (mem_buffer_) return mem_buffer_;
|
||||
return buffer_;
|
||||
}
|
||||
void clear()
|
||||
{
|
||||
if (mem_buffer_) {
|
||||
delete[] mem_buffer_;
|
||||
mem_buffer_ = 0;
|
||||
}
|
||||
buffer_[0] = 0;
|
||||
}
|
||||
~basic_stackstring()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
private:
|
||||
static size_t get_space(size_t insize, size_t outsize, size_t in)
|
||||
{
|
||||
if (insize <= outsize)
|
||||
return in;
|
||||
else if (insize == 2 && outsize == 1)
|
||||
return 3 * in;
|
||||
else if (insize == 4 && outsize == 1)
|
||||
return 4 * in;
|
||||
else // if(insize == 4 && outsize == 2)
|
||||
return 2 * in;
|
||||
}
|
||||
output_char buffer_[buffer_size];
|
||||
output_char* mem_buffer_;
|
||||
}; // basic_stackstring
|
||||
|
||||
///
|
||||
/// Convinience typedef
|
||||
///
|
||||
typedef basic_stackstring<wchar_t, char, 256> wstackstring;
|
||||
///
|
||||
/// Convinience typedef
|
||||
///
|
||||
typedef basic_stackstring<char, wchar_t, 256> stackstring;
|
||||
///
|
||||
/// Convinience typedef
|
||||
///
|
||||
typedef basic_stackstring<wchar_t, char, 16> wshort_stackstring;
|
||||
///
|
||||
/// Convinience typedef
|
||||
///
|
||||
typedef basic_stackstring<char, wchar_t, 16> short_stackstring;
|
||||
|
||||
} // namespace nowide
|
||||
|
||||
#endif
|
||||
///
|
||||
// vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4
|
||||
@@ -0,0 +1,44 @@
|
||||
//
|
||||
// Copyright (c) 2012 Artyom Beilis (Tonkikh)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
#ifndef NOWIDE_CSTDLIB_HPP
|
||||
# define NOWIDE_CSTDLIB_HPP
|
||||
|
||||
# include <errno.h>
|
||||
# include <nowide/stackstring.hpp>
|
||||
# include <stdlib.h>
|
||||
|
||||
namespace nowide
|
||||
{
|
||||
# if !defined(NOWIDE_WINDOWS) && !defined(NOWIDE_DOXYGEN)
|
||||
|
||||
using ::system;
|
||||
|
||||
# else // Windows
|
||||
|
||||
///
|
||||
/// Same as std::system but cmd is UTF-8.
|
||||
///
|
||||
/// If the input is not valid UTF-8, -1 returned and errno set to EINVAL
|
||||
///
|
||||
inline int system(char const* cmd)
|
||||
{
|
||||
if (!cmd) return _wsystem(0);
|
||||
wstackstring wcmd;
|
||||
if (!wcmd.convert(cmd)) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
return _wsystem(wcmd.c_str());
|
||||
}
|
||||
|
||||
# endif
|
||||
} // namespace nowide
|
||||
|
||||
#endif
|
||||
///
|
||||
// vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4
|
||||
+443
@@ -0,0 +1,443 @@
|
||||
//
|
||||
// Copyright (c) 2009-2011 Artyom Beilis (Tonkikh)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
#ifndef NOWIDE_UTF_HPP_INCLUDED
|
||||
# define NOWIDE_UTF_HPP_INCLUDED
|
||||
|
||||
# include <nowide/config.hpp>
|
||||
|
||||
# ifndef NOWIDE_MSVC
|
||||
namespace nowide
|
||||
{
|
||||
namespace utf
|
||||
{
|
||||
typedef unsigned uint32_t;
|
||||
typedef unsigned short uint16_t;
|
||||
typedef unsigned char uint8_t;
|
||||
} // namespace utf
|
||||
} // namespace nowide
|
||||
# else
|
||||
# include <stdint.h>
|
||||
# endif
|
||||
|
||||
namespace nowide
|
||||
{
|
||||
///
|
||||
/// \brief Namespace that holds basic operations on UTF encoded sequences
|
||||
///
|
||||
/// All functions defined in this namespace do not require linking with Boost.Locale library
|
||||
///
|
||||
namespace utf
|
||||
{
|
||||
/// \cond INTERNAL
|
||||
# ifdef __GNUC__
|
||||
# define NOWIDE_LIKELY(x) __builtin_expect((x), 1)
|
||||
# define NOWIDE_UNLIKELY(x) __builtin_expect((x), 0)
|
||||
# else
|
||||
# define NOWIDE_LIKELY(x) (x)
|
||||
# define NOWIDE_UNLIKELY(x) (x)
|
||||
# endif
|
||||
/// \endcond
|
||||
|
||||
///
|
||||
/// \brief The integral type type that can hold a Unicode code point
|
||||
///
|
||||
typedef uint32_t code_point;
|
||||
|
||||
///
|
||||
/// \brief Special constant that defines illegal code point
|
||||
///
|
||||
static const code_point illegal = 0xFFFFFFFFu;
|
||||
|
||||
///
|
||||
/// \brief Special constant that defines incomplete code point
|
||||
///
|
||||
static const code_point incomplete = 0xFFFFFFFEu;
|
||||
|
||||
///
|
||||
/// \brief the function checks if \a v is a valid code point
|
||||
///
|
||||
inline bool is_valid_codepoint(code_point v)
|
||||
{
|
||||
if (v > 0x10FFFF) return false;
|
||||
if (0xD800 <= v && v <= 0xDFFF) // surragates
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
# ifdef NOWIDE_DOXYGEN
|
||||
///
|
||||
/// \brief UTF Traits class - functions to convert UTF sequences to and from Unicode code points
|
||||
///
|
||||
template<typename CharType, int size = sizeof(CharType)>
|
||||
struct utf_traits
|
||||
{
|
||||
///
|
||||
/// The type of the character
|
||||
///
|
||||
typedef CharType char_type;
|
||||
///
|
||||
/// Read one code point from the range [p,e) and return it.
|
||||
///
|
||||
/// - If the sequence that was read is incomplete sequence returns \ref incomplete,
|
||||
/// - If illegal sequence detected returns \ref illegal
|
||||
///
|
||||
/// Requirements
|
||||
///
|
||||
/// - Iterator is valid input iterator
|
||||
///
|
||||
/// Postconditions
|
||||
///
|
||||
/// - p points to the last consumed character
|
||||
///
|
||||
template<typename Iterator>
|
||||
static code_point decode(Iterator& p, Iterator e);
|
||||
|
||||
///
|
||||
/// Maximal width of valid sequence in the code units:
|
||||
///
|
||||
/// - UTF-8 - 4
|
||||
/// - UTF-16 - 2
|
||||
/// - UTF-32 - 1
|
||||
///
|
||||
static const int max_width;
|
||||
///
|
||||
/// The width of specific code point in the code units.
|
||||
///
|
||||
/// Requirement: value is a valid Unicode code point
|
||||
/// Returns value in range [1..max_width]
|
||||
///
|
||||
static int width(code_point value);
|
||||
|
||||
///
|
||||
/// Get the size of the trail part of variable length encoded sequence.
|
||||
///
|
||||
/// Returns -1 if C is not valid lead character
|
||||
///
|
||||
static int trail_length(char_type c);
|
||||
///
|
||||
/// Returns true if c is trail code unit, always false for UTF-32
|
||||
///
|
||||
static bool is_trail(char_type c);
|
||||
///
|
||||
/// Returns true if c is lead code unit, always true of UTF-32
|
||||
///
|
||||
static bool is_lead(char_type c);
|
||||
|
||||
///
|
||||
/// Convert valid Unicode code point \a value to the UTF sequence.
|
||||
///
|
||||
/// Requirements:
|
||||
///
|
||||
/// - \a value is valid code point
|
||||
/// - \a out is an output iterator should be able to accept at least width(value) units
|
||||
///
|
||||
/// Returns the iterator past the last written code unit.
|
||||
///
|
||||
template<typename Iterator>
|
||||
static Iterator encode(code_point getValue, Iterator out);
|
||||
///
|
||||
/// Decodes valid UTF sequence that is pointed by p into code point.
|
||||
///
|
||||
/// If the sequence is invalid or points to end the behavior is undefined
|
||||
///
|
||||
template<typename Iterator>
|
||||
static code_point decode_valid(Iterator& p);
|
||||
};
|
||||
|
||||
# else
|
||||
|
||||
template<typename CharType, int size = sizeof(CharType)>
|
||||
struct utf_traits;
|
||||
|
||||
template<typename CharType>
|
||||
struct utf_traits<CharType, 1>
|
||||
{
|
||||
typedef CharType char_type;
|
||||
|
||||
static int trail_length(char_type ci)
|
||||
{
|
||||
unsigned char c = ci;
|
||||
if (c < 128) return 0;
|
||||
if (NOWIDE_UNLIKELY(c < 194)) return -1;
|
||||
if (c < 224) return 1;
|
||||
if (c < 240) return 2;
|
||||
if (NOWIDE_LIKELY(c <= 244)) return 3;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static const int max_width = 4;
|
||||
|
||||
static int width(code_point value)
|
||||
{
|
||||
if (value <= 0x7F) {
|
||||
return 1;
|
||||
}
|
||||
else if (value <= 0x7FF) {
|
||||
return 2;
|
||||
}
|
||||
else if (NOWIDE_LIKELY(value <= 0xFFFF)) {
|
||||
return 3;
|
||||
}
|
||||
else {
|
||||
return 4;
|
||||
}
|
||||
}
|
||||
|
||||
static bool is_trail(char_type ci)
|
||||
{
|
||||
unsigned char c = ci;
|
||||
return (c & 0xC0) == 0x80;
|
||||
}
|
||||
|
||||
static bool is_lead(char_type ci)
|
||||
{
|
||||
return !is_trail(ci);
|
||||
}
|
||||
|
||||
template<typename Iterator>
|
||||
static code_point decode(Iterator& p, Iterator e)
|
||||
{
|
||||
if (NOWIDE_UNLIKELY(p == e)) return incomplete;
|
||||
|
||||
unsigned char lead = *p++;
|
||||
|
||||
// First byte is fully validated here
|
||||
int trail_size = trail_length(lead);
|
||||
|
||||
if (NOWIDE_UNLIKELY(trail_size < 0)) return illegal;
|
||||
|
||||
//
|
||||
// Ok as only ASCII may be of size = 0
|
||||
// also optimize for ASCII text
|
||||
//
|
||||
if (trail_size == 0) return lead;
|
||||
|
||||
code_point c = lead & ((1 << (6 - trail_size)) - 1);
|
||||
|
||||
// Read the rest
|
||||
unsigned char tmp;
|
||||
switch (trail_size) {
|
||||
case 3:
|
||||
if (NOWIDE_UNLIKELY(p == e)) return incomplete;
|
||||
tmp = *p++;
|
||||
if (!is_trail(tmp)) return illegal;
|
||||
c = (c << 6) | (tmp & 0x3F);
|
||||
case 2:
|
||||
if (NOWIDE_UNLIKELY(p == e)) return incomplete;
|
||||
tmp = *p++;
|
||||
if (!is_trail(tmp)) return illegal;
|
||||
c = (c << 6) | (tmp & 0x3F);
|
||||
case 1:
|
||||
if (NOWIDE_UNLIKELY(p == e)) return incomplete;
|
||||
tmp = *p++;
|
||||
if (!is_trail(tmp)) return illegal;
|
||||
c = (c << 6) | (tmp & 0x3F);
|
||||
}
|
||||
|
||||
// Check code point validity: no surrogates and
|
||||
// valid range
|
||||
if (NOWIDE_UNLIKELY(!is_valid_codepoint(c))) return illegal;
|
||||
|
||||
// make sure it is the most compact representation
|
||||
if (NOWIDE_UNLIKELY(width(c) != trail_size + 1)) return illegal;
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
template<typename Iterator>
|
||||
static code_point decode_valid(Iterator& p)
|
||||
{
|
||||
unsigned char lead = *p++;
|
||||
if (lead < 192) return lead;
|
||||
|
||||
int trail_size;
|
||||
|
||||
if (lead < 224)
|
||||
trail_size = 1;
|
||||
else if (NOWIDE_LIKELY(lead < 240)) // non-BMP rare
|
||||
trail_size = 2;
|
||||
else
|
||||
trail_size = 3;
|
||||
|
||||
code_point c = lead & ((1 << (6 - trail_size)) - 1);
|
||||
|
||||
switch (trail_size) {
|
||||
case 3:
|
||||
c = (c << 6) | (static_cast<unsigned char>(*p++) & 0x3F);
|
||||
case 2:
|
||||
c = (c << 6) | (static_cast<unsigned char>(*p++) & 0x3F);
|
||||
case 1:
|
||||
c = (c << 6) | (static_cast<unsigned char>(*p++) & 0x3F);
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
template<typename Iterator>
|
||||
static Iterator encode(code_point value, Iterator out)
|
||||
{
|
||||
if (value <= 0x7F) {
|
||||
*out++ = static_cast<char_type>(value);
|
||||
}
|
||||
else if (value <= 0x7FF) {
|
||||
*out++ = static_cast<char_type>((value >> 6) | 0xC0);
|
||||
*out++ = static_cast<char_type>((value & 0x3F) | 0x80);
|
||||
}
|
||||
else if (NOWIDE_LIKELY(value <= 0xFFFF)) {
|
||||
*out++ = static_cast<char_type>((value >> 12) | 0xE0);
|
||||
*out++ = static_cast<char_type>(((value >> 6) & 0x3F) | 0x80);
|
||||
*out++ = static_cast<char_type>((value & 0x3F) | 0x80);
|
||||
}
|
||||
else {
|
||||
*out++ = static_cast<char_type>((value >> 18) | 0xF0);
|
||||
*out++ = static_cast<char_type>(((value >> 12) & 0x3F) | 0x80);
|
||||
*out++ = static_cast<char_type>(((value >> 6) & 0x3F) | 0x80);
|
||||
*out++ = static_cast<char_type>((value & 0x3F) | 0x80);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
}; // utf8
|
||||
|
||||
template<typename CharType>
|
||||
struct utf_traits<CharType, 2>
|
||||
{
|
||||
typedef CharType char_type;
|
||||
|
||||
// See RFC 2781
|
||||
static bool is_first_surrogate(uint16_t x)
|
||||
{
|
||||
return 0xD800 <= x && x <= 0xDBFF;
|
||||
}
|
||||
static bool is_second_surrogate(uint16_t x)
|
||||
{
|
||||
return 0xDC00 <= x && x <= 0xDFFF;
|
||||
}
|
||||
static code_point combine_surrogate(uint16_t w1, uint16_t w2)
|
||||
{
|
||||
return ((code_point(w1 & 0x3FF) << 10) | (w2 & 0x3FF)) + 0x10000;
|
||||
}
|
||||
static int trail_length(char_type c)
|
||||
{
|
||||
if (is_first_surrogate(c)) return 1;
|
||||
if (is_second_surrogate(c)) return -1;
|
||||
return 0;
|
||||
}
|
||||
///
|
||||
/// Returns true if c is trail code unit, always false for UTF-32
|
||||
///
|
||||
static bool is_trail(char_type c)
|
||||
{
|
||||
return is_second_surrogate(c);
|
||||
}
|
||||
///
|
||||
/// Returns true if c is lead code unit, always true of UTF-32
|
||||
///
|
||||
static bool is_lead(char_type c)
|
||||
{
|
||||
return !is_second_surrogate(c);
|
||||
}
|
||||
|
||||
template<typename It>
|
||||
static code_point decode(It& current, It last)
|
||||
{
|
||||
if (NOWIDE_UNLIKELY(current == last)) return incomplete;
|
||||
uint16_t w1 = *current++;
|
||||
if (NOWIDE_LIKELY(w1 < 0xD800 || 0xDFFF < w1)) {
|
||||
return w1;
|
||||
}
|
||||
if (w1 > 0xDBFF) return illegal;
|
||||
if (current == last) return incomplete;
|
||||
uint16_t w2 = *current++;
|
||||
if (w2 < 0xDC00 || 0xDFFF < w2) return illegal;
|
||||
return combine_surrogate(w1, w2);
|
||||
}
|
||||
template<typename It>
|
||||
static code_point decode_valid(It& current)
|
||||
{
|
||||
uint16_t w1 = *current++;
|
||||
if (NOWIDE_LIKELY(w1 < 0xD800 || 0xDFFF < w1)) {
|
||||
return w1;
|
||||
}
|
||||
uint16_t w2 = *current++;
|
||||
return combine_surrogate(w1, w2);
|
||||
}
|
||||
|
||||
static const int max_width = 2;
|
||||
static int width(code_point u)
|
||||
{
|
||||
return u >= 0x10000 ? 2 : 1;
|
||||
}
|
||||
template<typename It>
|
||||
static It encode(code_point u, It out)
|
||||
{
|
||||
if (NOWIDE_LIKELY(u <= 0xFFFF)) {
|
||||
*out++ = static_cast<char_type>(u);
|
||||
}
|
||||
else {
|
||||
u -= 0x10000;
|
||||
*out++ = static_cast<char_type>(0xD800 | (u >> 10));
|
||||
*out++ = static_cast<char_type>(0xDC00 | (u & 0x3FF));
|
||||
}
|
||||
return out;
|
||||
}
|
||||
}; // utf16;
|
||||
|
||||
template<typename CharType>
|
||||
struct utf_traits<CharType, 4>
|
||||
{
|
||||
typedef CharType char_type;
|
||||
static int trail_length(char_type c)
|
||||
{
|
||||
if (is_valid_codepoint(c)) return 0;
|
||||
return -1;
|
||||
}
|
||||
static bool is_trail(char_type /*c*/)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
static bool is_lead(char_type /*c*/)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename It>
|
||||
static code_point decode_valid(It& current)
|
||||
{
|
||||
return *current++;
|
||||
}
|
||||
|
||||
template<typename It>
|
||||
static code_point decode(It& current, It last)
|
||||
{
|
||||
if (NOWIDE_UNLIKELY(current == last)) return nowide::utf::incomplete;
|
||||
code_point c = *current++;
|
||||
if (NOWIDE_UNLIKELY(!is_valid_codepoint(c))) return nowide::utf::illegal;
|
||||
return c;
|
||||
}
|
||||
static const int max_width = 1;
|
||||
static int width(code_point /*u*/)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
template<typename It>
|
||||
static It encode(code_point u, It out)
|
||||
{
|
||||
*out++ = static_cast<char_type>(u);
|
||||
return out;
|
||||
}
|
||||
|
||||
}; // utf32
|
||||
|
||||
# endif
|
||||
|
||||
} // namespace utf
|
||||
} // namespace nowide
|
||||
|
||||
#endif
|
||||
|
||||
// vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4
|
||||
@@ -0,0 +1,475 @@
|
||||
//
|
||||
// Copyright (c) 2015 Artyom Beilis (Tonkikh)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
#ifndef NOWIDE_UTF8_CODECVT_HPP
|
||||
# define NOWIDE_UTF8_CODECVT_HPP
|
||||
|
||||
# include <locale>
|
||||
# include <nowide/cstdint.hpp>
|
||||
# include <nowide/static_assert.hpp>
|
||||
# include <nowide/utf.hpp>
|
||||
|
||||
namespace nowide
|
||||
{
|
||||
//
|
||||
// Make sure that mbstate can keep 16 bit of UTF-16 sequence
|
||||
//
|
||||
NOWIDE_STATIC_ASSERT(sizeof(std::mbstate_t) >= 2);
|
||||
|
||||
# if defined _MSC_VER && _MSC_VER < 1700
|
||||
// MSVC do_length is non-standard it counts wide characters instead of narrow and does not change mbstate
|
||||
# define NOWIDE_DO_LENGTH_MBSTATE_CONST
|
||||
# endif
|
||||
|
||||
template<typename CharType, int CharSize = sizeof(CharType)>
|
||||
class utf8_codecvt;
|
||||
|
||||
template<typename CharType>
|
||||
class utf8_codecvt<CharType, 2> : public std::codecvt<CharType, char, std::mbstate_t>
|
||||
{
|
||||
public:
|
||||
utf8_codecvt(size_t refs = 0) : std::codecvt<CharType, char, std::mbstate_t>(refs) {}
|
||||
|
||||
protected:
|
||||
typedef CharType uchar;
|
||||
|
||||
virtual std::codecvt_base::result do_unshift(std::mbstate_t& s, char* from, char* /*to*/, char*& next) const
|
||||
{
|
||||
nowide::uint16_t& state = *reinterpret_cast<nowide::uint16_t*>(&s);
|
||||
# ifdef DEBUG_CODECVT
|
||||
std::cout << "Entering unshift " << std::hex << state << std::dec << std::endl;
|
||||
# endif
|
||||
if (state != 0) return std::codecvt_base::error;
|
||||
next = from;
|
||||
return std::codecvt_base::ok;
|
||||
}
|
||||
virtual int do_encoding() const throw()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
virtual int do_max_length() const throw()
|
||||
{
|
||||
return 4;
|
||||
}
|
||||
virtual bool do_always_noconv() const throw()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual int do_length(std::mbstate_t
|
||||
# ifdef NOWIDE_DO_LENGTH_MBSTATE_CONST
|
||||
const
|
||||
# endif
|
||||
& std_state,
|
||||
char const* from,
|
||||
char const* from_end,
|
||||
size_t max) const
|
||||
{
|
||||
# ifndef NOWIDE_DO_LENGTH_MBSTATE_CONST
|
||||
char const* save_from = from;
|
||||
nowide::uint16_t& state = *reinterpret_cast<nowide::uint16_t*>(&std_state);
|
||||
# else
|
||||
size_t save_max = max;
|
||||
nowide::uint16_t state = *reinterpret_cast<nowide::uint16_t const*>(&std_state);
|
||||
# endif
|
||||
while (max > 0 && from < from_end) {
|
||||
char const* prev_from = from;
|
||||
nowide::uint32_t ch = nowide::utf::utf_traits<char>::decode(from, from_end);
|
||||
if (ch == nowide::utf::incomplete || ch == nowide::utf::illegal) {
|
||||
from = prev_from;
|
||||
break;
|
||||
}
|
||||
max--;
|
||||
if (ch > 0xFFFF) {
|
||||
if (state == 0) {
|
||||
from = prev_from;
|
||||
state = 1;
|
||||
}
|
||||
else {
|
||||
state = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
# ifndef NOWIDE_DO_LENGTH_MBSTATE_CONST
|
||||
return from - save_from;
|
||||
# else
|
||||
return save_max - max;
|
||||
# endif
|
||||
}
|
||||
|
||||
virtual std::codecvt_base::result do_in(std::mbstate_t& std_state,
|
||||
char const* from,
|
||||
char const* from_end,
|
||||
char const*& from_next,
|
||||
uchar* to,
|
||||
uchar* to_end,
|
||||
uchar*& to_next) const
|
||||
{
|
||||
std::codecvt_base::result r = std::codecvt_base::ok;
|
||||
|
||||
// mbstate_t is POD type and should be initialized to 0 (i.a. state = stateT())
|
||||
// according to standard. We use it to keep a flag 0/1 for surrogate pair writing
|
||||
//
|
||||
// if 0 no code above >0xFFFF observed, of 1 a code above 0xFFFF observerd
|
||||
// and first pair is written, but no input consumed
|
||||
nowide::uint16_t& state = *reinterpret_cast<nowide::uint16_t*>(&std_state);
|
||||
while (to < to_end && from < from_end) {
|
||||
# ifdef DEBUG_CODECVT
|
||||
std::cout << "Entering IN--------------" << std::endl;
|
||||
std::cout << "State " << std::hex << state << std::endl;
|
||||
std::cout << "Left in " << std::dec << from_end - from << " out " << to_end - to << std::endl;
|
||||
# endif
|
||||
char const* from_saved = from;
|
||||
|
||||
uint32_t ch = nowide::utf::utf_traits<char>::decode(from, from_end);
|
||||
|
||||
if (ch == nowide::utf::illegal) {
|
||||
from = from_saved;
|
||||
r = std::codecvt_base::error;
|
||||
break;
|
||||
}
|
||||
if (ch == nowide::utf::incomplete) {
|
||||
from = from_saved;
|
||||
r = std::codecvt_base::partial;
|
||||
break;
|
||||
}
|
||||
// Normal codepoints go direcly to stream
|
||||
if (ch <= 0xFFFF) {
|
||||
*to++ = ch;
|
||||
}
|
||||
else {
|
||||
// for other codepoints we do following
|
||||
//
|
||||
// 1. We can't consume our input as we may find ourselfs
|
||||
// in state where all input consumed but not all output written,i.e. only
|
||||
// 1st pair is written
|
||||
// 2. We only write first pair and mark this in the state, we also revert back
|
||||
// the from pointer in order to make sure this codepoint would be read
|
||||
// once again and then we would consume our input together with writing
|
||||
// second surrogate pair
|
||||
ch -= 0x10000;
|
||||
nowide::uint16_t vh = ch >> 10;
|
||||
nowide::uint16_t vl = ch & 0x3FF;
|
||||
nowide::uint16_t w1 = vh + 0xD800;
|
||||
nowide::uint16_t w2 = vl + 0xDC00;
|
||||
if (state == 0) {
|
||||
from = from_saved;
|
||||
*to++ = w1;
|
||||
state = 1;
|
||||
}
|
||||
else {
|
||||
*to++ = w2;
|
||||
state = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
from_next = from;
|
||||
to_next = to;
|
||||
if (r == std::codecvt_base::ok && (from != from_end || state != 0)) r = std::codecvt_base::partial;
|
||||
# ifdef DEBUG_CODECVT
|
||||
std::cout << "Returning ";
|
||||
switch (r) {
|
||||
case std::codecvt_base::ok:
|
||||
std::cout << "ok" << std::endl;
|
||||
break;
|
||||
case std::codecvt_base::partial:
|
||||
std::cout << "partial" << std::endl;
|
||||
break;
|
||||
case std::codecvt_base::error:
|
||||
std::cout << "error" << std::endl;
|
||||
break;
|
||||
default:
|
||||
std::cout << "other" << std::endl;
|
||||
break;
|
||||
}
|
||||
std::cout << "State " << std::hex << state << std::endl;
|
||||
std::cout << "Left in " << std::dec << from_end - from << " out " << to_end - to << std::endl;
|
||||
# endif
|
||||
return r;
|
||||
}
|
||||
|
||||
virtual std::codecvt_base::result do_out(std::mbstate_t& std_state,
|
||||
uchar const* from,
|
||||
uchar const* from_end,
|
||||
uchar const*& from_next,
|
||||
char* to,
|
||||
char* to_end,
|
||||
char*& to_next) const
|
||||
{
|
||||
std::codecvt_base::result r = std::codecvt_base::ok;
|
||||
// mbstate_t is POD type and should be initialized to 0 (i.a. state = stateT())
|
||||
// according to standard. We assume that sizeof(mbstate_t) >=2 in order
|
||||
// to be able to store first observerd surrogate pair
|
||||
//
|
||||
// State: state!=0 - a first surrogate pair was observerd (state = first pair),
|
||||
// we expect the second one to come and then zero the state
|
||||
///
|
||||
nowide::uint16_t& state = *reinterpret_cast<nowide::uint16_t*>(&std_state);
|
||||
while (to < to_end && from < from_end) {
|
||||
# ifdef DEBUG_CODECVT
|
||||
std::cout << "Entering OUT --------------" << std::endl;
|
||||
std::cout << "State " << std::hex << state << std::endl;
|
||||
std::cout << "Left in " << std::dec << from_end - from << " out " << to_end - to << std::endl;
|
||||
# endif
|
||||
nowide::uint32_t ch = 0;
|
||||
if (state != 0) {
|
||||
// if the state idecates that 1st surrogate pair was written
|
||||
// we should make sure that the second one that comes is actually
|
||||
// second surrogate
|
||||
nowide::uint16_t w1 = state;
|
||||
nowide::uint16_t w2 = *from;
|
||||
// we don't forward from as writing may fail to incomplete or
|
||||
// partial conversion
|
||||
if (0xDC00 <= w2 && w2 <= 0xDFFF) {
|
||||
nowide::uint16_t vh = w1 - 0xD800;
|
||||
nowide::uint16_t vl = w2 - 0xDC00;
|
||||
ch = ((uint32_t(vh) << 10) | vl) + 0x10000;
|
||||
}
|
||||
else {
|
||||
// Invalid surrogate
|
||||
r = std::codecvt_base::error;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
ch = *from;
|
||||
if (0xD800 <= ch && ch <= 0xDBFF) {
|
||||
// if this is a first surrogate pair we put
|
||||
// it into the state and consume it, note we don't
|
||||
// go forward as it should be illegal so we increase
|
||||
// the from pointer manually
|
||||
state = ch;
|
||||
from++;
|
||||
continue;
|
||||
}
|
||||
else if (0xDC00 <= ch && ch <= 0xDFFF) {
|
||||
// if we observe second surrogate pair and
|
||||
// first only may be expected we should break from the loop with error
|
||||
// as it is illegal input
|
||||
r = std::codecvt_base::error;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!nowide::utf::is_valid_codepoint(ch)) {
|
||||
r = std::codecvt_base::error;
|
||||
break;
|
||||
}
|
||||
int len = nowide::utf::utf_traits<char>::width(ch);
|
||||
if (to_end - to < len) {
|
||||
r = std::codecvt_base::partial;
|
||||
break;
|
||||
}
|
||||
to = nowide::utf::utf_traits<char>::encode(ch, to);
|
||||
state = 0;
|
||||
from++;
|
||||
}
|
||||
from_next = from;
|
||||
to_next = to;
|
||||
if (r == std::codecvt_base::ok && from != from_end) r = std::codecvt_base::partial;
|
||||
# ifdef DEBUG_CODECVT
|
||||
std::cout << "Returning ";
|
||||
switch (r) {
|
||||
case std::codecvt_base::ok:
|
||||
std::cout << "ok" << std::endl;
|
||||
break;
|
||||
case std::codecvt_base::partial:
|
||||
std::cout << "partial" << std::endl;
|
||||
break;
|
||||
case std::codecvt_base::error:
|
||||
std::cout << "error" << std::endl;
|
||||
break;
|
||||
default:
|
||||
std::cout << "other" << std::endl;
|
||||
break;
|
||||
}
|
||||
std::cout << "State " << std::hex << state << std::endl;
|
||||
std::cout << "Left in " << std::dec << from_end - from << " out " << to_end - to << std::endl;
|
||||
# endif
|
||||
return r;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename CharType>
|
||||
class utf8_codecvt<CharType, 4> : public std::codecvt<CharType, char, std::mbstate_t>
|
||||
{
|
||||
public:
|
||||
utf8_codecvt(size_t refs = 0) : std::codecvt<CharType, char, std::mbstate_t>(refs) {}
|
||||
|
||||
protected:
|
||||
typedef CharType uchar;
|
||||
|
||||
virtual std::codecvt_base::result do_unshift(std::mbstate_t& /*s*/, char* from, char* /*to*/, char*& next) const
|
||||
{
|
||||
next = from;
|
||||
return std::codecvt_base::ok;
|
||||
}
|
||||
virtual int do_encoding() const throw()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
virtual int do_max_length() const throw()
|
||||
{
|
||||
return 4;
|
||||
}
|
||||
virtual bool do_always_noconv() const throw()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual int do_length(std::mbstate_t
|
||||
# ifdef NOWIDE_DO_LENGTH_MBSTATE_CONST
|
||||
const
|
||||
# endif
|
||||
& /*state*/,
|
||||
char const* from,
|
||||
char const* from_end,
|
||||
size_t max) const
|
||||
{
|
||||
# ifndef NOWIDE_DO_LENGTH_MBSTATE_CONST
|
||||
char const* start_from = from;
|
||||
# else
|
||||
size_t save_max = max;
|
||||
# endif
|
||||
|
||||
while (max > 0 && from < from_end) {
|
||||
char const* save_from = from;
|
||||
nowide::uint32_t ch = nowide::utf::utf_traits<char>::decode(from, from_end);
|
||||
if (ch == nowide::utf::incomplete || ch == nowide::utf::illegal) {
|
||||
from = save_from;
|
||||
break;
|
||||
}
|
||||
max--;
|
||||
}
|
||||
# ifndef NOWIDE_DO_LENGTH_MBSTATE_CONST
|
||||
return from - start_from;
|
||||
# else
|
||||
return save_max - max;
|
||||
# endif
|
||||
}
|
||||
|
||||
virtual std::codecvt_base::result do_in(std::mbstate_t& /*state*/,
|
||||
char const* from,
|
||||
char const* from_end,
|
||||
char const*& from_next,
|
||||
uchar* to,
|
||||
uchar* to_end,
|
||||
uchar*& to_next) const
|
||||
{
|
||||
std::codecvt_base::result r = std::codecvt_base::ok;
|
||||
|
||||
// mbstate_t is POD type and should be initialized to 0 (i.a. state = stateT())
|
||||
// according to standard. We use it to keep a flag 0/1 for surrogate pair writing
|
||||
//
|
||||
// if 0 no code above >0xFFFF observed, of 1 a code above 0xFFFF observerd
|
||||
// and first pair is written, but no input consumed
|
||||
while (to < to_end && from < from_end) {
|
||||
# ifdef DEBUG_CODECVT
|
||||
std::cout << "Entering IN--------------" << std::endl;
|
||||
std::cout << "State " << std::hex << state << std::endl;
|
||||
std::cout << "Left in " << std::dec << from_end - from << " out " << to_end - to << std::endl;
|
||||
# endif
|
||||
char const* from_saved = from;
|
||||
|
||||
uint32_t ch = nowide::utf::utf_traits<char>::decode(from, from_end);
|
||||
|
||||
if (ch == nowide::utf::illegal) {
|
||||
r = std::codecvt_base::error;
|
||||
from = from_saved;
|
||||
break;
|
||||
}
|
||||
if (ch == nowide::utf::incomplete) {
|
||||
r = std::codecvt_base::partial;
|
||||
from = from_saved;
|
||||
break;
|
||||
}
|
||||
*to++ = ch;
|
||||
}
|
||||
from_next = from;
|
||||
to_next = to;
|
||||
if (r == std::codecvt_base::ok && from != from_end) r = std::codecvt_base::partial;
|
||||
# ifdef DEBUG_CODECVT
|
||||
std::cout << "Returning ";
|
||||
switch (r) {
|
||||
case std::codecvt_base::ok:
|
||||
std::cout << "ok" << std::endl;
|
||||
break;
|
||||
case std::codecvt_base::partial:
|
||||
std::cout << "partial" << std::endl;
|
||||
break;
|
||||
case std::codecvt_base::error:
|
||||
std::cout << "error" << std::endl;
|
||||
break;
|
||||
default:
|
||||
std::cout << "other" << std::endl;
|
||||
break;
|
||||
}
|
||||
std::cout << "State " << std::hex << state << std::endl;
|
||||
std::cout << "Left in " << std::dec << from_end - from << " out " << to_end - to << std::endl;
|
||||
# endif
|
||||
return r;
|
||||
}
|
||||
|
||||
virtual std::codecvt_base::result do_out(std::mbstate_t& std_state,
|
||||
uchar const* from,
|
||||
uchar const* from_end,
|
||||
uchar const*& from_next,
|
||||
char* to,
|
||||
char* to_end,
|
||||
char*& to_next) const
|
||||
{
|
||||
std::codecvt_base::result r = std::codecvt_base::ok;
|
||||
while (to < to_end && from < from_end) {
|
||||
# ifdef DEBUG_CODECVT
|
||||
std::cout << "Entering OUT --------------" << std::endl;
|
||||
std::cout << "State " << std::hex << state << std::endl;
|
||||
std::cout << "Left in " << std::dec << from_end - from << " out " << to_end - to << std::endl;
|
||||
# endif
|
||||
nowide::uint32_t ch = 0;
|
||||
ch = *from;
|
||||
if (!nowide::utf::is_valid_codepoint(ch)) {
|
||||
r = std::codecvt_base::error;
|
||||
break;
|
||||
}
|
||||
int len = nowide::utf::utf_traits<char>::width(ch);
|
||||
if (to_end - to < len) {
|
||||
r = std::codecvt_base::partial;
|
||||
break;
|
||||
}
|
||||
to = nowide::utf::utf_traits<char>::encode(ch, to);
|
||||
from++;
|
||||
}
|
||||
from_next = from;
|
||||
to_next = to;
|
||||
if (r == std::codecvt_base::ok && from != from_end) r = std::codecvt_base::partial;
|
||||
# ifdef DEBUG_CODECVT
|
||||
std::cout << "Returning ";
|
||||
switch (r) {
|
||||
case std::codecvt_base::ok:
|
||||
std::cout << "ok" << std::endl;
|
||||
break;
|
||||
case std::codecvt_base::partial:
|
||||
std::cout << "partial" << std::endl;
|
||||
break;
|
||||
case std::codecvt_base::error:
|
||||
std::cout << "error" << std::endl;
|
||||
break;
|
||||
default:
|
||||
std::cout << "other" << std::endl;
|
||||
break;
|
||||
}
|
||||
std::cout << "State " << std::hex << state << std::endl;
|
||||
std::cout << "Left in " << std::dec << from_end - from << " out " << to_end - to << std::endl;
|
||||
# endif
|
||||
return r;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace nowide
|
||||
|
||||
#endif
|
||||
///
|
||||
// vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4
|
||||
@@ -0,0 +1,36 @@
|
||||
//
|
||||
// Copyright (c) 2012 Artyom Beilis (Tonkikh)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
#ifndef NOWIDE_WINDOWS_HPP_INCLUDED
|
||||
# define NOWIDE_WINDOWS_HPP_INCLUDED
|
||||
|
||||
# include <stddef.h>
|
||||
|
||||
# ifdef NOWIDE_USE_WINDOWS_H
|
||||
# include <windows.h>
|
||||
# else
|
||||
|
||||
//
|
||||
// These are function prototypes... Allow to to include windows.h
|
||||
//
|
||||
extern "C"
|
||||
{
|
||||
__declspec(dllimport) wchar_t* __stdcall GetEnvironmentStringsW(void);
|
||||
__declspec(dllimport) int __stdcall FreeEnvironmentStringsW(wchar_t*);
|
||||
__declspec(dllimport) wchar_t* __stdcall GetCommandLineW(void);
|
||||
__declspec(dllimport) wchar_t** __stdcall CommandLineToArgvW(wchar_t const*, int*);
|
||||
__declspec(dllimport) unsigned long __stdcall GetLastError();
|
||||
__declspec(dllimport) void* __stdcall LocalFree(void*);
|
||||
__declspec(dllimport) int __stdcall SetEnvironmentVariableW(wchar_t const*, wchar_t const*);
|
||||
__declspec(dllimport) unsigned long __stdcall GetEnvironmentVariableW(wchar_t const*, wchar_t*, unsigned long);
|
||||
}
|
||||
|
||||
# endif
|
||||
|
||||
#endif
|
||||
///
|
||||
// vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4
|
||||
+77
@@ -0,0 +1,77 @@
|
||||
/**
|
||||
* pugixml parser - version 1.11
|
||||
* --------------------------------------------------------
|
||||
* Copyright (C) 2006-2020, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com)
|
||||
* Report bugs and download new versions at https://pugixml.org/
|
||||
*
|
||||
* This library is distributed under the MIT License. See notice at the end
|
||||
* of this file.
|
||||
*
|
||||
* This work is based on the pugxml parser, which is:
|
||||
* Copyright (C) 2003, by Kristen Wegner (kristen@tima.net)
|
||||
*/
|
||||
|
||||
#ifndef HEADER_PUGICONFIG_HPP
|
||||
#define HEADER_PUGICONFIG_HPP
|
||||
|
||||
// Uncomment this to enable wchar_t mode
|
||||
// #define PUGIXML_WCHAR_MODE
|
||||
|
||||
// Uncomment this to enable compact mode
|
||||
// #define PUGIXML_COMPACT
|
||||
|
||||
// Uncomment this to disable XPath
|
||||
#define PUGIXML_NO_XPATH
|
||||
|
||||
// Uncomment this to disable STL
|
||||
// #define PUGIXML_NO_STL
|
||||
|
||||
// Uncomment this to disable exceptions
|
||||
// #define PUGIXML_NO_EXCEPTIONS
|
||||
|
||||
// Set this to control attributes for public classes/functions, i.e.:
|
||||
// #define PUGIXML_API __declspec(dllexport) // to export all public symbols from DLL
|
||||
// #define PUGIXML_CLASS __declspec(dllimport) // to import all classes from DLL
|
||||
// #define PUGIXML_FUNCTION __fastcall // to set calling conventions to all public functions to fastcall
|
||||
// In absence of PUGIXML_CLASS/PUGIXML_FUNCTION definitions PUGIXML_API is used instead
|
||||
|
||||
// Tune these constants to adjust memory-related behavior
|
||||
// #define PUGIXML_MEMORY_PAGE_SIZE 32768
|
||||
// #define PUGIXML_MEMORY_OUTPUT_STACK 10240
|
||||
// #define PUGIXML_MEMORY_XPATH_PAGE_SIZE 4096
|
||||
|
||||
// Tune this constant to adjust max nesting for XPath queries
|
||||
// #define PUGIXML_XPATH_DEPTH_LIMIT 1024
|
||||
|
||||
// Uncomment this to switch to header-only version
|
||||
#define PUGIXML_HEADER_ONLY
|
||||
|
||||
// Uncomment this to enable long long support
|
||||
// #define PUGIXML_HAS_LONG_LONG
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Copyright (c) 2006-2020 Arseny Kapoulkine
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
+13020
File diff suppressed because it is too large
Load Diff
+1499
File diff suppressed because it is too large
Load Diff
+10980
File diff suppressed because it is too large
Load Diff
+345
@@ -0,0 +1,345 @@
|
||||
/*
|
||||
|
||||
____ ____ ___ ____ ____ ____ ___
|
||||
6MMMMb `MM( )M' `MM' 6MMMMb\`MM( )M'
|
||||
8P Y8 `MM. d' MM 6M' ` `MM. d'
|
||||
6M Mb __ ____ ____ ___ __ `MM. d' MM MM `MM. d'
|
||||
MM MM `M6MMMMb 6MMMMb `MM 6MMb `MM. d' MM YM. `MM. d'
|
||||
MM MM MM' `Mb 6M' `Mb MMM9 `Mb `MMd MM YMMMMb `MMd
|
||||
MM MM MM MM MM MM MM' MM dMM. MM `Mb dMM.
|
||||
MM MM MM MM MMMMMMMM MM MM d'`MM. MM MM d'`MM.
|
||||
YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM.
|
||||
8b d8 MM. ,M9 YM d9 MM MM d' `MM. MM / L ,M9 d' `MM.
|
||||
YMMMM9 MMYMMM9 YMMMM9 _MM_ _MM_M(_ _)MM_ _MMMMMMM MYMMMM9 _M(_ _)MM_
|
||||
MM
|
||||
MM
|
||||
_MM_
|
||||
|
||||
Copyright (c) 2022, Kenneth Troldal Balslev
|
||||
|
||||
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.
|
||||
- Neither the name of the author nor the
|
||||
names of any 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 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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef OPENXLSX_IZIPARCHIVE_HPP
|
||||
#define OPENXLSX_IZIPARCHIVE_HPP
|
||||
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4251)
|
||||
#pragma warning(disable : 4275)
|
||||
|
||||
// ===== OpenXLSX Includes ===== //
|
||||
#include "OpenXLSX-Exports.hpp"
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
namespace OpenXLSX
|
||||
{
|
||||
/**
|
||||
* @brief This class functions as a wrapper around any class that provides the necessary functionality for
|
||||
* a zip archive.
|
||||
* @details This class works by applying 'type erasure'. This enables the use of objects of any class, the only
|
||||
* requirement being that it provides the right interface. No inheritance from a base class is needed.
|
||||
*/
|
||||
class OPENXLSX_EXPORT IZipArchive
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Default constructor
|
||||
*/
|
||||
IZipArchive() : m_zipArchive() {} // NOLINT
|
||||
|
||||
/**
|
||||
* @brief Constructor, taking the target object as an argument.
|
||||
* @tparam T The type of the target object (will be auto deducted)
|
||||
* @param x The target object
|
||||
* @note This method is deliberately not marked 'explicit', because as a templated constructor, it should be able
|
||||
* to take any type as an argument. However, only objects that satisfy the required interface can be used.
|
||||
*/
|
||||
template<typename T>
|
||||
IZipArchive(const T& zipArchive) : m_zipArchive { std::make_unique<Model<T>>(zipArchive) } {} // NOLINT
|
||||
|
||||
/**
|
||||
* @brief Copy constructor
|
||||
* @param other
|
||||
*/
|
||||
IZipArchive(const IZipArchive& other) : m_zipArchive(other.m_zipArchive ? other.m_zipArchive->clone() : nullptr) {}
|
||||
|
||||
/**
|
||||
* @brief Move constructor
|
||||
* @param other
|
||||
*/
|
||||
IZipArchive(IZipArchive&& other) noexcept = default;
|
||||
|
||||
/**
|
||||
* @brief Destructor
|
||||
*/
|
||||
~IZipArchive() = default;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @tparam T
|
||||
* @param x
|
||||
* @return
|
||||
*/
|
||||
template<typename T>
|
||||
inline IZipArchive& operator=(const T& zipArchive)
|
||||
{
|
||||
m_zipArchive = std::make_unique<Model<T>>(zipArchive);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param other
|
||||
* @return
|
||||
*/
|
||||
inline IZipArchive& operator=(const IZipArchive& other)
|
||||
{
|
||||
IZipArchive copy(other);
|
||||
*this = std::move(copy);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param other
|
||||
* @return
|
||||
*/
|
||||
inline IZipArchive& operator=(IZipArchive&& other) noexcept = default;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @return
|
||||
*/
|
||||
inline explicit operator bool() const
|
||||
{
|
||||
return isValid();
|
||||
}
|
||||
|
||||
inline bool isValid() const {
|
||||
return m_zipArchive->isValid();
|
||||
|
||||
}
|
||||
|
||||
inline bool isOpen() const {
|
||||
return m_zipArchive->isOpen();
|
||||
}
|
||||
|
||||
inline void open(const std::string& fileName) {
|
||||
m_zipArchive->open(fileName);
|
||||
}
|
||||
|
||||
inline void close() const {
|
||||
m_zipArchive->close();
|
||||
}
|
||||
|
||||
inline void save(const std::string& path) {
|
||||
m_zipArchive->save(path);
|
||||
}
|
||||
|
||||
inline void addEntry(const std::string& name, const std::string& data) {
|
||||
m_zipArchive->addEntry(name, data);
|
||||
}
|
||||
|
||||
inline void deleteEntry(const std::string& entryName) {
|
||||
m_zipArchive->deleteEntry(entryName);
|
||||
}
|
||||
|
||||
inline std::string getEntry(const std::string& name) {
|
||||
return m_zipArchive->getEntry(name);
|
||||
}
|
||||
|
||||
inline bool hasEntry(const std::string& entryName) {
|
||||
return m_zipArchive->hasEntry(entryName);
|
||||
}
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief
|
||||
*/
|
||||
struct Concept
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief
|
||||
*/
|
||||
Concept() = default;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*/
|
||||
Concept(const Concept&) = default;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*/
|
||||
Concept(Concept&&) noexcept = default;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*/
|
||||
virtual ~Concept() = default;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @return
|
||||
*/
|
||||
inline Concept& operator=(const Concept&) = default;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @return
|
||||
*/
|
||||
inline Concept& operator=(Concept&&) noexcept = default;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @return
|
||||
*/
|
||||
inline virtual std::unique_ptr<Concept> clone() const = 0;
|
||||
|
||||
inline virtual bool isValid() const = 0;
|
||||
|
||||
inline virtual bool isOpen() const = 0;
|
||||
|
||||
inline virtual void open(const std::string& fileName) = 0;
|
||||
|
||||
inline virtual void close() = 0;
|
||||
|
||||
inline virtual void save (const std::string& path) = 0;
|
||||
|
||||
inline virtual void addEntry(const std::string& name, const std::string& data) = 0;
|
||||
|
||||
inline virtual void deleteEntry(const std::string& entryName) = 0;
|
||||
|
||||
inline virtual std::string getEntry(const std::string& name) = 0;
|
||||
|
||||
inline virtual bool hasEntry(const std::string& entryName) = 0;
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @tparam T
|
||||
*/
|
||||
template<typename T>
|
||||
struct Model : Concept
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief
|
||||
* @param x
|
||||
*/
|
||||
explicit Model(const T& x) : ZipType(x) {}
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param other
|
||||
*/
|
||||
Model(const Model& other) = default;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param other
|
||||
*/
|
||||
Model(Model&& other) noexcept = default;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*/
|
||||
~Model() override = default;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param other
|
||||
* @return
|
||||
*/
|
||||
inline Model& operator=(const Model& other) = default;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param other
|
||||
* @return
|
||||
*/
|
||||
inline Model& operator=(Model&& other) noexcept = default;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @return
|
||||
*/
|
||||
inline std::unique_ptr<Concept> clone() const override
|
||||
{
|
||||
return std::make_unique<Model<T>>(ZipType);
|
||||
}
|
||||
|
||||
inline bool isValid() const override {
|
||||
return ZipType.isValid();
|
||||
}
|
||||
|
||||
inline bool isOpen() const override {
|
||||
return ZipType.isOpen();
|
||||
}
|
||||
|
||||
inline void open(const std::string& fileName) override {
|
||||
ZipType.open(fileName);
|
||||
}
|
||||
|
||||
inline void close() override {
|
||||
ZipType.close();
|
||||
}
|
||||
|
||||
inline void save(const std::string& path) override {
|
||||
ZipType.save(path);
|
||||
}
|
||||
|
||||
inline void addEntry(const std::string& name, const std::string& data) override {
|
||||
ZipType.addEntry(name, data);
|
||||
}
|
||||
|
||||
inline void deleteEntry(const std::string& entryName) override {
|
||||
ZipType.deleteEntry(entryName);
|
||||
}
|
||||
|
||||
inline std::string getEntry(const std::string& name) override {
|
||||
return ZipType.getEntry(name);
|
||||
}
|
||||
|
||||
inline bool hasEntry(const std::string& entryName) override {
|
||||
return ZipType.hasEntry(entryName);
|
||||
}
|
||||
|
||||
private:
|
||||
T ZipType;
|
||||
};
|
||||
|
||||
std::unique_ptr<Concept> m_zipArchive;
|
||||
};
|
||||
|
||||
} // namespace OpenXLSX
|
||||
|
||||
#pragma warning(pop)
|
||||
#endif // OPENXLSX_IZIPARCHIVE_HPP
|
||||
Vendored
+231
@@ -0,0 +1,231 @@
|
||||
/*
|
||||
|
||||
____ ____ ___ ____ ____ ____ ___
|
||||
6MMMMb `MM( )M' `MM' 6MMMMb\`MM( )M'
|
||||
8P Y8 `MM. d' MM 6M' ` `MM. d'
|
||||
6M Mb __ ____ ____ ___ __ `MM. d' MM MM `MM. d'
|
||||
MM MM `M6MMMMb 6MMMMb `MM 6MMb `MM. d' MM YM. `MM. d'
|
||||
MM MM MM' `Mb 6M' `Mb MMM9 `Mb `MMd MM YMMMMb `MMd
|
||||
MM MM MM MM MM MM MM' MM dMM. MM `Mb dMM.
|
||||
MM MM MM MM MMMMMMMM MM MM d'`MM. MM MM d'`MM.
|
||||
YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM.
|
||||
8b d8 MM. ,M9 YM d9 MM MM d' `MM. MM / L ,M9 d' `MM.
|
||||
YMMMM9 MMYMMM9 YMMMM9 _MM_ _MM_M(_ _)MM_ _MMMMMMM MYMMMM9 _M(_ _)MM_
|
||||
MM
|
||||
MM
|
||||
_MM_
|
||||
|
||||
Copyright (c) 2018, Kenneth Troldal Balslev
|
||||
|
||||
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.
|
||||
- Neither the name of the author nor the
|
||||
names of any 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 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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef OPENXLSX_XLCELL_HPP
|
||||
#define OPENXLSX_XLCELL_HPP
|
||||
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4251)
|
||||
#pragma warning(disable : 4275)
|
||||
|
||||
#include <memory>
|
||||
|
||||
// ===== OpenXLSX Includes ===== //
|
||||
#include "OpenXLSX-Exports.hpp"
|
||||
#include "XLCellReference.hpp"
|
||||
#include "XLCellValue.hpp"
|
||||
#include "XLFormula.hpp"
|
||||
#include "XLSharedStrings.hpp"
|
||||
|
||||
// ========== CLASS AND ENUM TYPE DEFINITIONS ========== //
|
||||
namespace OpenXLSX
|
||||
{
|
||||
class XLCellRange;
|
||||
class XLSharedStrings;
|
||||
|
||||
/**
|
||||
* @brief An implementation class encapsulating the properties and behaviours of a spreadsheet cell.
|
||||
*/
|
||||
class OPENXLSX_EXPORT XLCell
|
||||
{
|
||||
friend class XLCellIterator;
|
||||
friend class XLCellValueProxy;
|
||||
friend class XLRowDataIterator;
|
||||
friend bool operator==(const XLCell& lhs, const XLCell& rhs);
|
||||
friend bool operator!=(const XLCell& lhs, const XLCell& rhs);
|
||||
|
||||
public:
|
||||
//---------- Public Member Functions ----------//
|
||||
|
||||
/**
|
||||
* @brief Default constructor. Constructs a null object.
|
||||
*/
|
||||
XLCell();
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param cellNode
|
||||
* @param sharedStrings
|
||||
*/
|
||||
XLCell(const XMLNode& cellNode, const XLSharedStrings& sharedStrings);
|
||||
|
||||
/**
|
||||
* @brief Copy constructor
|
||||
* @param other The XLCell object to be copied.
|
||||
* @note The copy constructor has been deleted, as it makes no sense to copy a cell. If the objective is to
|
||||
* copy the getValue, create the the target object and then use the copy assignment operator.
|
||||
*/
|
||||
XLCell(const XLCell& other);
|
||||
|
||||
/**
|
||||
* @brief Move constructor
|
||||
* @param other The XLCell object to be moved
|
||||
* @note The move constructor has been deleted, as it makes no sense to move a cell.
|
||||
*/
|
||||
XLCell(XLCell&& other) noexcept;
|
||||
|
||||
/**
|
||||
* @brief Destructor
|
||||
* @note Using the default destructor
|
||||
*/
|
||||
~XLCell();
|
||||
|
||||
/**
|
||||
* @brief Copy assignment operator
|
||||
* @param other The XLCell object to be copy assigned
|
||||
* @return A reference to the new object
|
||||
* @note Copies only the cell contents, not the pointer to parent worksheet etc.
|
||||
*/
|
||||
XLCell& operator=(const XLCell& other);
|
||||
|
||||
/**
|
||||
* @brief Move assignment operator [deleted]
|
||||
* @param other The XLCell object to be move assigned
|
||||
* @return A reference to the new object
|
||||
* @note The move assignment constructor has been deleted, as it makes no sense to move a cell.
|
||||
*/
|
||||
XLCell& operator=(XLCell&& other) noexcept;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @return
|
||||
*/
|
||||
explicit operator bool() const;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @return
|
||||
*/
|
||||
XLCellValueProxy& value();
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @return
|
||||
*/
|
||||
const XLCellValueProxy& value() const;
|
||||
|
||||
/**
|
||||
* @brief get the XLCellReference object for the cell.
|
||||
* @return A reference to the cells' XLCellReference object.
|
||||
*/
|
||||
XLCellReference cellReference() const;
|
||||
|
||||
/**
|
||||
* @brief get the XLCell object from the current cell offset
|
||||
* @return A reference to the XLCell object.
|
||||
*/
|
||||
XLCell offset(uint16_t rowOffset, uint16_t colOffset) const;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @return
|
||||
*/
|
||||
bool hasFormula() const;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @return
|
||||
*/
|
||||
XLFormulaProxy& formula();
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @return
|
||||
*/
|
||||
const XLFormulaProxy& formula() const;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param newFormula
|
||||
*/
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param lhs
|
||||
* @param rhs
|
||||
* @return
|
||||
*/
|
||||
static bool isEqual(const XLCell& lhs, const XLCell& rhs);
|
||||
|
||||
//---------- Private Member Variables ---------- //
|
||||
std::unique_ptr<XMLNode> m_cellNode; /**< A pointer to the root XMLNode for the cell. */
|
||||
XLSharedStrings m_sharedStrings; /**< */
|
||||
XLCellValueProxy m_valueProxy; /**< */
|
||||
XLFormulaProxy m_formulaProxy; /**< */
|
||||
};
|
||||
|
||||
} // namespace OpenXLSX
|
||||
|
||||
// ========== FRIEND FUNCTION IMPLEMENTATIONS ========== //
|
||||
namespace OpenXLSX
|
||||
{
|
||||
/**
|
||||
* @brief
|
||||
* @param lhs
|
||||
* @param rhs
|
||||
* @return
|
||||
*/
|
||||
inline bool operator==(const XLCell& lhs, const XLCell& rhs)
|
||||
{
|
||||
return XLCell::isEqual(lhs, rhs);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param lhs
|
||||
* @param rhs
|
||||
* @return
|
||||
*/
|
||||
inline bool operator!=(const XLCell& lhs, const XLCell& rhs)
|
||||
{
|
||||
return !XLCell::isEqual(lhs, rhs);
|
||||
}
|
||||
|
||||
} // namespace OpenXLSX
|
||||
|
||||
#pragma warning(pop)
|
||||
#endif // OPENXLSX_XLCELL_HPP
|
||||
+179
@@ -0,0 +1,179 @@
|
||||
/*
|
||||
|
||||
____ ____ ___ ____ ____ ____ ___
|
||||
6MMMMb `MM( )M' `MM' 6MMMMb\`MM( )M'
|
||||
8P Y8 `MM. d' MM 6M' ` `MM. d'
|
||||
6M Mb __ ____ ____ ___ __ `MM. d' MM MM `MM. d'
|
||||
MM MM `M6MMMMb 6MMMMb `MM 6MMb `MM. d' MM YM. `MM. d'
|
||||
MM MM MM' `Mb 6M' `Mb MMM9 `Mb `MMd MM YMMMMb `MMd
|
||||
MM MM MM MM MM MM MM' MM dMM. MM `Mb dMM.
|
||||
MM MM MM MM MMMMMMMM MM MM d'`MM. MM MM d'`MM.
|
||||
YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM.
|
||||
8b d8 MM. ,M9 YM d9 MM MM d' `MM. MM / L ,M9 d' `MM.
|
||||
YMMMM9 MMYMMM9 YMMMM9 _MM_ _MM_M(_ _)MM_ _MMMMMMM MYMMMM9 _M(_ _)MM_
|
||||
MM
|
||||
MM
|
||||
_MM_
|
||||
|
||||
Copyright (c) 2018, Kenneth Troldal Balslev
|
||||
|
||||
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.
|
||||
- Neither the name of the author nor the
|
||||
names of any 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 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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef OPENXLSX_XLCELLITERATOR_HPP
|
||||
#define OPENXLSX_XLCELLITERATOR_HPP
|
||||
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4251)
|
||||
#pragma warning(disable : 4275)
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "OpenXLSX-Exports.hpp"
|
||||
#include "XLCell.hpp"
|
||||
#include "XLCellReference.hpp"
|
||||
#include "XLIterator.hpp"
|
||||
#include "XLXmlParser.hpp"
|
||||
|
||||
namespace OpenXLSX
|
||||
{
|
||||
class OPENXLSX_EXPORT XLCellIterator
|
||||
{
|
||||
public:
|
||||
using iterator_category = std::forward_iterator_tag;
|
||||
using value_type = XLCell;
|
||||
using difference_type = int64_t;
|
||||
using pointer = XLCell*;
|
||||
using reference = XLCell&;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param cellRange
|
||||
* @param loc
|
||||
*/
|
||||
explicit XLCellIterator(const XLCellRange& cellRange, XLIteratorLocation loc);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*/
|
||||
~XLCellIterator();
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param other
|
||||
*/
|
||||
XLCellIterator(const XLCellIterator& other);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param other
|
||||
*/
|
||||
[[maybe_unused]] XLCellIterator(XLCellIterator&& other) noexcept;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param other
|
||||
* @return
|
||||
*/
|
||||
XLCellIterator& operator=(const XLCellIterator& other);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param other
|
||||
* @return
|
||||
*/
|
||||
XLCellIterator& operator=(XLCellIterator&& other) noexcept;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @return
|
||||
*/
|
||||
XLCellIterator& operator++();
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @return
|
||||
*/
|
||||
XLCellIterator operator++(int); // NOLINT
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @return
|
||||
*/
|
||||
reference operator*();
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @return
|
||||
*/
|
||||
pointer operator->();
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param rhs
|
||||
* @return
|
||||
*/
|
||||
bool operator==(const XLCellIterator& rhs) const;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param rhs
|
||||
* @return
|
||||
*/
|
||||
bool operator!=(const XLCellIterator& rhs) const;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param last
|
||||
* @return
|
||||
*/
|
||||
uint64_t distance(const XLCellIterator& last);
|
||||
|
||||
private:
|
||||
std::unique_ptr<XMLNode> m_dataNode; /**< */
|
||||
XLCellReference m_topLeft; /**< The cell reference of the first cell in the range */
|
||||
XLCellReference m_bottomRight; /**< The cell reference of the last cell in the range */
|
||||
XLCell m_currentCell; /**< */
|
||||
XLSharedStrings m_sharedStrings; /**< */
|
||||
bool m_endReached { false }; /**< */
|
||||
};
|
||||
|
||||
} // namespace OpenXLSX
|
||||
|
||||
// ===== Template specialization for std::distance.
|
||||
namespace std // NOLINT
|
||||
{
|
||||
using OpenXLSX::XLCellIterator;
|
||||
template<>
|
||||
inline typename std::iterator_traits<XLCellIterator>::difference_type distance<XLCellIterator>(XLCellIterator first,
|
||||
XLCellIterator last)
|
||||
{
|
||||
return static_cast<typename std::iterator_traits<XLCellIterator>::difference_type>(first.distance(last));
|
||||
}
|
||||
} // namespace std
|
||||
|
||||
#pragma warning(pop)
|
||||
#endif // OPENXLSX_XLCELLITERATOR_HPP
|
||||
+169
@@ -0,0 +1,169 @@
|
||||
/*
|
||||
|
||||
____ ____ ___ ____ ____ ____ ___
|
||||
6MMMMb `MM( )M' `MM' 6MMMMb\`MM( )M'
|
||||
8P Y8 `MM. d' MM 6M' ` `MM. d'
|
||||
6M Mb __ ____ ____ ___ __ `MM. d' MM MM `MM. d'
|
||||
MM MM `M6MMMMb 6MMMMb `MM 6MMb `MM. d' MM YM. `MM. d'
|
||||
MM MM MM' `Mb 6M' `Mb MMM9 `Mb `MMd MM YMMMMb `MMd
|
||||
MM MM MM MM MM MM MM' MM dMM. MM `Mb dMM.
|
||||
MM MM MM MM MMMMMMMM MM MM d'`MM. MM MM d'`MM.
|
||||
YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM.
|
||||
8b d8 MM. ,M9 YM d9 MM MM d' `MM. MM / L ,M9 d' `MM.
|
||||
YMMMM9 MMYMMM9 YMMMM9 _MM_ _MM_M(_ _)MM_ _MMMMMMM MYMMMM9 _M(_ _)MM_
|
||||
MM
|
||||
MM
|
||||
_MM_
|
||||
|
||||
Copyright (c) 2018, Kenneth Troldal Balslev
|
||||
|
||||
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.
|
||||
- Neither the name of the author nor the
|
||||
names of any 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 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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef OPENXLSX_XLCELLRANGE_HPP
|
||||
#define OPENXLSX_XLCELLRANGE_HPP
|
||||
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4251)
|
||||
#pragma warning(disable : 4275)
|
||||
|
||||
// ===== External Includes ===== //
|
||||
#include <memory>
|
||||
|
||||
// ===== OpenXLSX Includes ===== //
|
||||
#include "OpenXLSX-Exports.hpp"
|
||||
#include "XLCell.hpp"
|
||||
#include "XLCellIterator.hpp"
|
||||
#include "XLCellReference.hpp"
|
||||
#include "XLXmlParser.hpp"
|
||||
|
||||
namespace OpenXLSX
|
||||
{
|
||||
/**
|
||||
* @brief This class encapsulates the concept of a cell range, i.e. a square area
|
||||
* (or subset) of cells in a spreadsheet.
|
||||
*/
|
||||
class OPENXLSX_EXPORT XLCellRange
|
||||
{
|
||||
friend class XLCellIterator;
|
||||
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
// Public Member Functions
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief
|
||||
* @param dataNode
|
||||
* @param topLeft
|
||||
* @param bottomRight
|
||||
* @param sharedStrings
|
||||
*/
|
||||
explicit XLCellRange(const XMLNode& dataNode,
|
||||
const XLCellReference& topLeft,
|
||||
const XLCellReference& bottomRight,
|
||||
const XLSharedStrings& sharedStrings);
|
||||
|
||||
/**
|
||||
* @brief Copy constructor [default].
|
||||
* @param other The range object to be copied.
|
||||
* @note This implements the default copy constructor, i.e. memberwise copying.
|
||||
*/
|
||||
XLCellRange(const XLCellRange& other);
|
||||
|
||||
/**
|
||||
* @brief Move constructor [default].
|
||||
* @param other The range object to be moved.
|
||||
* @note This implements the default move constructor, i.e. memberwise move.
|
||||
*/
|
||||
XLCellRange(XLCellRange&& other) noexcept;
|
||||
|
||||
/**
|
||||
* @brief Destructor [default]
|
||||
* @note This implements the default destructor.
|
||||
*/
|
||||
~XLCellRange();
|
||||
|
||||
/**
|
||||
* @brief The copy assignment operator [default]
|
||||
* @param other The range object to be copied and assigned.
|
||||
* @return A reference to the new object.
|
||||
* @throws A std::range_error if the source range and destination range are of different size and shape.
|
||||
* @note This implements the default copy assignment operator.
|
||||
*/
|
||||
XLCellRange& operator=(const XLCellRange& other);
|
||||
|
||||
/**
|
||||
* @brief The move assignment operator [default].
|
||||
* @param other The range object to be moved and assigned.
|
||||
* @return A reference to the new object.
|
||||
* @note This implements the default move assignment operator.
|
||||
*/
|
||||
XLCellRange& operator=(XLCellRange&& other) noexcept;
|
||||
|
||||
/**
|
||||
* @brief Get the number of rows in the range.
|
||||
* @return The number of rows.
|
||||
*/
|
||||
uint32_t numRows() const;
|
||||
|
||||
/**
|
||||
* @brief Get the number of columns in the range.
|
||||
* @return The number of columns.
|
||||
*/
|
||||
uint16_t numColumns() const;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @return
|
||||
*/
|
||||
XLCellIterator begin() const;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @return
|
||||
*/
|
||||
XLCellIterator end() const;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*/
|
||||
void clear();
|
||||
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
// Private Member Variables
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
private:
|
||||
std::unique_ptr<XMLNode> m_dataNode; /**< */
|
||||
XLCellReference m_topLeft; /**< The cell reference of the first cell in the range */
|
||||
XLCellReference m_bottomRight; /**< The cell reference of the last cell in the range */
|
||||
XLSharedStrings m_sharedStrings;
|
||||
};
|
||||
} // namespace OpenXLSX
|
||||
|
||||
#pragma warning(pop)
|
||||
#endif // OPENXLSX_XLCELLRANGE_HPP
|
||||
+324
@@ -0,0 +1,324 @@
|
||||
/*
|
||||
|
||||
____ ____ ___ ____ ____ ____ ___
|
||||
6MMMMb `MM( )M' `MM' 6MMMMb\`MM( )M'
|
||||
8P Y8 `MM. d' MM 6M' ` `MM. d'
|
||||
6M Mb __ ____ ____ ___ __ `MM. d' MM MM `MM. d'
|
||||
MM MM `M6MMMMb 6MMMMb `MM 6MMb `MM. d' MM YM. `MM. d'
|
||||
MM MM MM' `Mb 6M' `Mb MMM9 `Mb `MMd MM YMMMMb `MMd
|
||||
MM MM MM MM MM MM MM' MM dMM. MM `Mb dMM.
|
||||
MM MM MM MM MMMMMMMM MM MM d'`MM. MM MM d'`MM.
|
||||
YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM.
|
||||
8b d8 MM. ,M9 YM d9 MM MM d' `MM. MM / L ,M9 d' `MM.
|
||||
YMMMM9 MMYMMM9 YMMMM9 _MM_ _MM_M(_ _)MM_ _MMMMMMM MYMMMM9 _M(_ _)MM_
|
||||
MM
|
||||
MM
|
||||
_MM_
|
||||
|
||||
Copyright (c) 2018, Kenneth Troldal Balslev
|
||||
|
||||
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.
|
||||
- Neither the name of the author nor the
|
||||
names of any 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 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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef OPENXLSX_XLCELLREFERENCE_HPP
|
||||
#define OPENXLSX_XLCELLREFERENCE_HPP
|
||||
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4251)
|
||||
#pragma warning(disable : 4275)
|
||||
|
||||
// ===== External Includes ===== //
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <cstdint>
|
||||
|
||||
// ===== OpenXLSX Includes ===== //
|
||||
#include "OpenXLSX-Exports.hpp"
|
||||
|
||||
namespace OpenXLSX
|
||||
{
|
||||
/**
|
||||
* @brief
|
||||
*/
|
||||
using XLCoordinates = std::pair<uint32_t, uint16_t>;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*/
|
||||
class OPENXLSX_EXPORT XLCellReference final
|
||||
{
|
||||
friend bool operator==(const XLCellReference& lhs, const XLCellReference& rhs);
|
||||
friend bool operator!=(const XLCellReference& lhs, const XLCellReference& rhs);
|
||||
friend bool operator<(const XLCellReference& lhs, const XLCellReference& rhs);
|
||||
friend bool operator>(const XLCellReference& lhs, const XLCellReference& rhs);
|
||||
friend bool operator<=(const XLCellReference& lhs, const XLCellReference& rhs);
|
||||
friend bool operator>=(const XLCellReference& lhs, const XLCellReference& rhs);
|
||||
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
// Public Member Functions
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Constructor taking a cell address as argument.
|
||||
* @param cellAddress The address of the cell, e.g. 'A1'.
|
||||
* @details The constructor creates a new XLCellReference from a string, e.g. 'A1'. If there's no input,
|
||||
* the default reference will be cell A1.
|
||||
*/
|
||||
XLCellReference(const std::string& cellAddress = ""); // NOLINT
|
||||
|
||||
/**
|
||||
* @brief Constructor taking the cell coordinates as arguments.
|
||||
* @param row The row number of the cell.
|
||||
* @param column The column number of the cell.
|
||||
*/
|
||||
XLCellReference(uint32_t row, uint16_t column);
|
||||
|
||||
/**
|
||||
* @brief Constructor taking the row number and the column letter as arguments.
|
||||
* @param row The row number of the cell.
|
||||
* @param column The column letter of the cell.
|
||||
*/
|
||||
XLCellReference(uint32_t row, const std::string& column);
|
||||
|
||||
/**
|
||||
* @brief Copy constructor
|
||||
* @param other The object to be copied.
|
||||
*/
|
||||
XLCellReference(const XLCellReference& other);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param other
|
||||
*/
|
||||
XLCellReference(XLCellReference&& other) noexcept;
|
||||
|
||||
/**
|
||||
* @brief Destructor. Default implementation used.
|
||||
*/
|
||||
~XLCellReference();
|
||||
|
||||
/**
|
||||
* @brief Assignment operator.
|
||||
* @param other The object to be copied/assigned.
|
||||
* @return A reference to the new object.
|
||||
*/
|
||||
XLCellReference& operator=(const XLCellReference& other);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param other
|
||||
* @return
|
||||
*/
|
||||
XLCellReference& operator=(XLCellReference&& other) noexcept;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @return
|
||||
*/
|
||||
XLCellReference& operator++();
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @return
|
||||
*/
|
||||
XLCellReference operator++(int); // NOLINT
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @return
|
||||
*/
|
||||
XLCellReference& operator--();
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @return
|
||||
*/
|
||||
XLCellReference operator--(int); // NOLINT
|
||||
|
||||
/**
|
||||
* @brief Get the row number of the XLCellReference.
|
||||
* @return The row.
|
||||
*/
|
||||
uint32_t row() const;
|
||||
|
||||
/**
|
||||
* @brief Set the row number for the XLCellReference.
|
||||
* @param row The row number.
|
||||
*/
|
||||
void setRow(uint32_t row);
|
||||
|
||||
/**
|
||||
* @brief Get the column number of the XLCellReference.
|
||||
* @return The column number.
|
||||
*/
|
||||
uint16_t column() const;
|
||||
|
||||
/**
|
||||
* @brief Set the column number of the XLCellReference.
|
||||
* @param column The column number.
|
||||
*/
|
||||
void setColumn(uint16_t column);
|
||||
|
||||
/**
|
||||
* @brief Set both row and column number of the XLCellReference.
|
||||
* @param row The row number.
|
||||
* @param column The column number.
|
||||
*/
|
||||
void setRowAndColumn(uint32_t row, uint16_t column);
|
||||
|
||||
/**
|
||||
* @brief Get the address of the XLCellReference
|
||||
* @return The address, e.g. 'A1'
|
||||
*/
|
||||
std::string address() const;
|
||||
|
||||
/**
|
||||
* @brief Set the address of the XLCellReference
|
||||
* @param address The address, e.g. 'A1'
|
||||
* @pre The address input string must be a valid Excel cell reference. Otherwise the behaviour is undefined.
|
||||
*/
|
||||
void setAddress(const std::string& address);
|
||||
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
// Private Member Functions
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
// private:
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param row
|
||||
* @return
|
||||
*/
|
||||
static std::string rowAsString(uint32_t row);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param row
|
||||
* @return
|
||||
*/
|
||||
static uint32_t rowAsNumber(const std::string& row);
|
||||
|
||||
/**
|
||||
* @brief Static helper function to convert column number to column letter (e.g. column 1 becomes 'A')
|
||||
* @param column The column number.
|
||||
* @return The column letter
|
||||
*/
|
||||
static std::string columnAsString(uint16_t column);
|
||||
|
||||
/**
|
||||
* @brief Static helper function to convert column letter to column number (e.g. column 'A' becomes 1)
|
||||
* @param column The column letter, e.g. 'A'
|
||||
* @return The column number.
|
||||
*/
|
||||
static uint16_t columnAsNumber(const std::string& column);
|
||||
|
||||
/**
|
||||
* @brief Static helper function to convert cell address to coordinates.
|
||||
* @param address The address to be converted, e.g. 'A1'
|
||||
* @return A std::pair<row, column>
|
||||
*/
|
||||
static XLCoordinates coordinatesFromAddress(const std::string& address);
|
||||
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
// Private Member Variables
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
private:
|
||||
uint32_t m_row { 1 }; /**< The row */
|
||||
uint16_t m_column { 1 }; /**< The column */
|
||||
std::string m_cellAddress {"A1"}; /**< The address, e.g. 'A1' */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Helper function to check equality between two XLCellReferences.
|
||||
* @param lhs The first XLCellReference
|
||||
* @param rhs The second XLCellReference
|
||||
* @return true if equal; otherwise false.
|
||||
*/
|
||||
inline bool operator==(const XLCellReference& lhs, const XLCellReference& rhs)
|
||||
{
|
||||
return lhs.row() == rhs.row() && lhs.column() == rhs.column();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Helper function to check for in-equality between two XLCellReferences
|
||||
* @param lhs The first XLCellReference
|
||||
* @param rhs The second XLCellReference
|
||||
* @return false if equal; otherwise true.
|
||||
*/
|
||||
inline bool operator!=(const XLCellReference& lhs, const XLCellReference& rhs)
|
||||
{
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Helper function to check if one XLCellReference is smaller than another.
|
||||
* @param lhs The first XLCellReference
|
||||
* @param rhs The second XLCellReference
|
||||
* @return true if lhs < rhs; otherwise false.
|
||||
*/
|
||||
inline bool operator<(const XLCellReference& lhs, const XLCellReference& rhs)
|
||||
{
|
||||
return lhs.row() < rhs.row() || (lhs.row() <= rhs.row() && lhs.column() < rhs.column());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Helper function to check if one XLCellReference is larger than another.
|
||||
* @param lhs The first XLCellReference
|
||||
* @param rhs The second XLCellReference
|
||||
* @return true if lhs > rhs; otherwise false.
|
||||
*/
|
||||
inline bool operator>(const XLCellReference& lhs, const XLCellReference& rhs)
|
||||
{
|
||||
return (rhs < lhs);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Helper function to check if one XLCellReference is smaller than or equal to another.
|
||||
* @param lhs The first XLCellReference
|
||||
* @param rhs The second XLCellReference
|
||||
* @return true if lhs <= rhs; otherwise false
|
||||
*/
|
||||
inline bool operator<=(const XLCellReference& lhs, const XLCellReference& rhs)
|
||||
{
|
||||
return !(lhs > rhs);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Helper function to check if one XLCellReference is larger than or equal to another.
|
||||
* @param lhs The first XLCellReference
|
||||
* @param rhs The second XLCellReference
|
||||
* @return true if lhs >= rhs; otherwise false.
|
||||
*/
|
||||
inline bool operator>=(const XLCellReference& lhs, const XLCellReference& rhs)
|
||||
{
|
||||
return !(lhs < rhs);
|
||||
}
|
||||
} // namespace OpenXLSX
|
||||
|
||||
#pragma warning(pop)
|
||||
#endif // OPENXLSX_XLCELLREFERENCE_HPP
|
||||
+672
@@ -0,0 +1,672 @@
|
||||
/*
|
||||
|
||||
____ ____ ___ ____ ____ ____ ___
|
||||
6MMMMb `MM( )M' `MM' 6MMMMb\`MM( )M'
|
||||
8P Y8 `MM. d' MM 6M' ` `MM. d'
|
||||
6M Mb __ ____ ____ ___ __ `MM. d' MM MM `MM. d'
|
||||
MM MM `M6MMMMb 6MMMMb `MM 6MMb `MM. d' MM YM. `MM. d'
|
||||
MM MM MM' `Mb 6M' `Mb MMM9 `Mb `MMd MM YMMMMb `MMd
|
||||
MM MM MM MM MM MM MM' MM dMM. MM `Mb dMM.
|
||||
MM MM MM MM MMMMMMMM MM MM d'`MM. MM MM d'`MM.
|
||||
YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM.
|
||||
8b d8 MM. ,M9 YM d9 MM MM d' `MM. MM / L ,M9 d' `MM.
|
||||
YMMMM9 MMYMMM9 YMMMM9 _MM_ _MM_M(_ _)MM_ _MMMMMMM MYMMMM9 _M(_ _)MM_
|
||||
MM
|
||||
MM
|
||||
_MM_
|
||||
|
||||
Copyright (c) 2018, Kenneth Troldal Balslev
|
||||
|
||||
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.
|
||||
- Neither the name of the author nor the
|
||||
names of any 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 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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef OPENXLSX_XLCELLVALUE_HPP
|
||||
#define OPENXLSX_XLCELLVALUE_HPP
|
||||
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4251)
|
||||
#pragma warning(disable : 4275)
|
||||
|
||||
// ===== External Includes ===== //
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <variant>
|
||||
|
||||
// ===== OpenXLSX Includes ===== //
|
||||
#include "OpenXLSX-Exports.hpp"
|
||||
#include "XLDateTime.hpp"
|
||||
#include "XLException.hpp"
|
||||
#include "XLXmlParser.hpp"
|
||||
|
||||
// ========== CLASS AND ENUM TYPE DEFINITIONS ========== //
|
||||
namespace OpenXLSX
|
||||
{
|
||||
//---------- Forward Declarations ----------//
|
||||
class XLCellValueProxy;
|
||||
class XLCell;
|
||||
|
||||
/**
|
||||
* @brief Enum defining the valid value types for a an Excel spreadsheet cell.
|
||||
*/
|
||||
enum class XLValueType { Empty, Boolean, Integer, Float, Error, String };
|
||||
|
||||
/**
|
||||
* @brief Class encapsulating a cell value.
|
||||
*/
|
||||
class OPENXLSX_EXPORT XLCellValue
|
||||
{
|
||||
//---------- Friend Declarations ----------//
|
||||
|
||||
// TODO: Consider template functions to compare to ints, floats etc.
|
||||
friend bool operator==(const XLCellValue& lhs, const XLCellValue& rhs);
|
||||
friend bool operator!=(const XLCellValue& lhs, const XLCellValue& rhs);
|
||||
friend bool operator<(const XLCellValue& lhs, const XLCellValue& rhs);
|
||||
friend bool operator>(const XLCellValue& lhs, const XLCellValue& rhs);
|
||||
friend bool operator<=(const XLCellValue& lhs, const XLCellValue& rhs);
|
||||
friend bool operator>=(const XLCellValue& lhs, const XLCellValue& rhs);
|
||||
friend std::ostream& operator<<(std::ostream& os, const XLCellValue& value);
|
||||
friend std::hash<OpenXLSX::XLCellValue>;
|
||||
|
||||
public:
|
||||
//---------- Public Member Functions ----------//
|
||||
|
||||
/**
|
||||
* @brief Default constructor
|
||||
*/
|
||||
XLCellValue();
|
||||
|
||||
/**
|
||||
* @brief A templated constructor. Any value convertible to a valid cell value can be used as argument.
|
||||
* @tparam T The type of the argument (will be automatically deduced).
|
||||
* @param value The value.
|
||||
* @todo Consider changing the enable_if statement to check for objects with a .c_str() member function.
|
||||
*/
|
||||
template<
|
||||
typename T,
|
||||
typename std::enable_if<std::is_integral_v<T> || std::is_floating_point_v<T> || std::is_same_v<std::decay_t<T>, std::string> ||
|
||||
std::is_same_v<std::decay_t<T>, std::string_view> || std::is_same_v<std::decay_t<T>, const char*> ||
|
||||
std::is_same_v<std::decay_t<T>, char*> || std::is_same_v<T, XLDateTime>>::type* = nullptr>
|
||||
XLCellValue(T value) // NOLINT
|
||||
{
|
||||
// ===== If the argument is a bool, set the m_type attribute to Boolean.
|
||||
if constexpr (std::is_integral_v<T> && std::is_same_v<T, bool>) {
|
||||
m_type = XLValueType::Boolean;
|
||||
m_value = value;
|
||||
}
|
||||
|
||||
// ===== If the argument is an integral type, set the m_type attribute to Integer.
|
||||
else if constexpr (std::is_integral_v<T> && !std::is_same_v<T, bool>) {
|
||||
m_type = XLValueType::Integer;
|
||||
m_value = int64_t(value);
|
||||
}
|
||||
|
||||
// ===== If the argument is a string type (i.e. is constructable from *char),
|
||||
// ===== set the m_type attribute to String.
|
||||
else if constexpr (std::is_same_v<std::decay_t<T>, std::string> || std::is_same_v<std::decay_t<T>, std::string_view> ||
|
||||
std::is_same_v<std::decay_t<T>, const char*> ||
|
||||
(std::is_same_v<std::decay_t<T>, char*> && !std::is_same_v<T, bool>))
|
||||
{
|
||||
m_type = XLValueType::String;
|
||||
m_value = std::string(value);
|
||||
}
|
||||
|
||||
// ===== If the argument is an XLDateTime, set the value to the date/time serial number.
|
||||
else if constexpr (std::is_same_v<T, XLDateTime>) {
|
||||
m_type = XLValueType::Float;
|
||||
m_value = value.serial();
|
||||
}
|
||||
|
||||
// ===== If the argument is a floating point type, set the m_type attribute to Float.
|
||||
// ===== If not, a static_assert will result in compilation error.
|
||||
else {
|
||||
static_assert(std::is_floating_point_v<T>, "Invalid argument for constructing XLCellValue object");
|
||||
if (std::isfinite(value)) {
|
||||
m_type = XLValueType::Float;
|
||||
m_value = double(value);
|
||||
}
|
||||
else {
|
||||
m_type = XLValueType::Error;
|
||||
m_value = std::string("#NUM!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Copy constructor.
|
||||
* @param other The object to be copied.
|
||||
*/
|
||||
XLCellValue(const XLCellValue& other);
|
||||
|
||||
/**
|
||||
* @brief Move constructor.
|
||||
* @param other The object to be moved.
|
||||
*/
|
||||
XLCellValue(XLCellValue&& other) noexcept;
|
||||
|
||||
/**
|
||||
* @brief Destructor
|
||||
*/
|
||||
~XLCellValue();
|
||||
|
||||
/**
|
||||
* @brief Copy assignment operator.
|
||||
* @param other Object to be copied.
|
||||
* @return Reference to the copied-to object.
|
||||
*/
|
||||
XLCellValue& operator=(const XLCellValue& other);
|
||||
|
||||
/**
|
||||
* @brief Move assignment operator.
|
||||
* @param other Object to be moved.
|
||||
* @return Reference to the moved-to object.
|
||||
*/
|
||||
XLCellValue& operator=(XLCellValue&& other) noexcept;
|
||||
|
||||
/**
|
||||
* @brief Templated copy assignment operator.
|
||||
* @tparam T The type of the value argument.
|
||||
* @param value The value.
|
||||
* @return A reference to the assigned-to object.
|
||||
*/
|
||||
template<
|
||||
typename T,
|
||||
typename std::enable_if<std::is_integral_v<T> || std::is_floating_point_v<T> || std::is_same_v<std::decay_t<T>, std::string> ||
|
||||
std::is_same_v<std::decay_t<T>, std::string_view> || std::is_same_v<std::decay_t<T>, const char*> ||
|
||||
std::is_same_v<std::decay_t<T>, char*> || std::is_same_v<T, XLDateTime>>::type* = nullptr>
|
||||
XLCellValue& operator=(T value)
|
||||
{
|
||||
// ===== Implemented using copy-and-swap.
|
||||
XLCellValue temp(value);
|
||||
std::swap(*this, temp);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Templated setter for integral and bool types.
|
||||
* @tparam T The type of the value argument.
|
||||
* @param numberValue The value
|
||||
*/
|
||||
template<
|
||||
typename T,
|
||||
typename std::enable_if<std::is_same_v<T, XLCellValue> || std::is_integral_v<T> || std::is_floating_point_v<T> ||
|
||||
std::is_same_v<std::decay_t<T>, std::string> || std::is_same_v<std::decay_t<T>, std::string_view> ||
|
||||
std::is_same_v<std::decay_t<T>, const char*> || std::is_same_v<std::decay_t<T>, char*> ||
|
||||
std::is_same_v<T, XLDateTime>>::type* = nullptr>
|
||||
void set(T numberValue)
|
||||
{
|
||||
// ===== Implemented using the assignment operator.
|
||||
*this = numberValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Templated getter.
|
||||
* @tparam T The type of the value to be returned.
|
||||
* @return The value as a type T object.
|
||||
* @throws XLValueTypeError if the XLCellValue object does not contain a compatible type.
|
||||
*/
|
||||
template<
|
||||
typename T,
|
||||
typename std::enable_if<std::is_integral_v<T> || std::is_floating_point_v<T> || std::is_same_v<std::decay_t<T>, std::string> ||
|
||||
std::is_same_v<std::decay_t<T>, std::string_view> || std::is_same_v<std::decay_t<T>, const char*> ||
|
||||
std::is_same_v<std::decay_t<T>, char*> || std::is_same_v<T, XLDateTime>>::type* = nullptr>
|
||||
T get() const
|
||||
{
|
||||
try {
|
||||
if constexpr (std::is_integral_v<T> && std::is_same_v<T, bool>) return std::get<bool>(m_value);
|
||||
|
||||
if constexpr (std::is_integral_v<T> && !std::is_same_v<T, bool>) return static_cast<T>(std::get<int64_t>(m_value));
|
||||
|
||||
if constexpr (std::is_floating_point_v<T>) {
|
||||
if (m_type == XLValueType::Error) return std::nan("1");
|
||||
return static_cast<T>(std::get<double>(m_value));
|
||||
}
|
||||
|
||||
if constexpr (std::is_same_v<std::decay_t<T>, std::string> || std::is_same_v<std::decay_t<T>, std::string_view> ||
|
||||
std::is_same_v<std::decay_t<T>, const char*> ||
|
||||
(std::is_same_v<std::decay_t<T>, char*> && !std::is_same_v<T, bool>))
|
||||
return std::get<std::string>(m_value).c_str();
|
||||
|
||||
if constexpr (std::is_same_v<T, XLDateTime>) return XLDateTime(std::get<double>(m_value));
|
||||
}
|
||||
|
||||
catch (const std::bad_variant_access& ) {
|
||||
throw XLValueTypeError("XLCellValue object does not contain the requested type.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Explicit conversion operator for easy conversion to supported types.
|
||||
* @tparam T The type to cast to.
|
||||
* @return The XLCellValue object cast to requested type.
|
||||
* @throws XLValueTypeError if the XLCellValue object does not contain a compatible type.
|
||||
*/
|
||||
template<
|
||||
typename T,
|
||||
typename std::enable_if<std::is_integral_v<T> || std::is_floating_point_v<T> || std::is_same_v<std::decay_t<T>, std::string> ||
|
||||
std::is_same_v<std::decay_t<T>, std::string_view> || std::is_same_v<std::decay_t<T>, const char*> ||
|
||||
std::is_same_v<std::decay_t<T>, char*> || std::is_same_v<T, XLDateTime>>::type* = nullptr>
|
||||
operator T() const
|
||||
{
|
||||
return this->get<T>();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Clears the contents of the XLCellValue object.
|
||||
* @return Returns a reference to the current object.
|
||||
*/
|
||||
XLCellValue& clear();
|
||||
|
||||
/**
|
||||
* @brief Sets the value type to XLValueType::Error.
|
||||
* @return Returns a reference to the current object.
|
||||
*/
|
||||
XLCellValue& setError(const std::string &error);
|
||||
|
||||
/**
|
||||
* @brief Get the value type of the current object.
|
||||
* @return An XLValueType for the current object.
|
||||
*/
|
||||
XLValueType type() const;
|
||||
|
||||
/**
|
||||
* @brief Get the value type of the current object, as a string representation
|
||||
* @return A std::string representation of the value type.
|
||||
*/
|
||||
std::string typeAsString() const;
|
||||
|
||||
private:
|
||||
//---------- Private Member Variables ---------- //
|
||||
|
||||
std::variant<std::string, int64_t, double, bool> m_value { std::string("") }; /**< The value contained in the cell. */
|
||||
XLValueType m_type { XLValueType::Empty }; /**< The value type of the cell. */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief The XLCellValueProxy class is used for proxy (or placeholder) objects for XLCellValue objects.
|
||||
* @details The XLCellValueProxy class is used for proxy (or placeholder) objects for XLCellValue objects.
|
||||
* The purpose is to enable implicit conversion during assignment operations. XLCellValueProxy objects
|
||||
* can not be constructed manually by the user, only through XLCell objects.
|
||||
*/
|
||||
class OPENXLSX_EXPORT XLCellValueProxy
|
||||
{
|
||||
friend class XLCell;
|
||||
friend class XLCellValue;
|
||||
|
||||
public:
|
||||
//---------- Public Member Functions ----------//
|
||||
|
||||
/**
|
||||
* @brief Destructor
|
||||
*/
|
||||
~XLCellValueProxy();
|
||||
|
||||
/**
|
||||
* @brief Copy assignment operator.
|
||||
* @param other XLCellValueProxy object to be copied.
|
||||
* @return A reference to the current object.
|
||||
*/
|
||||
XLCellValueProxy& operator=(const XLCellValueProxy& other);
|
||||
|
||||
/**
|
||||
* @brief Templated assignment operator
|
||||
* @tparam T The type of numberValue assigned to the object.
|
||||
* @param value The value.
|
||||
* @return A reference to the current object.
|
||||
*/
|
||||
template<
|
||||
typename T,
|
||||
typename std::enable_if<std::is_integral_v<T> || std::is_floating_point_v<T> || std::is_same_v<std::decay_t<T>, std::string> ||
|
||||
std::is_same_v<std::decay_t<T>, std::string_view> || std::is_same_v<std::decay_t<T>, const char*> ||
|
||||
std::is_same_v<std::decay_t<T>, char*> || std::is_same_v<T, XLCellValue> ||
|
||||
std::is_same_v<T, XLDateTime>>::type* = nullptr>
|
||||
XLCellValueProxy& operator=(T value)
|
||||
{ // NOLINT
|
||||
|
||||
if constexpr (std::is_integral_v<T> && std::is_same_v<T, bool>) // if bool
|
||||
setBoolean(value);
|
||||
|
||||
else if constexpr (std::is_integral_v<T> && !std::is_same_v<T, bool>) // if integer
|
||||
setInteger(value);
|
||||
|
||||
else if constexpr (std::is_floating_point_v<T>) // if floating point
|
||||
setFloat(value);
|
||||
|
||||
else if constexpr (std::is_same_v<T, XLDateTime>)
|
||||
setFloat(value.serial());
|
||||
|
||||
else if constexpr (std::is_same_v<std::decay_t<T>, std::string> || std::is_same_v<std::decay_t<T>, std::string_view> ||
|
||||
std::is_same_v<std::decay_t<T>, const char*> ||
|
||||
(std::is_same_v<std::decay_t<T>, char*> && !std::is_same_v<T, bool> && !std::is_same_v<T, XLCellValue>))
|
||||
{
|
||||
if constexpr (std::is_same_v<std::decay_t<T>, const char*> || std::is_same_v<std::decay_t<T>, char*>)
|
||||
setString(value);
|
||||
else if constexpr (std::is_same_v<std::decay_t<T>, std::string_view>)
|
||||
setString(std::string(value).c_str());
|
||||
else
|
||||
setString(value.c_str());
|
||||
}
|
||||
|
||||
if constexpr (std::is_same_v<T, XLCellValue>) {
|
||||
switch (value.type()) {
|
||||
case XLValueType::Boolean:
|
||||
setBoolean(value.template get<bool>());
|
||||
break;
|
||||
case XLValueType::Integer:
|
||||
setInteger(value.template get<int64_t>());
|
||||
break;
|
||||
case XLValueType::Float:
|
||||
setFloat(value.template get<double>());
|
||||
break;
|
||||
case XLValueType::String:
|
||||
setString(value.template get<const char*>());
|
||||
break;
|
||||
case XLValueType::Empty:
|
||||
clear();
|
||||
break;
|
||||
default:
|
||||
setError("#N/A");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @tparam T
|
||||
* @param value
|
||||
*/
|
||||
template<
|
||||
typename T,
|
||||
typename std::enable_if<std::is_integral_v<T> || std::is_floating_point_v<T> || std::is_same_v<std::decay_t<T>, std::string> ||
|
||||
std::is_same_v<std::decay_t<T>, std::string_view> || std::is_same_v<std::decay_t<T>, const char*> ||
|
||||
std::is_same_v<std::decay_t<T>, char*> || std::is_same_v<T, XLCellValue> ||
|
||||
std::is_same_v<T, XLDateTime>>::type* = nullptr>
|
||||
void set(T value)
|
||||
{
|
||||
*this = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @tparam T
|
||||
* @return
|
||||
* @todo Is an explicit conversion operator needed as well?
|
||||
*/
|
||||
template<
|
||||
typename T,
|
||||
typename std::enable_if<std::is_integral_v<T> || std::is_floating_point_v<T> || std::is_same_v<std::decay_t<T>, std::string> ||
|
||||
std::is_same_v<std::decay_t<T>, std::string_view> || std::is_same_v<std::decay_t<T>, const char*> ||
|
||||
std::is_same_v<std::decay_t<T>, char*> || std::is_same_v<T, XLDateTime>>::type* = nullptr>
|
||||
T get() const
|
||||
{
|
||||
return getValue().get<T>();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Clear the contents of the cell.
|
||||
* @return A reference to the current object.
|
||||
*/
|
||||
XLCellValueProxy& clear();
|
||||
|
||||
/**
|
||||
* @brief Set the cell value to a error state.
|
||||
* @return A reference to the current object.
|
||||
*/
|
||||
XLCellValueProxy& setError(const std::string & error);
|
||||
|
||||
/**
|
||||
* @brief Get the value type for the cell.
|
||||
* @return An XLCellValue corresponding to the cell value.
|
||||
*/
|
||||
XLValueType type() const;
|
||||
|
||||
/**
|
||||
* @brief Get the value type of the current object, as a string representation
|
||||
* @return A std::string representation of the value type.
|
||||
*/
|
||||
std::string typeAsString() const;
|
||||
|
||||
/**
|
||||
* @brief Implicitly convert the XLCellValueProxy object to a XLCellValue object.
|
||||
* @return An XLCellValue object, corresponding to the cell value.
|
||||
*/
|
||||
operator XLCellValue(); // NOLINT
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @tparam T
|
||||
* @return
|
||||
*/
|
||||
template<
|
||||
typename T,
|
||||
typename std::enable_if<std::is_integral_v<T> || std::is_floating_point_v<T> || std::is_same_v<std::decay_t<T>, std::string> ||
|
||||
std::is_same_v<std::decay_t<T>, std::string_view> || std::is_same_v<std::decay_t<T>, const char*> ||
|
||||
std::is_same_v<std::decay_t<T>, char*> || std::is_same_v<T, XLDateTime>>::type* = nullptr>
|
||||
operator T() const
|
||||
{
|
||||
return getValue().get<T>();
|
||||
}
|
||||
|
||||
private:
|
||||
//---------- Private Member Functions ---------- //
|
||||
|
||||
/**
|
||||
* @brief Constructor
|
||||
* @param cell Pointer to the parent XLCell object.
|
||||
* @param cellNode Pointer to the corresponding XMLNode object.
|
||||
*/
|
||||
XLCellValueProxy(XLCell* cell, XMLNode* cellNode);
|
||||
|
||||
/**
|
||||
* @brief Copy constructor
|
||||
* @param other Object to be copied.
|
||||
*/
|
||||
XLCellValueProxy(const XLCellValueProxy& other);
|
||||
|
||||
/**
|
||||
* @brief Move constructor
|
||||
* @param other Object to be moved.
|
||||
*/
|
||||
XLCellValueProxy(XLCellValueProxy&& other) noexcept;
|
||||
|
||||
/**
|
||||
* @brief Move assignment operator
|
||||
* @param other Object to be moved
|
||||
* @return Reference to moved-to pbject.
|
||||
*/
|
||||
XLCellValueProxy& operator=(XLCellValueProxy&& other) noexcept;
|
||||
|
||||
/**
|
||||
* @brief Set cell to an integer value.
|
||||
* @param numberValue The value to be set.
|
||||
*/
|
||||
void setInteger(int64_t numberValue);
|
||||
|
||||
/**
|
||||
* @brief Set the cell to a bool value.
|
||||
* @param numberValue The value to be set.
|
||||
*/
|
||||
void setBoolean(bool numberValue);
|
||||
|
||||
/**
|
||||
* @brief Set the cell to a floating point value.
|
||||
* @param numberValue The value to be set.
|
||||
*/
|
||||
void setFloat(double numberValue);
|
||||
|
||||
/**
|
||||
* @brief Set the cell to a string value.
|
||||
* @param stringValue The value to be set.
|
||||
*/
|
||||
void setString(const char* stringValue);
|
||||
|
||||
/**
|
||||
* @brief Get a copy of the XLCellValue object for the cell.
|
||||
* @return An XLCellValue object.
|
||||
*/
|
||||
XLCellValue getValue() const;
|
||||
|
||||
//---------- Private Member Variables ---------- //
|
||||
|
||||
XLCell* m_cell; /**< Pointer to the owning XLCell object. */
|
||||
XMLNode* m_cellNode; /**< Pointer to corresponding XML cell node. */
|
||||
};
|
||||
|
||||
} // namespace OpenXLSX
|
||||
|
||||
// TODO: Consider comparison operators on fundamental datatypes
|
||||
// ========== FRIEND FUNCTION IMPLEMENTATIONS ========== //
|
||||
namespace OpenXLSX
|
||||
{
|
||||
/**
|
||||
* @brief
|
||||
* @param lhs
|
||||
* @param rhs
|
||||
* @return
|
||||
*/
|
||||
inline bool operator==(const XLCellValue& lhs, const XLCellValue& rhs)
|
||||
{
|
||||
return lhs.m_value == rhs.m_value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param lhs
|
||||
* @param rhs
|
||||
* @return
|
||||
*/
|
||||
inline bool operator!=(const XLCellValue& lhs, const XLCellValue& rhs)
|
||||
{
|
||||
return lhs.m_value != rhs.m_value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param lhs
|
||||
* @param rhs
|
||||
* @return
|
||||
*/
|
||||
inline bool operator<(const XLCellValue& lhs, const XLCellValue& rhs)
|
||||
{
|
||||
return lhs.m_value < rhs.m_value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param lhs
|
||||
* @param rhs
|
||||
* @return
|
||||
*/
|
||||
inline bool operator>(const XLCellValue& lhs, const XLCellValue& rhs)
|
||||
{
|
||||
return lhs.m_value > rhs.m_value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param lhs
|
||||
* @param rhs
|
||||
* @return
|
||||
*/
|
||||
inline bool operator<=(const XLCellValue& lhs, const XLCellValue& rhs)
|
||||
{
|
||||
return lhs.m_value <= rhs.m_value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param lhs
|
||||
* @param rhs
|
||||
* @return
|
||||
*/
|
||||
inline bool operator>=(const XLCellValue& lhs, const XLCellValue& rhs)
|
||||
{
|
||||
return lhs.m_value >= rhs.m_value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param os
|
||||
* @param value
|
||||
* @return
|
||||
*/
|
||||
inline std::ostream& operator<<(std::ostream& os, const XLCellValue& value)
|
||||
{
|
||||
switch (value.type()) {
|
||||
case XLValueType::Empty:
|
||||
return os << "";
|
||||
case XLValueType::Boolean:
|
||||
return os << value.get<bool>();
|
||||
case XLValueType::Integer:
|
||||
return os << value.get<int64_t>();
|
||||
case XLValueType::Float:
|
||||
return os << value.get<double>();
|
||||
case XLValueType::String:
|
||||
return os << value.get<std::string_view>();
|
||||
default:
|
||||
return os << "";
|
||||
}
|
||||
}
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& os, const XLCellValueProxy& value)
|
||||
{
|
||||
switch (value.type()) {
|
||||
case XLValueType::Empty:
|
||||
return os << "";
|
||||
case XLValueType::Boolean:
|
||||
return os << value.get<bool>();
|
||||
case XLValueType::Integer:
|
||||
return os << value.get<int64_t>();
|
||||
case XLValueType::Float:
|
||||
return os << value.get<double>();
|
||||
case XLValueType::String:
|
||||
return os << value.get<std::string_view>();
|
||||
default:
|
||||
return os << "";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} // namespace OpenXLSX
|
||||
|
||||
namespace std
|
||||
{
|
||||
template<>
|
||||
struct hash<OpenXLSX::XLCellValue> // NOLINT
|
||||
{
|
||||
std::size_t operator()(const OpenXLSX::XLCellValue& value) const noexcept
|
||||
{
|
||||
return std::hash<std::variant<std::string, int64_t, double, bool>> {}(value.m_value);
|
||||
}
|
||||
};
|
||||
} // namespace std
|
||||
|
||||
#pragma warning(pop)
|
||||
#endif // OPENXLSX_XLCELLVALUE_HPP
|
||||
Vendored
+230
@@ -0,0 +1,230 @@
|
||||
/*
|
||||
|
||||
____ ____ ___ ____ ____ ____ ___
|
||||
6MMMMb `MM( )M' `MM' 6MMMMb\`MM( )M'
|
||||
8P Y8 `MM. d' MM 6M' ` `MM. d'
|
||||
6M Mb __ ____ ____ ___ __ `MM. d' MM MM `MM. d'
|
||||
MM MM `M6MMMMb 6MMMMb `MM 6MMb `MM. d' MM YM. `MM. d'
|
||||
MM MM MM' `Mb 6M' `Mb MMM9 `Mb `MMd MM YMMMMb `MMd
|
||||
MM MM MM MM MM MM MM' MM dMM. MM `Mb dMM.
|
||||
MM MM MM MM MMMMMMMM MM MM d'`MM. MM MM d'`MM.
|
||||
YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM.
|
||||
8b d8 MM. ,M9 YM d9 MM MM d' `MM. MM / L ,M9 d' `MM.
|
||||
YMMMM9 MMYMMM9 YMMMM9 _MM_ _MM_M(_ _)MM_ _MMMMMMM MYMMMM9 _M(_ _)MM_
|
||||
MM
|
||||
MM
|
||||
_MM_
|
||||
|
||||
Copyright (c) 2018, Kenneth Troldal Balslev
|
||||
|
||||
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.
|
||||
- Neither the name of the author nor the
|
||||
names of any 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 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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef OPENXLSX_XLCOLOR_HPP
|
||||
#define OPENXLSX_XLCOLOR_HPP
|
||||
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4251)
|
||||
#pragma warning(disable : 4275)
|
||||
|
||||
// ===== External Includes ===== //
|
||||
#include <string>
|
||||
#include <cstdint>
|
||||
|
||||
// ===== OpenXLSX Includes ===== //
|
||||
#include "OpenXLSX-Exports.hpp"
|
||||
|
||||
namespace OpenXLSX
|
||||
{
|
||||
/**
|
||||
* @brief
|
||||
*/
|
||||
class OPENXLSX_EXPORT XLColor
|
||||
{
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
// Public Member Functions
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
friend bool operator==(const XLColor& lhs, const XLColor& rhs);
|
||||
friend bool operator!=(const XLColor& lhs, const XLColor& rhs);
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief
|
||||
*/
|
||||
XLColor();
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param alpha
|
||||
* @param red
|
||||
* @param green
|
||||
* @param blue
|
||||
*/
|
||||
XLColor(uint8_t alpha, uint8_t red, uint8_t green, uint8_t blue);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param red
|
||||
* @param green
|
||||
* @param blue
|
||||
*/
|
||||
XLColor(uint8_t red, uint8_t green, uint8_t blue);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param hexCode
|
||||
*/
|
||||
explicit XLColor(const std::string& hexCode);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param other
|
||||
*/
|
||||
XLColor(const XLColor& other);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param other
|
||||
*/
|
||||
XLColor(XLColor&& other) noexcept;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*/
|
||||
~XLColor();
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param other
|
||||
* @return
|
||||
*/
|
||||
XLColor& operator=(const XLColor& other);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param other
|
||||
* @return
|
||||
*/
|
||||
XLColor& operator=(XLColor&& other) noexcept;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param alpha
|
||||
* @param red
|
||||
* @param green
|
||||
* @param blue
|
||||
*/
|
||||
void set(uint8_t alpha, uint8_t red, uint8_t green, uint8_t blue);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param red
|
||||
* @param green
|
||||
* @param blue
|
||||
*/
|
||||
void set(uint8_t red = 0, uint8_t green = 0, uint8_t blue = 0);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param hexCode
|
||||
*/
|
||||
void set(const std::string& hexCode);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @return
|
||||
*/
|
||||
uint8_t alpha() const;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @return
|
||||
*/
|
||||
uint8_t red() const;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @return
|
||||
*/
|
||||
uint8_t green() const;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @return
|
||||
*/
|
||||
uint8_t blue() const;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @return
|
||||
*/
|
||||
std::string hex() const;
|
||||
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
// Private Member Variables
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
private:
|
||||
uint8_t m_alpha { 255 };
|
||||
|
||||
uint8_t m_red { 0 };
|
||||
|
||||
uint8_t m_green { 0 };
|
||||
|
||||
uint8_t m_blue { 0 };
|
||||
};
|
||||
|
||||
} // namespace OpenXLSX
|
||||
|
||||
namespace OpenXLSX
|
||||
{
|
||||
/**
|
||||
* @brief
|
||||
* @param lhs
|
||||
* @param rhs
|
||||
* @return
|
||||
*/
|
||||
inline bool operator==(const XLColor& lhs, const XLColor& rhs)
|
||||
{
|
||||
return lhs.alpha() == rhs.alpha() && lhs.red() == rhs.red() && lhs.green() == rhs.green() && lhs.blue() == rhs.blue();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param lhs
|
||||
* @param rhs
|
||||
* @return
|
||||
*/
|
||||
inline bool operator!=(const XLColor& lhs, const XLColor& rhs)
|
||||
{
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
} // namespace OpenXLSX
|
||||
|
||||
#pragma warning(pop)
|
||||
#endif // OPENXLSX_XLCOLOR_HPP
|
||||
Vendored
+139
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
|
||||
____ ____ ___ ____ ____ ____ ___
|
||||
6MMMMb `MM( )M' `MM' 6MMMMb\`MM( )M'
|
||||
8P Y8 `MM. d' MM 6M' ` `MM. d'
|
||||
6M Mb __ ____ ____ ___ __ `MM. d' MM MM `MM. d'
|
||||
MM MM `M6MMMMb 6MMMMb `MM 6MMb `MM. d' MM YM. `MM. d'
|
||||
MM MM MM' `Mb 6M' `Mb MMM9 `Mb `MMd MM YMMMMb `MMd
|
||||
MM MM MM MM MM MM MM' MM dMM. MM `Mb dMM.
|
||||
MM MM MM MM MMMMMMMM MM MM d'`MM. MM MM d'`MM.
|
||||
YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM.
|
||||
8b d8 MM. ,M9 YM d9 MM MM d' `MM. MM / L ,M9 d' `MM.
|
||||
YMMMM9 MMYMMM9 YMMMM9 _MM_ _MM_M(_ _)MM_ _MMMMMMM MYMMMM9 _M(_ _)MM_
|
||||
MM
|
||||
MM
|
||||
_MM_
|
||||
|
||||
Copyright (c) 2018, Kenneth Troldal Balslev
|
||||
|
||||
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.
|
||||
- Neither the name of the author nor the
|
||||
names of any 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 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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef OPENXLSX_XLCOLUMN_HPP
|
||||
#define OPENXLSX_XLCOLUMN_HPP
|
||||
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4251)
|
||||
#pragma warning(disable : 4275)
|
||||
|
||||
// ===== External Includes ===== //
|
||||
#include <memory>
|
||||
|
||||
// ===== OpenXLSX Includes ===== //
|
||||
#include "OpenXLSX-Exports.hpp"
|
||||
#include "XLXmlParser.hpp"
|
||||
|
||||
namespace OpenXLSX
|
||||
{
|
||||
/**
|
||||
* @brief
|
||||
*/
|
||||
class OPENXLSX_EXPORT XLColumn
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Constructor
|
||||
* @param columnNode A pointer to the XMLNode for the column.
|
||||
*/
|
||||
explicit XLColumn(const XMLNode& columnNode);
|
||||
|
||||
/**
|
||||
* @brief Copy Constructor [deleted]
|
||||
*/
|
||||
XLColumn(const XLColumn& other);
|
||||
|
||||
/**
|
||||
* @brief Move Constructor
|
||||
* @note The move constructor has been explicitly deleted.
|
||||
*/
|
||||
XLColumn(XLColumn&& other) noexcept;
|
||||
|
||||
/**
|
||||
* @brief Destructor
|
||||
*/
|
||||
~XLColumn();
|
||||
|
||||
/**
|
||||
* @brief Copy assignment operator [deleted]
|
||||
*/
|
||||
XLColumn& operator=(const XLColumn& other);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param other
|
||||
* @return
|
||||
*/
|
||||
XLColumn& operator=(XLColumn&& other) noexcept = default;
|
||||
|
||||
/**
|
||||
* @brief Get the width of the column.
|
||||
* @return The width of the column.
|
||||
*/
|
||||
float width() const;
|
||||
|
||||
/**
|
||||
* @brief Set the width of the column
|
||||
* @param width The width of the column
|
||||
*/
|
||||
void setWidth(float width);
|
||||
|
||||
/**
|
||||
* @brief Is the column hidden?
|
||||
* @return The state of the column.
|
||||
*/
|
||||
bool isHidden() const;
|
||||
|
||||
/**
|
||||
* @brief Set the column to be shown or hidden.
|
||||
* @param state The state of the column.
|
||||
*/
|
||||
void setHidden(bool state);
|
||||
|
||||
/**
|
||||
* @brief Get the XMLNode object for the column.
|
||||
* @return The XMLNode for the column
|
||||
*/
|
||||
XMLNode& columnNode() const;
|
||||
|
||||
private:
|
||||
std::unique_ptr<XMLNode> m_columnNode; /**< A pointer to the XMLNode object for the column. */
|
||||
};
|
||||
|
||||
} // namespace OpenXLSX
|
||||
|
||||
#pragma warning(pop)
|
||||
#endif // OPENXLSX_XLCOLUMN_HPP
|
||||
+224
@@ -0,0 +1,224 @@
|
||||
/*
|
||||
|
||||
____ ____ ___ ____ ____ ____ ___
|
||||
6MMMMb `MM( )M' `MM' 6MMMMb\`MM( )M'
|
||||
8P Y8 `MM. d' MM 6M' ` `MM. d'
|
||||
6M Mb __ ____ ____ ___ __ `MM. d' MM MM `MM. d'
|
||||
MM MM `M6MMMMb 6MMMMb `MM 6MMb `MM. d' MM YM. `MM. d'
|
||||
MM MM MM' `Mb 6M' `Mb MMM9 `Mb `MMd MM YMMMMb `MMd
|
||||
MM MM MM MM MM MM MM' MM dMM. MM `Mb dMM.
|
||||
MM MM MM MM MMMMMMMM MM MM d'`MM. MM MM d'`MM.
|
||||
YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM.
|
||||
8b d8 MM. ,M9 YM d9 MM MM d' `MM. MM / L ,M9 d' `MM.
|
||||
YMMMM9 MMYMMM9 YMMMM9 _MM_ _MM_M(_ _)MM_ _MMMMMMM MYMMMM9 _M(_ _)MM_
|
||||
MM
|
||||
MM
|
||||
_MM_
|
||||
|
||||
Copyright (c) 2018, Kenneth Troldal Balslev
|
||||
|
||||
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.
|
||||
- Neither the name of the author nor the
|
||||
names of any 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 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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef OPENXLSX_XLCOMMANDQUERY_HPP
|
||||
#define OPENXLSX_XLCOMMANDQUERY_HPP
|
||||
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4251)
|
||||
#pragma warning(disable : 4275)
|
||||
|
||||
// ===== External Includes ===== //
|
||||
#include <any>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <variant>
|
||||
|
||||
// ===== OpenXLSX Includes ===== //
|
||||
#include "XLXmlData.hpp"
|
||||
#include "XLSharedStrings.hpp"
|
||||
|
||||
namespace OpenXLSX
|
||||
{
|
||||
/**
|
||||
* @brief
|
||||
*/
|
||||
enum class XLCommandType {
|
||||
SetSheetName,
|
||||
SetSheetColor,
|
||||
SetSheetVisibility,
|
||||
SetSheetIndex,
|
||||
SetSheetActive,
|
||||
ResetCalcChain,
|
||||
AddSharedStrings,
|
||||
AddWorksheet,
|
||||
AddChartsheet,
|
||||
DeleteSheet,
|
||||
CloneSheet,
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*/
|
||||
class XLCommand
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param type
|
||||
*/
|
||||
explicit XLCommand(XLCommandType type) : m_type(type) {}
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @tparam T
|
||||
* @param param
|
||||
* @param value
|
||||
* @return
|
||||
*/
|
||||
template<typename T>
|
||||
XLCommand& setParam(const std::string& param, T value) {
|
||||
m_params[param] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @tparam T
|
||||
* @param param
|
||||
* @return
|
||||
*/
|
||||
template<typename T>
|
||||
T getParam(const std::string& param) const {
|
||||
return std::any_cast<T>(m_params.at(param));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @return
|
||||
*/
|
||||
XLCommandType type() const {
|
||||
return m_type;
|
||||
}
|
||||
|
||||
private:
|
||||
XLCommandType m_type; /*< */
|
||||
std::map<std::string, std::any> m_params; /*< */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*/
|
||||
enum class XLQueryType {
|
||||
QuerySheetName,
|
||||
QuerySheetIndex,
|
||||
QuerySheetVisibility,
|
||||
QuerySheetIsActive,
|
||||
QuerySheetType,
|
||||
QuerySheetID,
|
||||
QuerySheetRelsID,
|
||||
QuerySheetRelsTarget,
|
||||
QuerySharedStrings,
|
||||
QueryXmlData
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*/
|
||||
class XLQuery
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param type
|
||||
*/
|
||||
explicit XLQuery(XLQueryType type) : m_type(type) {}
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @tparam T
|
||||
* @param param
|
||||
* @param value
|
||||
* @return
|
||||
*/
|
||||
template<typename T>
|
||||
XLQuery& setParam(const std::string& param, T value) {
|
||||
m_params[param] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @tparam T
|
||||
* @param param
|
||||
* @return
|
||||
*/
|
||||
template<typename T>
|
||||
T getParam(const std::string& param) const {
|
||||
return std::any_cast<T>(m_params.at(param));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @tparam T
|
||||
* @param value
|
||||
* @return
|
||||
*/
|
||||
template<typename T>
|
||||
XLQuery& setResult(T value) {
|
||||
m_result = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @tparam T
|
||||
* @return
|
||||
*/
|
||||
template<typename T>
|
||||
T result() const {
|
||||
return std::any_cast<T>(m_result);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @return
|
||||
*/
|
||||
XLQueryType type() const {
|
||||
return m_type;
|
||||
}
|
||||
|
||||
private:
|
||||
XLQueryType m_type; /*< */
|
||||
std::any m_result; /*< */
|
||||
std::map<std::string, std::any> m_params; /*< */
|
||||
};
|
||||
|
||||
} // namespace OpenXLSX
|
||||
|
||||
#pragma warning(pop)
|
||||
#endif // OPENXLSX_XLCOMMANDQUERY_HPP
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
//
|
||||
// Created by Kenneth Balslev on 15/08/2021.
|
||||
//
|
||||
|
||||
#ifndef OPENXLSX_XLCONSTANTS_HPP
|
||||
#define OPENXLSX_XLCONSTANTS_HPP
|
||||
|
||||
namespace OpenXLSX
|
||||
{
|
||||
inline const uint16_t MAX_COLS = 16'384;
|
||||
inline const uint32_t MAX_ROWS = 1'048'576;
|
||||
} // namespace OpenXLSX
|
||||
|
||||
#endif // OPENXLSX_XLCONSTANTS_HPP
|
||||
+251
@@ -0,0 +1,251 @@
|
||||
/*
|
||||
|
||||
____ ____ ___ ____ ____ ____ ___
|
||||
6MMMMb `MM( )M' `MM' 6MMMMb\`MM( )M'
|
||||
8P Y8 `MM. d' MM 6M' ` `MM. d'
|
||||
6M Mb __ ____ ____ ___ __ `MM. d' MM MM `MM. d'
|
||||
MM MM `M6MMMMb 6MMMMb `MM 6MMb `MM. d' MM YM. `MM. d'
|
||||
MM MM MM' `Mb 6M' `Mb MMM9 `Mb `MMd MM YMMMMb `MMd
|
||||
MM MM MM MM MM MM MM' MM dMM. MM `Mb dMM.
|
||||
MM MM MM MM MMMMMMMM MM MM d'`MM. MM MM d'`MM.
|
||||
YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM.
|
||||
8b d8 MM. ,M9 YM d9 MM MM d' `MM. MM / L ,M9 d' `MM.
|
||||
YMMMM9 MMYMMM9 YMMMM9 _MM_ _MM_M(_ _)MM_ _MMMMMMM MYMMMM9 _M(_ _)MM_
|
||||
MM
|
||||
MM
|
||||
_MM_
|
||||
|
||||
Copyright (c) 2018, Kenneth Troldal Balslev
|
||||
|
||||
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.
|
||||
- Neither the name of the author nor the
|
||||
names of any 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 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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef OPENXLSX_XLCONTENTTYPES_HPP
|
||||
#define OPENXLSX_XLCONTENTTYPES_HPP
|
||||
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4251)
|
||||
#pragma warning(disable : 4275)
|
||||
|
||||
// ===== External Includes ===== //
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
// ===== OpenXLSX Includes ===== //
|
||||
#include "OpenXLSX-Exports.hpp"
|
||||
#include "XLXmlFile.hpp"
|
||||
#include "XLXmlParser.hpp"
|
||||
|
||||
namespace OpenXLSX
|
||||
{
|
||||
/**
|
||||
* @brief
|
||||
*/
|
||||
enum class XLContentType {
|
||||
Workbook,
|
||||
WorkbookMacroEnabled,
|
||||
Worksheet,
|
||||
Chartsheet,
|
||||
ExternalLink,
|
||||
Theme,
|
||||
Styles,
|
||||
SharedStrings,
|
||||
Drawing,
|
||||
Chart,
|
||||
ChartStyle,
|
||||
ChartColorStyle,
|
||||
ControlProperties,
|
||||
CalculationChain,
|
||||
VBAProject,
|
||||
CoreProperties,
|
||||
ExtendedProperties,
|
||||
CustomProperties,
|
||||
Comments,
|
||||
Table,
|
||||
VMLDrawing,
|
||||
Unknown
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*/
|
||||
class OPENXLSX_EXPORT XLContentItem
|
||||
{
|
||||
friend class XLContentTypes;
|
||||
|
||||
public: // ---------- Public Member Functions ---------- //
|
||||
/**
|
||||
* @brief
|
||||
*/
|
||||
XLContentItem();
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param node
|
||||
*/
|
||||
explicit XLContentItem(const XMLNode& node);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*/
|
||||
~XLContentItem();
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param other
|
||||
* @return
|
||||
*/
|
||||
XLContentItem(const XLContentItem& other);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param other
|
||||
* @return
|
||||
*/
|
||||
XLContentItem(XLContentItem&& other) noexcept;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param other
|
||||
* @return
|
||||
*/
|
||||
XLContentItem& operator=(const XLContentItem& other);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param other
|
||||
* @return
|
||||
*/
|
||||
XLContentItem& operator=(XLContentItem&& other) noexcept;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @return
|
||||
*/
|
||||
XLContentType type() const;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @return
|
||||
*/
|
||||
std::string path() const;
|
||||
|
||||
private:
|
||||
std::unique_ptr<XMLNode> m_contentNode; /**< */
|
||||
};
|
||||
|
||||
// ================================================================================
|
||||
// XLContentTypes Class
|
||||
// ================================================================================
|
||||
|
||||
/**
|
||||
* @brief The purpose of this class is to load, store add and save item in the [Content_Types].xml file.
|
||||
*/
|
||||
class OPENXLSX_EXPORT XLContentTypes : public XLXmlFile
|
||||
{
|
||||
public: // ---------- Public Member Functions ---------- //
|
||||
/**
|
||||
* @brief
|
||||
*/
|
||||
XLContentTypes();
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param xmlData
|
||||
*/
|
||||
explicit XLContentTypes(XLXmlData* xmlData);
|
||||
|
||||
/**
|
||||
* @brief Destructor
|
||||
*/
|
||||
~XLContentTypes();
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param other
|
||||
*/
|
||||
XLContentTypes(const XLContentTypes& other);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param other
|
||||
*/
|
||||
XLContentTypes(XLContentTypes&& other) noexcept;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param other
|
||||
* @return
|
||||
*/
|
||||
XLContentTypes& operator=(const XLContentTypes& other);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param other
|
||||
* @return
|
||||
*/
|
||||
XLContentTypes& operator=(XLContentTypes&& other) noexcept;
|
||||
|
||||
/**
|
||||
* @brief Add a new override key/getValue pair to the data store.
|
||||
* @param path The key
|
||||
* @param type The getValue
|
||||
*/
|
||||
void addOverride(const std::string& path, XLContentType type);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param path
|
||||
*/
|
||||
void deleteOverride(const std::string& path);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param item
|
||||
*/
|
||||
void deleteOverride(XLContentItem& item);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param path
|
||||
* @return
|
||||
*/
|
||||
XLContentItem contentItem(const std::string& path);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @return
|
||||
*/
|
||||
std::vector<XLContentItem> getContentItems();
|
||||
|
||||
// ---------- Protected Member Functions ---------- //
|
||||
};
|
||||
} // namespace OpenXLSX
|
||||
|
||||
#pragma warning(pop)
|
||||
#endif // OPENXLSX_XLCONTENTTYPES_HPP
|
||||
+173
@@ -0,0 +1,173 @@
|
||||
/*
|
||||
|
||||
____ ____ ___ ____ ____ ____ ___
|
||||
6MMMMb `MM( )M' `MM' 6MMMMb\`MM( )M'
|
||||
8P Y8 `MM. d' MM 6M' ` `MM. d'
|
||||
6M Mb __ ____ ____ ___ __ `MM. d' MM MM `MM. d'
|
||||
MM MM `M6MMMMb 6MMMMb `MM 6MMb `MM. d' MM YM. `MM. d'
|
||||
MM MM MM' `Mb 6M' `Mb MMM9 `Mb `MMd MM YMMMMb `MMd
|
||||
MM MM MM MM MM MM MM' MM dMM. MM `Mb dMM.
|
||||
MM MM MM MM MMMMMMMM MM MM d'`MM. MM MM d'`MM.
|
||||
YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM.
|
||||
8b d8 MM. ,M9 YM d9 MM MM d' `MM. MM / L ,M9 d' `MM.
|
||||
YMMMM9 MMYMMM9 YMMMM9 _MM_ _MM_M(_ _)MM_ _MMMMMMM MYMMMM9 _M(_ _)MM_
|
||||
MM
|
||||
MM
|
||||
_MM_
|
||||
|
||||
Copyright (c) 2018, Kenneth Troldal Balslev
|
||||
|
||||
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.
|
||||
- Neither the name of the author nor the
|
||||
names of any 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 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.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#ifndef OPENXLSX_XLDATETIME_HPP
|
||||
#define OPENXLSX_XLDATETIME_HPP
|
||||
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4251)
|
||||
#pragma warning(disable : 4275)
|
||||
|
||||
// ===== External Includes ===== //
|
||||
#include <ctime>
|
||||
|
||||
// ===== OpenXLSX Includes ===== //
|
||||
#include "OpenXLSX-Exports.hpp"
|
||||
#include "XLException.hpp"
|
||||
|
||||
// ========== CLASS AND ENUM TYPE DEFINITIONS ========== //
|
||||
namespace OpenXLSX
|
||||
{
|
||||
class OPENXLSX_EXPORT XLDateTime
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief Constructor.
|
||||
*/
|
||||
XLDateTime();
|
||||
|
||||
/**
|
||||
* @brief Constructor taking an Excel time point serial number as an argument.
|
||||
* @param serial Excel time point serial number.
|
||||
*/
|
||||
explicit XLDateTime(double serial);
|
||||
|
||||
/**
|
||||
* @brief Constructor taking a std::tm struct as an argument.
|
||||
* @param timepoint A std::tm struct.
|
||||
*/
|
||||
explicit XLDateTime(const std::tm& timepoint);
|
||||
|
||||
/**
|
||||
* @brief Constructor taking a unixtime format (seconds since 1/1/1970) as an argument.
|
||||
* @param unixtime A time_t number.
|
||||
*/
|
||||
explicit XLDateTime(time_t unixtime);
|
||||
|
||||
/**
|
||||
* @brief Copy constructor.
|
||||
* @param other Object to be copied.
|
||||
*/
|
||||
XLDateTime(const XLDateTime& other);
|
||||
|
||||
/**
|
||||
* @brief Move constructor.
|
||||
* @param other Object to be moved.
|
||||
*/
|
||||
XLDateTime(XLDateTime&& other) noexcept;
|
||||
|
||||
/**
|
||||
* @brief Destructor
|
||||
*/
|
||||
~XLDateTime();
|
||||
|
||||
/**
|
||||
* @brief Copy assignment operator.
|
||||
* @param other Object to be copied.
|
||||
* @return Reference to the copied-to object.
|
||||
*/
|
||||
XLDateTime& operator=(const XLDateTime& other);
|
||||
|
||||
/**
|
||||
* @brief Move assignment operator.
|
||||
* @param other Object to be moved.
|
||||
* @return Reference to the moved-to object.
|
||||
*/
|
||||
XLDateTime& operator=(XLDateTime&& other) noexcept;
|
||||
|
||||
/**
|
||||
* @brief Assignment operator taking an Excel date/time serial number as an argument.
|
||||
* @param serial A floating point value with the serial number.
|
||||
* @return Reference to the copied-to object.
|
||||
*/
|
||||
XLDateTime& operator=(double serial);
|
||||
|
||||
/**
|
||||
* @brief Assignment operator taking a std::tm object as an argument.
|
||||
* @param timepoint std::tm object with the time point
|
||||
* @return Reference to the copied-to object.
|
||||
*/
|
||||
XLDateTime& operator=(const std::tm& timepoint);
|
||||
|
||||
/**
|
||||
* @brief Implicit conversion to Excel date/time serial number (any floating point type).
|
||||
* @tparam T Type to convert to (any floating point type).
|
||||
* @return Excel date/time serial number.
|
||||
*/
|
||||
template<typename T,
|
||||
typename std::enable_if<std::is_floating_point_v<T> >::type* = nullptr>
|
||||
operator T() const // NOLINT
|
||||
{
|
||||
return serial();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Implicit conversion to std::tm object.
|
||||
* @return std::tm object.
|
||||
*/
|
||||
operator std::tm() const; // NOLINT
|
||||
|
||||
/**
|
||||
* @brief Get the date/time in the form of an Excel date/time serial number.
|
||||
* @return A double with the serial number.
|
||||
*/
|
||||
double serial() const;
|
||||
|
||||
/**
|
||||
* @brief Get the date/time in the form of a std::tm struct.
|
||||
* @return A std::tm struct with the time point.
|
||||
*/
|
||||
std::tm tm() const;
|
||||
|
||||
private:
|
||||
double m_serial {1.0}; /**< */
|
||||
|
||||
|
||||
};
|
||||
} // namespace OpenXLSX
|
||||
|
||||
#endif // OPENXLSX_XLDATETIME_HPP
|
||||
+320
@@ -0,0 +1,320 @@
|
||||
/*
|
||||
|
||||
____ ____ ___ ____ ____ ____ ___
|
||||
6MMMMb `MM( )M' `MM' 6MMMMb\`MM( )M'
|
||||
8P Y8 `MM. d' MM 6M' ` `MM. d'
|
||||
6M Mb __ ____ ____ ___ __ `MM. d' MM MM `MM. d'
|
||||
MM MM `M6MMMMb 6MMMMb `MM 6MMb `MM. d' MM YM. `MM. d'
|
||||
MM MM MM' `Mb 6M' `Mb MMM9 `Mb `MMd MM YMMMMb `MMd
|
||||
MM MM MM MM MM MM MM' MM dMM. MM `Mb dMM.
|
||||
MM MM MM MM MMMMMMMM MM MM d'`MM. MM MM d'`MM.
|
||||
YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM.
|
||||
8b d8 MM. ,M9 YM d9 MM MM d' `MM. MM / L ,M9 d' `MM.
|
||||
YMMMM9 MMYMMM9 YMMMM9 _MM_ _MM_M(_ _)MM_ _MMMMMMM MYMMMM9 _M(_ _)MM_
|
||||
MM
|
||||
MM
|
||||
_MM_
|
||||
|
||||
Copyright (c) 2018, Kenneth Troldal Balslev
|
||||
|
||||
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.
|
||||
- Neither the name of the author nor the
|
||||
names of any 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 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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef OPENXLSX_XLDOCUMENT_HPP
|
||||
#define OPENXLSX_XLDOCUMENT_HPP
|
||||
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4251)
|
||||
#pragma warning(disable : 4275)
|
||||
|
||||
// ===== External Includes ===== //
|
||||
#include <algorithm>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
// ===== OpenXLSX Includes ===== //
|
||||
#include "IZipArchive.hpp"
|
||||
#include "OpenXLSX-Exports.hpp"
|
||||
#include "XLCommandQuery.hpp"
|
||||
#include "XLContentTypes.hpp"
|
||||
#include "XLException.hpp"
|
||||
#include "XLProperties.hpp"
|
||||
#include "XLRelationships.hpp"
|
||||
#include "XLSharedStrings.hpp"
|
||||
#include "XLWorkbook.hpp"
|
||||
#include "XLXmlData.hpp"
|
||||
#include "XLZipArchive.hpp"
|
||||
|
||||
namespace OpenXLSX
|
||||
{
|
||||
/**
|
||||
* @brief The XLDocumentProperties class is an enumeration of the possible properties (metadata) that can be set
|
||||
* for a XLDocument object (and .xlsx file)
|
||||
*/
|
||||
enum class XLProperty {
|
||||
Title,
|
||||
Subject,
|
||||
Creator,
|
||||
Keywords,
|
||||
Description,
|
||||
LastModifiedBy,
|
||||
LastPrinted,
|
||||
CreationDate,
|
||||
ModificationDate,
|
||||
Category,
|
||||
Application,
|
||||
DocSecurity,
|
||||
ScaleCrop,
|
||||
Manager,
|
||||
Company,
|
||||
LinksUpToDate,
|
||||
SharedDoc,
|
||||
HyperlinkBase,
|
||||
HyperlinksChanged,
|
||||
AppVersion
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief This class encapsulates the concept of an excel file. It is different from the XLWorkbook, in that an
|
||||
* XLDocument holds an XLWorkbook together with its metadata, as well as methods for opening,
|
||||
* closing and saving the document.\n<b><em>The XLDocument is the entrypoint for clients
|
||||
* using the RapidXLSX library.</em></b>
|
||||
*/
|
||||
class OPENXLSX_EXPORT XLDocument final
|
||||
{
|
||||
//----- Friends
|
||||
friend class XLXmlFile;
|
||||
friend class XLWorkbook;
|
||||
friend class XLSheet;
|
||||
friend class XLXmlData;
|
||||
|
||||
//---------- Public Member Functions
|
||||
public:
|
||||
/**
|
||||
* @brief Constructor. The default constructor with no arguments.
|
||||
*/
|
||||
explicit XLDocument(const IZipArchive& zipArchive = XLZipArchive());
|
||||
|
||||
/**
|
||||
* @brief Constructor. An alternative constructor, taking the path to the .xlsx file as an argument.
|
||||
* @param docPath A std::string with the path to the .xlsx file.
|
||||
*/
|
||||
explicit XLDocument(const std::string& docPath, const IZipArchive& zipArchive = XLZipArchive());
|
||||
|
||||
/**
|
||||
* @brief Copy constructor
|
||||
* @param other The object to copy
|
||||
* @note Copy constructor explicitly deleted.
|
||||
*/
|
||||
XLDocument(const XLDocument& other) = delete;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param other
|
||||
*/
|
||||
XLDocument(XLDocument&& other) noexcept = default;
|
||||
|
||||
/**
|
||||
* @brief Destructor
|
||||
*/
|
||||
~XLDocument();
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param other
|
||||
* @return
|
||||
*/
|
||||
XLDocument& operator=(const XLDocument& other) = delete;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param other
|
||||
* @return
|
||||
*/
|
||||
XLDocument& operator=(XLDocument&& other) noexcept = default;
|
||||
|
||||
/**
|
||||
* @brief Open the .xlsx file with the given path
|
||||
* @param fileName The path of the .xlsx file to open
|
||||
*/
|
||||
void open(const std::string& fileName);
|
||||
|
||||
/**
|
||||
* @brief Create a new .xlsx file with the given name.
|
||||
* @param fileName The path of the new .xlsx file.
|
||||
*/
|
||||
void create(const std::string& fileName);
|
||||
|
||||
/**
|
||||
* @brief Close the current document
|
||||
*/
|
||||
void close();
|
||||
|
||||
/**
|
||||
* @brief Save the current document using the current filename, overwriting the existing file.
|
||||
* @return true if successful; otherwise false.
|
||||
*/
|
||||
void save();
|
||||
|
||||
/**
|
||||
* @brief Save the document with a new name. If a file exists with that name, it will be overwritten.
|
||||
* @param fileName The path of the file
|
||||
* @return true if successful; otherwise false.
|
||||
*/
|
||||
void saveAs(const std::string& fileName);
|
||||
|
||||
/**
|
||||
* @brief Get the filename of the current document, e.g. "spreadsheet.xlsx".
|
||||
* @return A std::string with the filename.
|
||||
*/
|
||||
const std::string& name() const;
|
||||
|
||||
/**
|
||||
* @brief Get the full path of the current document, e.g. "drive/blah/spreadsheet.xlsx"
|
||||
* @return A std::string with the path.
|
||||
*/
|
||||
const std::string& path() const;
|
||||
|
||||
/**
|
||||
* @brief Get the underlying workbook object, as a const object.
|
||||
* @return A const pointer to the XLWorkbook object.
|
||||
*/
|
||||
XLWorkbook workbook() const;
|
||||
|
||||
/**
|
||||
* @brief Get the requested document property.
|
||||
* @param prop The name of the property to get.
|
||||
* @return The property as a string
|
||||
*/
|
||||
std::string property(XLProperty prop) const;
|
||||
|
||||
/**
|
||||
* @brief Set a property
|
||||
* @param prop The property to set.
|
||||
* @param value The getValue of the property, as a string
|
||||
*/
|
||||
void setProperty(XLProperty prop, const std::string& value);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @return
|
||||
*/
|
||||
explicit operator bool() const;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @return
|
||||
*/
|
||||
bool isOpen() const;
|
||||
|
||||
/**
|
||||
* @brief Delete the property from the document
|
||||
* @param theProperty The property to delete from the document
|
||||
*/
|
||||
void deleteProperty(XLProperty theProperty);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param command
|
||||
*/
|
||||
void execCommand(const XLCommand& command);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param query
|
||||
* @return
|
||||
*/
|
||||
XLQuery execQuery(const XLQuery& query) const;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param query
|
||||
* @return
|
||||
*/
|
||||
XLQuery execQuery(const XLQuery& query);
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
// Protected Member Functions
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
protected:
|
||||
/**
|
||||
* @brief Get an XML file from the .xlsx archive.
|
||||
* @param path The relative path of the file.
|
||||
* @return A std::string with the content of the file
|
||||
*/
|
||||
std::string extractXmlFromArchive(const std::string& path);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param path
|
||||
* @return
|
||||
*/
|
||||
XLXmlData* getXmlData(const std::string& path);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param path
|
||||
* @return
|
||||
*/
|
||||
const XLXmlData* getXmlData(const std::string& path) const;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param path
|
||||
* @return
|
||||
*/
|
||||
bool hasXmlData(const std::string& path) const;
|
||||
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
// Private Member Variables
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
private:
|
||||
std::string m_filePath {}; /**< The path to the original file*/
|
||||
std::string m_realPath {}; /**< */
|
||||
|
||||
mutable std::list<XLXmlData> m_data {}; /**< */
|
||||
mutable std::deque<std::string> m_sharedStringCache {}; /**< */
|
||||
mutable XLSharedStrings m_sharedStrings {}; /**< */
|
||||
|
||||
XLRelationships m_docRelationships {}; /**< A pointer to the document relationships object*/
|
||||
XLRelationships m_wbkRelationships {}; /**< A pointer to the document relationships object*/
|
||||
XLContentTypes m_contentTypes {}; /**< A pointer to the content types object*/
|
||||
XLAppProperties m_appProperties {}; /**< A pointer to the App properties object */
|
||||
XLProperties m_coreProperties {}; /**< A pointer to the Core properties object*/
|
||||
XLWorkbook m_workbook {}; /**< A pointer to the workbook object */
|
||||
IZipArchive m_archive {}; /**< */
|
||||
};
|
||||
|
||||
} // namespace OpenXLSX
|
||||
|
||||
#pragma warning(pop)
|
||||
#endif // OPENXLSX_XLDOCUMENT_HPP
|
||||
+155
@@ -0,0 +1,155 @@
|
||||
/*
|
||||
|
||||
____ ____ ___ ____ ____ ____ ___
|
||||
6MMMMb `MM( )M' `MM' 6MMMMb\`MM( )M'
|
||||
8P Y8 `MM. d' MM 6M' ` `MM. d'
|
||||
6M Mb __ ____ ____ ___ __ `MM. d' MM MM `MM. d'
|
||||
MM MM `M6MMMMb 6MMMMb `MM 6MMb `MM. d' MM YM. `MM. d'
|
||||
MM MM MM' `Mb 6M' `Mb MMM9 `Mb `MMd MM YMMMMb `MMd
|
||||
MM MM MM MM MM MM MM' MM dMM. MM `Mb dMM.
|
||||
MM MM MM MM MMMMMMMM MM MM d'`MM. MM MM d'`MM.
|
||||
YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM.
|
||||
8b d8 MM. ,M9 YM d9 MM MM d' `MM. MM / L ,M9 d' `MM.
|
||||
YMMMM9 MMYMMM9 YMMMM9 _MM_ _MM_M(_ _)MM_ _MMMMMMM MYMMMM9 _M(_ _)MM_
|
||||
MM
|
||||
MM
|
||||
_MM_
|
||||
|
||||
Copyright (c) 2018, Kenneth Troldal Balslev
|
||||
|
||||
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.
|
||||
- Neither the name of the author nor the
|
||||
names of any 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 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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef OPENXLSX_XLEXCEPTION_HPP
|
||||
#define OPENXLSX_XLEXCEPTION_HPP
|
||||
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4251)
|
||||
#pragma warning(disable : 4275)
|
||||
|
||||
// ===== External Includes ===== //
|
||||
#include <stdexcept>
|
||||
|
||||
// ===== OpenXLSX Includes ===== //
|
||||
#include "OpenXLSX-Exports.hpp"
|
||||
|
||||
namespace OpenXLSX
|
||||
{
|
||||
/**
|
||||
* @brief
|
||||
*/
|
||||
class OPENXLSX_EXPORT XLException : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
inline explicit XLException(const std::string& err) : runtime_error(err) {};
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*/
|
||||
class OPENXLSX_EXPORT XLOverflowError : public XLException
|
||||
{
|
||||
public:
|
||||
inline explicit XLOverflowError(const std::string& err) : XLException(err) {};
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*/
|
||||
class OPENXLSX_EXPORT XLValueTypeError : public XLException
|
||||
{
|
||||
public:
|
||||
inline explicit XLValueTypeError(const std::string& err) : XLException(err) {};
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*/
|
||||
class OPENXLSX_EXPORT XLCellAddressError : public XLException
|
||||
{
|
||||
public:
|
||||
inline explicit XLCellAddressError(const std::string& err) : XLException(err) {};
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*/
|
||||
class OPENXLSX_EXPORT XLInputError : public XLException
|
||||
{
|
||||
public:
|
||||
inline explicit XLInputError(const std::string& err) : XLException(err) {};
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*/
|
||||
class OPENXLSX_EXPORT XLInternalError : public XLException
|
||||
{
|
||||
public:
|
||||
inline explicit XLInternalError(const std::string& err) : XLException(err) {};
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*/
|
||||
class OPENXLSX_EXPORT XLPropertyError : public XLException
|
||||
{
|
||||
public:
|
||||
inline explicit XLPropertyError(const std::string& err) : XLException(err) {};
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*/
|
||||
class OPENXLSX_EXPORT XLSheetError : public XLException
|
||||
{
|
||||
public:
|
||||
inline explicit XLSheetError(const std::string& err) : XLException(err) {};
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*/
|
||||
class OPENXLSX_EXPORT XLDateTimeError : public XLException
|
||||
{
|
||||
public:
|
||||
inline explicit XLDateTimeError(const std::string& err) : XLException(err) {};
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*/
|
||||
class OPENXLSX_EXPORT XLFormulaError : public XLException
|
||||
{
|
||||
public:
|
||||
inline explicit XLFormulaError(const std::string& err) : XLException(err) {};
|
||||
};
|
||||
|
||||
|
||||
} // namespace OpenXLSX
|
||||
|
||||
#pragma warning(pop)
|
||||
#endif // OPENXLSX_XLEXCEPTION_HPP
|
||||
Vendored
+365
@@ -0,0 +1,365 @@
|
||||
/*
|
||||
|
||||
____ ____ ___ ____ ____ ____ ___
|
||||
6MMMMb `MM( )M' `MM' 6MMMMb\`MM( )M'
|
||||
8P Y8 `MM. d' MM 6M' ` `MM. d'
|
||||
6M Mb __ ____ ____ ___ __ `MM. d' MM MM `MM. d'
|
||||
MM MM `M6MMMMb 6MMMMb `MM 6MMb `MM. d' MM YM. `MM. d'
|
||||
MM MM MM' `Mb 6M' `Mb MMM9 `Mb `MMd MM YMMMMb `MMd
|
||||
MM MM MM MM MM MM MM' MM dMM. MM `Mb dMM.
|
||||
MM MM MM MM MMMMMMMM MM MM d'`MM. MM MM d'`MM.
|
||||
YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM.
|
||||
8b d8 MM. ,M9 YM d9 MM MM d' `MM. MM / L ,M9 d' `MM.
|
||||
YMMMM9 MMYMMM9 YMMMM9 _MM_ _MM_M(_ _)MM_ _MMMMMMM MYMMMM9 _M(_ _)MM_
|
||||
MM
|
||||
MM
|
||||
_MM_
|
||||
|
||||
Copyright (c) 2018, Kenneth Troldal Balslev
|
||||
|
||||
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.
|
||||
- Neither the name of the author nor the
|
||||
names of any 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 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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef OPENXLSX_XLFORMULA_HPP
|
||||
#define OPENXLSX_XLFORMULA_HPP
|
||||
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4251)
|
||||
#pragma warning(disable : 4275)
|
||||
|
||||
// ===== External Includes ===== //
|
||||
#include <cstdint>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <variant>
|
||||
|
||||
// ===== OpenXLSX Includes ===== //
|
||||
#include "OpenXLSX-Exports.hpp"
|
||||
#include "XLException.hpp"
|
||||
#include "XLXmlParser.hpp"
|
||||
|
||||
// ========== CLASS AND ENUM TYPE DEFINITIONS ========== //
|
||||
namespace OpenXLSX
|
||||
{
|
||||
//---------- Forward Declarations ----------//
|
||||
class XLFormulaProxy;
|
||||
class XLCell;
|
||||
|
||||
/**
|
||||
* @brief The XLFormula class encapsulates the concept of an Excel formula. The class is essentially
|
||||
* a wrapper around a std::string.
|
||||
* @warning This class currently only supports simple formulas. Array formulas and shared formulas are
|
||||
* not supported. Unfortunately, many spreadsheets have shared formulas, so this class is probably
|
||||
* best used for adding formulas, not reading them from an existing spreadsheet.
|
||||
* @todo Enable handling of shared and array formulas.
|
||||
*/
|
||||
class OPENXLSX_EXPORT XLFormula
|
||||
{
|
||||
//---------- Friend Declarations ----------//
|
||||
|
||||
friend bool operator==(const XLFormula& lhs, const XLFormula& rhs);
|
||||
friend bool operator!=(const XLFormula& lhs, const XLFormula& rhs);
|
||||
friend std::ostream& operator<<(std::ostream& os, const XLFormula& value);
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Constructor
|
||||
*/
|
||||
XLFormula();
|
||||
|
||||
/**
|
||||
* @brief Constructor, taking a string-type argument
|
||||
* @tparam T Type of argument used. Must be string-type.
|
||||
* @param formula The formula to initialize the object with.
|
||||
*/
|
||||
template<typename T,
|
||||
typename std::enable_if<
|
||||
std::is_same_v<std::decay_t<T>, std::string> || std::is_same_v<std::decay_t<T>, std::string_view> ||
|
||||
std::is_same_v<std::decay_t<T>, const char*> || std::is_same_v<std::decay_t<T>, char*>>::type* = nullptr>
|
||||
explicit XLFormula(T formula)
|
||||
{
|
||||
// ===== If the argument is a const char *, use the argument directly; otherwise, assume it has a .c_str() function.
|
||||
if constexpr (std::is_same_v<std::decay_t<T>, const char*> || std::is_same_v<std::decay_t<T>, char*>)
|
||||
m_formulaString = formula;
|
||||
else if constexpr (std::is_same_v<std::decay_t<T>, std::string_view>)
|
||||
m_formulaString = std::string(formula);
|
||||
else
|
||||
m_formulaString = formula.c_str();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Copy constructor.
|
||||
* @param other Object to be copied.
|
||||
*/
|
||||
XLFormula(const XLFormula& other);
|
||||
|
||||
/**
|
||||
* @brief Move constructor.
|
||||
* @param other Object to be moved.
|
||||
*/
|
||||
XLFormula(XLFormula&& other) noexcept;
|
||||
|
||||
/**
|
||||
* @brief Destructor.
|
||||
*/
|
||||
~XLFormula();
|
||||
|
||||
/**
|
||||
* @brief Copy assignment operator.
|
||||
* @param other Object to be copied.
|
||||
* @return Reference to copied-to object.
|
||||
*/
|
||||
XLFormula& operator=(const XLFormula& other);
|
||||
|
||||
/**
|
||||
* @brief Move assignment operator.
|
||||
* @param other Object to be moved.
|
||||
* @return Reference to moved-to object.
|
||||
*/
|
||||
XLFormula& operator=(XLFormula&& other) noexcept;
|
||||
|
||||
/**
|
||||
* @brief Templated assignment operator, taking a string-type object as an argument.
|
||||
* @tparam T Type of argument (only string-types are allowed).
|
||||
* @param formula String containing the formula.
|
||||
* @return Reference to the assigned-to object.
|
||||
*/
|
||||
template<typename T,
|
||||
typename std::enable_if<
|
||||
std::is_same_v<std::decay_t<T>, std::string> || std::is_same_v<std::decay_t<T>, std::string_view> ||
|
||||
std::is_same_v<std::decay_t<T>, const char*> || std::is_same_v<std::decay_t<T>, char*>>::type* = nullptr>
|
||||
XLFormula& operator=(T formula)
|
||||
{
|
||||
XLFormula temp(formula);
|
||||
std::swap(*this, temp);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Templated setter function, taking a string-type object as an argument.
|
||||
* @tparam T Type of argument (only string-types are allowed).
|
||||
* @param formula String containing the formula.
|
||||
*/
|
||||
template<typename T,
|
||||
typename std::enable_if<
|
||||
std::is_same_v<std::decay_t<T>, std::string> || std::is_same_v<std::decay_t<T>, std::string_view> ||
|
||||
std::is_same_v<std::decay_t<T>, const char*> || std::is_same_v<std::decay_t<T>, char*>>::type* = nullptr>
|
||||
void set(T formula)
|
||||
{
|
||||
*this = formula;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the forumla as a std::string.
|
||||
* @return A std::string with the formula.
|
||||
*/
|
||||
std::string get() const;
|
||||
|
||||
/**
|
||||
* @brief Conversion operator, for converting object to a std::string.
|
||||
* @return The formula as a std::string.
|
||||
*/
|
||||
operator std::string() const; // NOLINT
|
||||
|
||||
/**
|
||||
* @brief Clear the formula.
|
||||
* @return Return a reference to the cleared object.
|
||||
*/
|
||||
XLFormula& clear();
|
||||
|
||||
private:
|
||||
std::string m_formulaString; /**< A std::string, holding the formula string.*/
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief The XLFormulaProxy serves as a placeholder for XLFormula objects. This enable
|
||||
* getting and setting formulas through the same interface.
|
||||
*/
|
||||
class OPENXLSX_EXPORT XLFormulaProxy
|
||||
{
|
||||
friend class XLCell;
|
||||
friend class XLFormula;
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Destructor
|
||||
*/
|
||||
~XLFormulaProxy();
|
||||
|
||||
/**
|
||||
* @brief Copy assignment operator.
|
||||
* @param other Object to be copied.
|
||||
* @return A reference to the copied-to object.
|
||||
*/
|
||||
XLFormulaProxy& operator=(const XLFormulaProxy& other);
|
||||
|
||||
/**
|
||||
* @brief Templated assignment operator, taking a string-type argument.
|
||||
* @tparam T Type of argument.
|
||||
* @param formula The formula string to be assigned.
|
||||
* @return A reference to the copied-to object.
|
||||
*/
|
||||
template<
|
||||
typename T,
|
||||
typename std::enable_if<std::is_same_v<std::decay_t<T>, XLFormula> || std::is_same_v<std::decay_t<T>, std::string> ||
|
||||
std::is_same_v<std::decay_t<T>, std::string_view> || std::is_same_v<std::decay_t<T>, const char*> ||
|
||||
std::is_same_v<std::decay_t<T>, char*>>::type* = nullptr>
|
||||
XLFormulaProxy& operator=(T formula)
|
||||
{
|
||||
if constexpr (std::is_same_v<std::decay_t<T>, XLFormula>)
|
||||
setFormulaString(formula.get().c_str());
|
||||
else if constexpr (std::is_same_v<std::decay_t<T>, std::string>)
|
||||
setFormulaString(formula.c_str());
|
||||
else if constexpr (std::is_same_v<std::decay_t<T>, std::string_view>)
|
||||
setFormulaString(std::string(formula).c_str());
|
||||
else
|
||||
setFormulaString(formula);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Templated setter, taking a string-type argument.
|
||||
* @tparam T Type of argument.
|
||||
* @param formula The formula string to be assigned.
|
||||
*/
|
||||
template<typename T,
|
||||
typename std::enable_if<
|
||||
std::is_same_v<std::decay_t<T>, std::string> || std::is_same_v<std::decay_t<T>, std::string_view> ||
|
||||
std::is_same_v<std::decay_t<T>, const char*> || std::is_same_v<std::decay_t<T>, char*>>::type* = nullptr>
|
||||
void set(T formula)
|
||||
{
|
||||
*this = formula;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the forumla as a std::string.
|
||||
* @return A std::string with the formula.
|
||||
*/
|
||||
std::string get() const;
|
||||
|
||||
/**
|
||||
* @brief Clear the formula.
|
||||
* @return Return a reference to the cleared object.
|
||||
*/
|
||||
XLFormulaProxy& clear();
|
||||
|
||||
/**
|
||||
* @brief Conversion operator, for converting the object to a std::string.
|
||||
* @return The formula as a std::string.
|
||||
*/
|
||||
operator std::string() const; // NOLINT
|
||||
|
||||
/**
|
||||
* @brief Implicit conversion to XLFormula object.
|
||||
* @return Returns the corresponding XLFormula object.
|
||||
*/
|
||||
operator XLFormula() const; // NOLINT
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief Constructor, taking pointers to the cell and cell node objects.
|
||||
* @param cell Pointer to the associated cell object.
|
||||
* @param cellNode Pointer to the associated cell node object.
|
||||
*/
|
||||
XLFormulaProxy(XLCell* cell, XMLNode* cellNode);
|
||||
|
||||
/**
|
||||
* @brief Copy constructor.
|
||||
* @param other Object to be copied.
|
||||
*/
|
||||
XLFormulaProxy(const XLFormulaProxy& other);
|
||||
|
||||
/**
|
||||
* @brief Move constructor.
|
||||
* @param other Object to be moved.
|
||||
*/
|
||||
XLFormulaProxy(XLFormulaProxy&& other) noexcept;
|
||||
|
||||
/**
|
||||
* @brief Move assignment operator.
|
||||
* @param other Object to be moved.
|
||||
* @return A reference to the moved-to object.
|
||||
*/
|
||||
XLFormulaProxy& operator=(XLFormulaProxy&& other) noexcept;
|
||||
|
||||
/**
|
||||
* @brief Set the formula to the given string.
|
||||
* @param formulaString String holding the formula.
|
||||
*/
|
||||
void setFormulaString(const char* formulaString);
|
||||
|
||||
/**
|
||||
* @brief Get the underlying XLFormula object.
|
||||
* @return A XLFormula object.
|
||||
* @throw XLFormulaError if the formula is of 'shared' or 'array' types.
|
||||
*/
|
||||
XLFormula getFormula() const;
|
||||
|
||||
//---------- Private Member Variables ---------- //
|
||||
XLCell* m_cell; /**< Pointer to the owning XLCell object. */
|
||||
XMLNode* m_cellNode; /**< Pointer to corresponding XML cell node. */
|
||||
};
|
||||
} // namespace OpenXLSX
|
||||
|
||||
// ========== FRIEND FUNCTION IMPLEMENTATIONS ========== //
|
||||
namespace OpenXLSX
|
||||
{
|
||||
/**
|
||||
* @brief
|
||||
* @param lhs
|
||||
* @param rhs
|
||||
* @return
|
||||
*/
|
||||
inline bool operator==(const XLFormula& lhs, const XLFormula& rhs)
|
||||
{
|
||||
return lhs.m_formulaString == rhs.m_formulaString;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param lhs
|
||||
* @param rhs
|
||||
* @return
|
||||
*/
|
||||
inline bool operator!=(const XLFormula& lhs, const XLFormula& rhs)
|
||||
{
|
||||
return lhs.m_formulaString != rhs.m_formulaString;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param os
|
||||
* @param value
|
||||
* @return
|
||||
*/
|
||||
inline std::ostream& operator<<(std::ostream& os, const XLFormula& value)
|
||||
{
|
||||
return os << value.m_formulaString;
|
||||
}
|
||||
} // namespace OpenXLSX
|
||||
|
||||
#endif // OPENXLSX_XLFORMULA_HPP
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
//
|
||||
// Created by Kenneth Balslev on 22/08/2020.
|
||||
//
|
||||
|
||||
#ifndef OPENXLSX_XLITERATOR_HPP
|
||||
#define OPENXLSX_XLITERATOR_HPP
|
||||
|
||||
namespace OpenXLSX
|
||||
{
|
||||
enum class XLIteratorDirection { Forward, Reverse };
|
||||
enum class XLIteratorLocation { Begin, End };
|
||||
|
||||
} // namespace OpenXLSX
|
||||
|
||||
#endif // OPENXLSX_XLITERATOR_HPP
|
||||
+298
@@ -0,0 +1,298 @@
|
||||
/*
|
||||
|
||||
____ ____ ___ ____ ____ ____ ___
|
||||
6MMMMb `MM( )M' `MM' 6MMMMb\`MM( )M'
|
||||
8P Y8 `MM. d' MM 6M' ` `MM. d'
|
||||
6M Mb __ ____ ____ ___ __ `MM. d' MM MM `MM. d'
|
||||
MM MM `M6MMMMb 6MMMMb `MM 6MMb `MM. d' MM YM. `MM. d'
|
||||
MM MM MM' `Mb 6M' `Mb MMM9 `Mb `MMd MM YMMMMb `MMd
|
||||
MM MM MM MM MM MM MM' MM dMM. MM `Mb dMM.
|
||||
MM MM MM MM MMMMMMMM MM MM d'`MM. MM MM d'`MM.
|
||||
YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM.
|
||||
8b d8 MM. ,M9 YM d9 MM MM d' `MM. MM / L ,M9 d' `MM.
|
||||
YMMMM9 MMYMMM9 YMMMM9 _MM_ _MM_M(_ _)MM_ _MMMMMMM MYMMMM9 _M(_ _)MM_
|
||||
MM
|
||||
MM
|
||||
_MM_
|
||||
|
||||
Copyright (c) 2018, Kenneth Troldal Balslev
|
||||
|
||||
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.
|
||||
- Neither the name of the author nor the
|
||||
names of any 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 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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef OPENXLSX_XLPROPERTIES_HPP
|
||||
#define OPENXLSX_XLPROPERTIES_HPP
|
||||
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4251)
|
||||
#pragma warning(disable : 4275)
|
||||
|
||||
// ===== External Includes ===== //
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
// ===== OpenXLSX Includes ===== //
|
||||
#include "OpenXLSX-Exports.hpp"
|
||||
#include "XLXmlFile.hpp"
|
||||
|
||||
namespace OpenXLSX
|
||||
{
|
||||
/**
|
||||
* @brief
|
||||
*/
|
||||
class OPENXLSX_EXPORT XLProperties : public XLXmlFile
|
||||
{
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
// Public Member Functions
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief
|
||||
*/
|
||||
XLProperties() = default;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param xmlData
|
||||
*/
|
||||
explicit XLProperties(XLXmlData* xmlData);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param other
|
||||
*/
|
||||
XLProperties(const XLProperties& other) = default;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param other
|
||||
*/
|
||||
XLProperties(XLProperties&& other) noexcept = default;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*/
|
||||
~XLProperties();
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param other
|
||||
* @return
|
||||
*/
|
||||
XLProperties& operator=(const XLProperties& other) = default;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param other
|
||||
* @return
|
||||
*/
|
||||
XLProperties& operator=(XLProperties&& other) = default;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param name
|
||||
* @param value
|
||||
* @return
|
||||
*/
|
||||
void setProperty(const std::string& name, const std::string& value);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param name
|
||||
* @param value
|
||||
* @return
|
||||
*/
|
||||
void setProperty(const std::string& name, int value);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param name
|
||||
* @param value
|
||||
* @return
|
||||
*/
|
||||
void setProperty(const std::string& name, double value);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param name
|
||||
* @return
|
||||
*/
|
||||
std::string property(const std::string& name) const;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param name
|
||||
*/
|
||||
void deleteProperty(const std::string& name);
|
||||
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
// Protected Member Functions
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief This class is a specialization of the XLAbstractXMLFile, with the purpose of the representing the
|
||||
* document app properties in the app.xml file (docProps folder) in the .xlsx package.
|
||||
*/
|
||||
class OPENXLSX_EXPORT XLAppProperties : public XLXmlFile
|
||||
{
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
// Public Member Functions
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief
|
||||
*/
|
||||
XLAppProperties() = default;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param xmlData
|
||||
*/
|
||||
explicit XLAppProperties(XLXmlData* xmlData);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param other
|
||||
*/
|
||||
XLAppProperties(const XLAppProperties& other) = default;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param other
|
||||
*/
|
||||
XLAppProperties(XLAppProperties&& other) noexcept = default;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*/
|
||||
~XLAppProperties();
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param other
|
||||
* @return
|
||||
*/
|
||||
XLAppProperties& operator=(const XLAppProperties& other) = default;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param other
|
||||
* @return
|
||||
*/
|
||||
XLAppProperties& operator=(XLAppProperties&& other) noexcept = default;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param title
|
||||
* @return
|
||||
*/
|
||||
void addSheetName(const std::string& title);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param title
|
||||
*/
|
||||
void deleteSheetName(const std::string& title);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param oldTitle
|
||||
* @param newTitle
|
||||
*/
|
||||
void setSheetName(const std::string& oldTitle, const std::string& newTitle);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param name
|
||||
* @param value
|
||||
*/
|
||||
void addHeadingPair(const std::string& name, int value);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param name
|
||||
*/
|
||||
void deleteHeadingPair(const std::string& name);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param name
|
||||
* @param newValue
|
||||
*/
|
||||
void setHeadingPair(const std::string& name, int newValue);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param name
|
||||
* @param value
|
||||
* @return
|
||||
*/
|
||||
void setProperty(const std::string& name, const std::string& value);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param name
|
||||
* @return
|
||||
*/
|
||||
std::string property(const std::string& name) const;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param name
|
||||
*/
|
||||
void deleteProperty(const std::string& name);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param sheetName
|
||||
* @return
|
||||
*/
|
||||
void appendSheetName(const std::string& sheetName);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param sheetName
|
||||
* @return
|
||||
*/
|
||||
void prependSheetName(const std::string& sheetName);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param sheetName
|
||||
* @param index
|
||||
* @return
|
||||
*/
|
||||
void insertSheetName(const std::string& sheetName, unsigned int index);
|
||||
};
|
||||
|
||||
} // namespace OpenXLSX
|
||||
|
||||
#pragma warning(pop)
|
||||
#endif // OPENXLSX_XLPROPERTIES_HPP
|
||||
+278
@@ -0,0 +1,278 @@
|
||||
/*
|
||||
|
||||
____ ____ ___ ____ ____ ____ ___
|
||||
6MMMMb `MM( )M' `MM' 6MMMMb\`MM( )M'
|
||||
8P Y8 `MM. d' MM 6M' ` `MM. d'
|
||||
6M Mb __ ____ ____ ___ __ `MM. d' MM MM `MM. d'
|
||||
MM MM `M6MMMMb 6MMMMb `MM 6MMb `MM. d' MM YM. `MM. d'
|
||||
MM MM MM' `Mb 6M' `Mb MMM9 `Mb `MMd MM YMMMMb `MMd
|
||||
MM MM MM MM MM MM MM' MM dMM. MM `Mb dMM.
|
||||
MM MM MM MM MMMMMMMM MM MM d'`MM. MM MM d'`MM.
|
||||
YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM.
|
||||
8b d8 MM. ,M9 YM d9 MM MM d' `MM. MM / L ,M9 d' `MM.
|
||||
YMMMM9 MMYMMM9 YMMMM9 _MM_ _MM_M(_ _)MM_ _MMMMMMM MYMMMM9 _M(_ _)MM_
|
||||
MM
|
||||
MM
|
||||
_MM_
|
||||
|
||||
Copyright (c) 2018, Kenneth Troldal Balslev
|
||||
|
||||
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.
|
||||
- Neither the name of the author nor the
|
||||
names of any 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 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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef OPENXLSX_XLRELATIONSHIPS_HPP
|
||||
#define OPENXLSX_XLRELATIONSHIPS_HPP
|
||||
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4251)
|
||||
#pragma warning(disable : 4275)
|
||||
|
||||
// ===== External Includes ===== //
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
// ===== OpenXLSX Includes ===== //
|
||||
#include "OpenXLSX-Exports.hpp"
|
||||
#include "XLXmlFile.hpp"
|
||||
#include "XLXmlParser.hpp"
|
||||
|
||||
namespace OpenXLSX
|
||||
{
|
||||
class XLRelationships;
|
||||
|
||||
class XLRelationshipItem;
|
||||
|
||||
/**
|
||||
* @brief An enum of the possible relationship (or XML document) types used in relationship (.rels) XML files.
|
||||
*/
|
||||
enum class XLRelationshipType {
|
||||
CoreProperties,
|
||||
ExtendedProperties,
|
||||
CustomProperties,
|
||||
Workbook,
|
||||
Worksheet,
|
||||
Chartsheet,
|
||||
Dialogsheet,
|
||||
Macrosheet,
|
||||
CalculationChain,
|
||||
ExternalLink,
|
||||
ExternalLinkPath,
|
||||
Theme,
|
||||
Styles,
|
||||
Chart,
|
||||
ChartStyle,
|
||||
ChartColorStyle,
|
||||
Image,
|
||||
Drawing,
|
||||
VMLDrawing,
|
||||
SharedStrings,
|
||||
PrinterSettings,
|
||||
VBAProject,
|
||||
ControlProperties,
|
||||
Unknown
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief An encapsulation of a relationship item, i.e. an XML file in the document, its type and an ID number.
|
||||
*/
|
||||
class OPENXLSX_EXPORT XLRelationshipItem
|
||||
{
|
||||
public: // ---------- Public Member Functions ---------- //
|
||||
/**
|
||||
* @brief
|
||||
*/
|
||||
XLRelationshipItem();
|
||||
|
||||
/**
|
||||
* @brief Constructor. New items should only be created through an XLRelationship object.
|
||||
* @param node An XMLNode object with the relationship item. If no input is provided, a null node is used.
|
||||
*/
|
||||
explicit XLRelationshipItem(const XMLNode& node);
|
||||
|
||||
/**
|
||||
* @brief Copy Constructor.
|
||||
* @param other Object to be copied.
|
||||
*/
|
||||
XLRelationshipItem(const XLRelationshipItem& other);
|
||||
|
||||
/**
|
||||
* @brief Move Constructor.
|
||||
* @param other Object to be moved.
|
||||
*/
|
||||
XLRelationshipItem(XLRelationshipItem&& other) noexcept = default;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*/
|
||||
~XLRelationshipItem();
|
||||
|
||||
/**
|
||||
* @brief Copy assignment operator.
|
||||
* @param other Right hand side of assignment operation.
|
||||
* @return A reference to the lhs object.
|
||||
*/
|
||||
XLRelationshipItem& operator=(const XLRelationshipItem& other);
|
||||
|
||||
/**
|
||||
* @brief Move assignment operator.
|
||||
* @param other Right hand side of assignment operation.
|
||||
* @return A reference to lhs object.
|
||||
*/
|
||||
XLRelationshipItem& operator=(XLRelationshipItem&& other) noexcept = default;
|
||||
|
||||
/**
|
||||
* @brief Get the type of the current relationship item.
|
||||
* @return An XLRelationshipType enum object, corresponding to the type.
|
||||
*/
|
||||
XLRelationshipType type() const;
|
||||
|
||||
/**
|
||||
* @brief Get the target, i.e. the path to the XML file the relationship item refers to.
|
||||
* @return An XMLAttribute object containing the Target getValue.
|
||||
*/
|
||||
std::string target() const;
|
||||
|
||||
/**
|
||||
* @brief Get the id of the relationship item.
|
||||
* @return An XMLAttribute object containing the Id getValue.
|
||||
*/
|
||||
std::string id() const;
|
||||
|
||||
private: // ---------- Private Member Variables ---------- //
|
||||
std::unique_ptr<XMLNode> m_relationshipNode; /**< An XMLNode object with the relationship item */
|
||||
};
|
||||
|
||||
// ================================================================================
|
||||
// XLRelationships Class
|
||||
// ================================================================================
|
||||
|
||||
/**
|
||||
* @brief An encapsulation of relationship files (.rels files) in an Excel document package.
|
||||
*/
|
||||
class OPENXLSX_EXPORT XLRelationships : public XLXmlFile
|
||||
{
|
||||
public: // ---------- Public Member Functions ---------- //
|
||||
/**
|
||||
* @brief
|
||||
*/
|
||||
XLRelationships() = default;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param xmlData
|
||||
*/
|
||||
explicit XLRelationships(XLXmlData* xmlData);
|
||||
|
||||
/**
|
||||
* @brief Destructor
|
||||
*/
|
||||
~XLRelationships();
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param other
|
||||
*/
|
||||
XLRelationships(const XLRelationships& other) = default;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param other
|
||||
*/
|
||||
XLRelationships(XLRelationships&& other) noexcept = default;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param other
|
||||
* @return
|
||||
*/
|
||||
XLRelationships& operator=(const XLRelationships& other) = default;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param other
|
||||
* @return
|
||||
*/
|
||||
XLRelationships& operator=(XLRelationships&& other) noexcept = default;
|
||||
|
||||
/**
|
||||
* @brief Look up a relationship item by ID.
|
||||
* @param id The ID string of the relationship item to retrieve.
|
||||
* @return An XLRelationshipItem object.
|
||||
*/
|
||||
XLRelationshipItem relationshipById(const std::string& id) const;
|
||||
|
||||
/**
|
||||
* @brief Look up a relationship item by Target.
|
||||
* @param target The Target string of the relationship item to retrieve.
|
||||
* @return An XLRelationshipItem object.
|
||||
*/
|
||||
XLRelationshipItem relationshipByTarget(const std::string& target) const;
|
||||
|
||||
/**
|
||||
* @brief Get the std::map with the relationship items, ordered by ID.
|
||||
* @return A const reference to the std::map with relationship items.
|
||||
*/
|
||||
std::vector<XLRelationshipItem> relationships() const;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param relID
|
||||
*/
|
||||
void deleteRelationship(const std::string& relID);
|
||||
|
||||
/**
|
||||
* @brief Delete an item from the Relationships register
|
||||
* @param item The XLRelationshipItem object to delete.
|
||||
*/
|
||||
void deleteRelationship(const XLRelationshipItem& item);
|
||||
|
||||
/**
|
||||
* @brief Add a new relationship item to the XLRelationships object.
|
||||
* @param type The type of the new relationship item.
|
||||
* @param target The target (or path) of the XML file for the relationship item.
|
||||
*/
|
||||
XLRelationshipItem addRelationship(XLRelationshipType type, const std::string& target);
|
||||
|
||||
/**
|
||||
* @brief Check if a XLRelationshipItem with the given Target string exists.
|
||||
* @param target The Target string to look up.
|
||||
* @return true if the XLRelationshipItem exists; otherwise false.
|
||||
*/
|
||||
bool targetExists(const std::string& target) const;
|
||||
|
||||
/**
|
||||
* @brief Check if a XLRelationshipItem with the given Id string exists.
|
||||
* @param id The Id string to look up.
|
||||
* @return true if the XLRelationshipItem exists; otherwise false.
|
||||
*/
|
||||
bool idExists(const std::string& id) const;
|
||||
|
||||
// ---------- Protected Member Functions ---------- //
|
||||
};
|
||||
} // namespace OpenXLSX
|
||||
|
||||
#pragma warning(pop)
|
||||
#endif // OPENXLSX_XLRELATIONSHIPS_HPP
|
||||
Vendored
+496
@@ -0,0 +1,496 @@
|
||||
/*
|
||||
|
||||
____ ____ ___ ____ ____ ____ ___
|
||||
6MMMMb `MM( )M' `MM' 6MMMMb\`MM( )M'
|
||||
8P Y8 `MM. d' MM 6M' ` `MM. d'
|
||||
6M Mb __ ____ ____ ___ __ `MM. d' MM MM `MM. d'
|
||||
MM MM `M6MMMMb 6MMMMb `MM 6MMb `MM. d' MM YM. `MM. d'
|
||||
MM MM MM' `Mb 6M' `Mb MMM9 `Mb `MMd MM YMMMMb `MMd
|
||||
MM MM MM MM MM MM MM' MM dMM. MM `Mb dMM.
|
||||
MM MM MM MM MMMMMMMM MM MM d'`MM. MM MM d'`MM.
|
||||
YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM.
|
||||
8b d8 MM. ,M9 YM d9 MM MM d' `MM. MM / L ,M9 d' `MM.
|
||||
YMMMM9 MMYMMM9 YMMMM9 _MM_ _MM_M(_ _)MM_ _MMMMMMM MYMMMM9 _M(_ _)MM_
|
||||
MM
|
||||
MM
|
||||
_MM_
|
||||
|
||||
Copyright (c) 2018, Kenneth Troldal Balslev
|
||||
|
||||
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.
|
||||
- Neither the name of the author nor the
|
||||
names of any 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 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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef OPENXLSX_XLROW_HPP
|
||||
#define OPENXLSX_XLROW_HPP
|
||||
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4251)
|
||||
#pragma warning(disable : 4275)
|
||||
|
||||
// ===== OpenXLSX Includes ===== //
|
||||
#include "OpenXLSX-Exports.hpp"
|
||||
#include "XLRowData.hpp"
|
||||
|
||||
// ========== CLASS AND ENUM TYPE DEFINITIONS ========== //
|
||||
namespace OpenXLSX
|
||||
{
|
||||
class XLRowRange;
|
||||
|
||||
/**
|
||||
* @brief The XLRow class represent a row in an Excel spreadsheet. Using XLRow objects, various row formatting
|
||||
* options can be set and modified.
|
||||
*/
|
||||
class OPENXLSX_EXPORT XLRow
|
||||
{
|
||||
friend class XLRowIterator;
|
||||
friend class XLRowDataProxy;
|
||||
friend bool operator==(const XLRow& lhs, const XLRow& rhs);
|
||||
friend bool operator!=(const XLRow& lhs, const XLRow& rhs);
|
||||
friend bool operator<(const XLRow& lhs, const XLRow& rhs);
|
||||
friend bool operator>(const XLRow& lhs, const XLRow& rhs);
|
||||
friend bool operator<=(const XLRow& lhs, const XLRow& rhs);
|
||||
friend bool operator>=(const XLRow& lhs, const XLRow& rhs);
|
||||
|
||||
//---------- PUBLIC MEMBER FUNCTIONS ----------//
|
||||
public:
|
||||
/**
|
||||
* @brief Default constructor
|
||||
*/
|
||||
XLRow();
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param rowNode
|
||||
* @param sharedStrings
|
||||
*/
|
||||
XLRow(const XMLNode& rowNode, const XLSharedStrings& sharedStrings);
|
||||
|
||||
/**
|
||||
* @brief Copy Constructor
|
||||
* @note The copy constructor is explicitly deleted
|
||||
*/
|
||||
XLRow(const XLRow& other);
|
||||
|
||||
/**
|
||||
* @brief Move Constructor
|
||||
* @note The move constructor has been explicitly deleted.
|
||||
*/
|
||||
XLRow(XLRow&& other) noexcept;
|
||||
|
||||
/**
|
||||
* @brief Destructor
|
||||
* @note The destructor has a default implementation.
|
||||
*/
|
||||
~XLRow();
|
||||
|
||||
/**
|
||||
* @brief Copy assignment operator.
|
||||
* @note The copy assignment operator is explicitly deleted.
|
||||
*/
|
||||
XLRow& operator=(const XLRow& other);
|
||||
|
||||
/**
|
||||
* @brief Move assignment operator.
|
||||
* @note The move assignment operator has been explicitly deleted.
|
||||
*/
|
||||
XLRow& operator=(XLRow&& other) noexcept;
|
||||
|
||||
/**
|
||||
* @brief Get the height of the row.
|
||||
* @return the row height.
|
||||
*/
|
||||
double height() const;
|
||||
|
||||
/**
|
||||
* @brief Set the height of the row.
|
||||
* @param height The height of the row.
|
||||
*/
|
||||
void setHeight(float height);
|
||||
|
||||
/**
|
||||
* @brief Get the descent of the row, which is the vertical distance in pixels from the bottom of the cells
|
||||
* in the current row to the typographical baseline of the cell content.
|
||||
* @return The row descent.
|
||||
*/
|
||||
float descent() const;
|
||||
|
||||
/**
|
||||
* @brief Set the descent of the row, which is he vertical distance in pixels from the bottom of the cells
|
||||
* in the current row to the typographical baseline of the cell content.
|
||||
* @param descent The row descent.
|
||||
*/
|
||||
void setDescent(float descent);
|
||||
|
||||
/**
|
||||
* @brief Is the row hidden?
|
||||
* @return The state of the row.
|
||||
*/
|
||||
bool isHidden() const;
|
||||
|
||||
/**
|
||||
* @brief Set the row to be hidden or visible.
|
||||
* @param state The state of the row.
|
||||
*/
|
||||
void setHidden(bool state);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @return
|
||||
*/
|
||||
uint64_t rowNumber() const;
|
||||
|
||||
/**
|
||||
* @brief Get the number of cells in the row.
|
||||
* @return The number of cells in the row.
|
||||
*/
|
||||
unsigned int cellCount() const;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @return
|
||||
*/
|
||||
XLRowDataProxy& values();
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @return
|
||||
*/
|
||||
const XLRowDataProxy& values() const;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @tparam T
|
||||
* @return
|
||||
*/
|
||||
template<typename T>
|
||||
T values() const
|
||||
{
|
||||
return static_cast<T>(values());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @return
|
||||
*/
|
||||
XLRowDataRange cells() const;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param cellCount
|
||||
* @return
|
||||
*/
|
||||
XLRowDataRange cells(uint16_t cellCount) const;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param firstCell
|
||||
* @param lastCell
|
||||
* @return
|
||||
*/
|
||||
XLRowDataRange cells(uint16_t firstCell, uint16_t lastCell) const;
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param lhs
|
||||
* @param rhs
|
||||
* @return
|
||||
*/
|
||||
static bool isEqual(const XLRow& lhs, const XLRow& rhs);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param lhs
|
||||
* @param rhs
|
||||
* @return
|
||||
*/
|
||||
static bool isLessThan(const XLRow& lhs, const XLRow& rhs);
|
||||
|
||||
//---------- PRIVATE MEMBER VARIABLES ----------//
|
||||
std::unique_ptr<XMLNode> m_rowNode; /**< The XMLNode object for the row. */
|
||||
XLSharedStrings m_sharedStrings; /**< */
|
||||
XLRowDataProxy m_rowDataProxy; /**< */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*/
|
||||
class OPENXLSX_EXPORT XLRowIterator
|
||||
{
|
||||
public:
|
||||
using iterator_category = std::forward_iterator_tag;
|
||||
using value_type = XLRow;
|
||||
using difference_type = int64_t;
|
||||
using pointer = XLRow*;
|
||||
using reference = XLRow&;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param rowRange
|
||||
* @param loc
|
||||
*/
|
||||
explicit XLRowIterator(const XLRowRange& rowRange, XLIteratorLocation loc);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*/
|
||||
~XLRowIterator();
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param other
|
||||
*/
|
||||
XLRowIterator(const XLRowIterator& other);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param other
|
||||
*/
|
||||
XLRowIterator(XLRowIterator&& other) noexcept;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param other
|
||||
* @return
|
||||
*/
|
||||
XLRowIterator& operator=(const XLRowIterator& other);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param other
|
||||
* @return
|
||||
*/
|
||||
XLRowIterator& operator=(XLRowIterator&& other) noexcept;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @return
|
||||
*/
|
||||
XLRowIterator& operator++();
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @return
|
||||
*/
|
||||
XLRowIterator operator++(int); // NOLINT
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @return
|
||||
*/
|
||||
reference operator*();
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @return
|
||||
*/
|
||||
pointer operator->();
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param rhs
|
||||
* @return
|
||||
*/
|
||||
bool operator==(const XLRowIterator& rhs) const;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param rhs
|
||||
* @return
|
||||
*/
|
||||
bool operator!=(const XLRowIterator& rhs) const;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @return
|
||||
*/
|
||||
explicit operator bool() const;
|
||||
|
||||
private:
|
||||
std::unique_ptr<XMLNode> m_dataNode; /**< */
|
||||
uint32_t m_firstRow { 1 }; /**< The cell reference of the first cell in the range */
|
||||
uint32_t m_lastRow { 1 }; /**< The cell reference of the last cell in the range */
|
||||
XLRow m_currentRow; /**< */
|
||||
XLSharedStrings m_sharedStrings; /**< */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*/
|
||||
class OPENXLSX_EXPORT XLRowRange
|
||||
{
|
||||
friend class XLRowIterator;
|
||||
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
// Public Member Functions
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief
|
||||
* @param dataNode
|
||||
* @param first
|
||||
* @param last
|
||||
* @param sharedStrings
|
||||
*/
|
||||
explicit XLRowRange(const XMLNode& dataNode, uint32_t first, uint32_t last, const XLSharedStrings& sharedStrings);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param other
|
||||
*/
|
||||
XLRowRange(const XLRowRange& other);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param other
|
||||
*/
|
||||
XLRowRange(XLRowRange&& other) noexcept;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*/
|
||||
~XLRowRange();
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param other
|
||||
* @return
|
||||
*/
|
||||
XLRowRange& operator=(const XLRowRange& other);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param other
|
||||
* @return
|
||||
*/
|
||||
XLRowRange& operator=(XLRowRange&& other) noexcept;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @return
|
||||
*/
|
||||
uint32_t rowCount() const;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @return
|
||||
*/
|
||||
XLRowIterator begin();
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @return
|
||||
*/
|
||||
XLRowIterator end();
|
||||
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
// Private Member Variables
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
private:
|
||||
std::unique_ptr<XMLNode> m_dataNode; /**< */
|
||||
uint32_t m_firstRow; /**< The cell reference of the first cell in the range */
|
||||
uint32_t m_lastRow; /**< The cell reference of the last cell in the range */
|
||||
XLSharedStrings m_sharedStrings; /**< */
|
||||
};
|
||||
|
||||
} // namespace OpenXLSX
|
||||
|
||||
// ========== FRIEND FUNCTION IMPLEMENTATIONS ========== //
|
||||
namespace OpenXLSX
|
||||
{
|
||||
/**
|
||||
* @brief
|
||||
* @param lhs
|
||||
* @param rhs
|
||||
* @return
|
||||
*/
|
||||
inline bool operator==(const XLRow& lhs, const XLRow& rhs)
|
||||
{
|
||||
return XLRow::isEqual(lhs, rhs);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param lhs
|
||||
* @param rhs
|
||||
* @return
|
||||
*/
|
||||
inline bool operator!=(const XLRow& lhs, const XLRow& rhs)
|
||||
{
|
||||
return !(lhs.m_rowNode == rhs.m_rowNode);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param lhs
|
||||
* @param rhs
|
||||
* @return
|
||||
*/
|
||||
inline bool operator<(const XLRow& lhs, const XLRow& rhs)
|
||||
{
|
||||
return XLRow::isLessThan(lhs, rhs);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param lhs
|
||||
* @param rhs
|
||||
* @return
|
||||
*/
|
||||
inline bool operator>(const XLRow& lhs, const XLRow& rhs)
|
||||
{
|
||||
return (rhs < lhs);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param lhs
|
||||
* @param rhs
|
||||
* @return
|
||||
*/
|
||||
inline bool operator<=(const XLRow& lhs, const XLRow& rhs)
|
||||
{
|
||||
return !(lhs > rhs);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param lhs
|
||||
* @param rhs
|
||||
* @return
|
||||
*/
|
||||
inline bool operator>=(const XLRow& lhs, const XLRow& rhs)
|
||||
{
|
||||
return !(lhs < rhs);
|
||||
}
|
||||
|
||||
} // namespace OpenXLSX
|
||||
|
||||
#pragma warning(pop)
|
||||
#endif // OPENXLSX_XLROW_HPP
|
||||
Vendored
+427
@@ -0,0 +1,427 @@
|
||||
//
|
||||
// Created by Kenneth Balslev on 24/08/2020.
|
||||
//
|
||||
|
||||
#ifndef OPENXLSX_XLROWDATA_HPP
|
||||
#define OPENXLSX_XLROWDATA_HPP
|
||||
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4251)
|
||||
#pragma warning(disable : 4275)
|
||||
|
||||
// ===== External Includes ===== //
|
||||
#include <deque>
|
||||
#include <iterator>
|
||||
#include <list>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
// ===== OpenXLSX Includes ===== //
|
||||
#include "OpenXLSX-Exports.hpp"
|
||||
#include "XLCell.hpp"
|
||||
#include "XLConstants.hpp"
|
||||
#include "XLException.hpp"
|
||||
#include "XLIterator.hpp"
|
||||
#include "XLXmlParser.hpp"
|
||||
|
||||
// ========== CLASS AND ENUM TYPE DEFINITIONS ========== //
|
||||
namespace OpenXLSX
|
||||
{
|
||||
class XLRow;
|
||||
class XLRowDataRange;
|
||||
|
||||
/**
|
||||
* @brief This class encapsulates a (non-const) iterator, for iterating over the cells in a row.
|
||||
* @todo Consider implementing a const iterator also
|
||||
*/
|
||||
class OPENXLSX_EXPORT XLRowDataIterator
|
||||
{
|
||||
friend class XLRowDataRange;
|
||||
|
||||
public:
|
||||
using iterator_category = std::forward_iterator_tag;
|
||||
using value_type = XLCell;
|
||||
using difference_type = int64_t;
|
||||
using pointer = XLCell*;
|
||||
using reference = XLCell&;
|
||||
|
||||
/**
|
||||
* @brief Destructor.
|
||||
*/
|
||||
~XLRowDataIterator();
|
||||
|
||||
/**
|
||||
* @brief Copy constructor.
|
||||
* @param other Object to be copied.
|
||||
*/
|
||||
XLRowDataIterator(const XLRowDataIterator& other);
|
||||
|
||||
/**
|
||||
* @brief Move constructor.
|
||||
* @param other Object to be moved.
|
||||
*/
|
||||
XLRowDataIterator(XLRowDataIterator&& other) noexcept;
|
||||
|
||||
/**
|
||||
* @brief Copy assignment operator.
|
||||
* @param other Object to be copied.
|
||||
* @return Reference to the copied-to object.
|
||||
*/
|
||||
XLRowDataIterator& operator=(const XLRowDataIterator& other);
|
||||
|
||||
/**
|
||||
* @brief Move assignment operator.
|
||||
* @param other Object to be moved.
|
||||
* @return Reference to the moved-to object.
|
||||
*/
|
||||
XLRowDataIterator& operator=(XLRowDataIterator&& other) noexcept;
|
||||
|
||||
/**
|
||||
* @brief Pre-increment of the iterator.
|
||||
* @return Reference to the iterator object.
|
||||
*/
|
||||
XLRowDataIterator& operator++();
|
||||
|
||||
/**
|
||||
* @brief Post-increment of the iterator.
|
||||
* @return Reference to the iterator object.
|
||||
*/
|
||||
XLRowDataIterator operator++(int); // NOLINT
|
||||
|
||||
/**
|
||||
* @brief Dereferencing operator.
|
||||
* @return Reference to the object pointed to by the iterator.
|
||||
*/
|
||||
reference operator*();
|
||||
|
||||
/**
|
||||
* @brief Arrow operator.
|
||||
* @return Pointer to the object pointed to by the iterator.
|
||||
*/
|
||||
pointer operator->();
|
||||
|
||||
/**
|
||||
* @brief Equality operator.
|
||||
* @param rhs XLRowDataIterator to compare to.
|
||||
* @return true if equal, otherwise false.
|
||||
*/
|
||||
bool operator==(const XLRowDataIterator& rhs) const;
|
||||
|
||||
/**
|
||||
* @brief Non-equality operator.
|
||||
* @param rhs XLRowDataIterator to compare to.
|
||||
* @return false if equal, otherwise true.
|
||||
*/
|
||||
bool operator!=(const XLRowDataIterator& rhs) const;
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief Constructor.
|
||||
* @param rowDataRange The range to iterate over.
|
||||
* @param loc The location of the iterator (begin or end).
|
||||
*/
|
||||
XLRowDataIterator(const XLRowDataRange& rowDataRange, XLIteratorLocation loc);
|
||||
|
||||
std::unique_ptr<XLRowDataRange> m_dataRange; /**< A pointer to the range to iterate over. */
|
||||
std::unique_ptr<XMLNode> m_cellNode; /**< The XML node representing the cell currently pointed at. */
|
||||
XLCell m_currentCell; /**< The XLCell currently pointed at. */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief This class encapsulates the concept of a contiguous range of cells in a row.
|
||||
*/
|
||||
class OPENXLSX_EXPORT XLRowDataRange
|
||||
{
|
||||
friend class XLRowDataIterator;
|
||||
friend class XLRowDataProxy;
|
||||
friend class XLRow;
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Copy constructor.
|
||||
* @param other Object to be copied.
|
||||
*/
|
||||
XLRowDataRange(const XLRowDataRange& other);
|
||||
|
||||
/**
|
||||
* @brief Move constructor.
|
||||
* @param other Object to be moved.
|
||||
*/
|
||||
XLRowDataRange(XLRowDataRange&& other) noexcept;
|
||||
|
||||
/**
|
||||
* @brief Destructor.
|
||||
*/
|
||||
~XLRowDataRange();
|
||||
|
||||
/**
|
||||
* @brief Copy assignment operator.
|
||||
* @param other Object to be copied.
|
||||
* @return A reference to the copied-to object.
|
||||
*/
|
||||
XLRowDataRange& operator=(const XLRowDataRange& other);
|
||||
|
||||
/**
|
||||
* @brief Move assignment operator.
|
||||
* @param other Object to be moved.
|
||||
* @return A reference to the moved-to object.
|
||||
*/
|
||||
XLRowDataRange& operator=(XLRowDataRange&& other) noexcept;
|
||||
|
||||
/**
|
||||
* @brief Get the size (length) of the range.
|
||||
* @return The size of the range.
|
||||
*/
|
||||
uint16_t size() const;
|
||||
|
||||
/**
|
||||
* @brief Get an iterator to the first element.
|
||||
* @return An XLRowDataIterator pointing to the first element.
|
||||
*/
|
||||
XLRowDataIterator begin();
|
||||
|
||||
/**
|
||||
* @brief Get an iterator to (one-past) the last element.
|
||||
* @return An XLRowDataIterator pointing to (one past) the last element.
|
||||
*/
|
||||
XLRowDataIterator end();
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief Constructor.
|
||||
* @param rowNode XMLNode representing the row of the range.
|
||||
* @param firstColumn The index of the first column.
|
||||
* @param lastColumn The index of the last column.
|
||||
* @param sharedStrings A pointer to the shared strings repository.
|
||||
*/
|
||||
explicit XLRowDataRange(const XMLNode& rowNode, uint16_t firstColumn, uint16_t lastColumn, const XLSharedStrings& sharedStrings);
|
||||
|
||||
std::unique_ptr<XMLNode> m_rowNode; /**< */
|
||||
uint16_t m_firstCol { 1 }; /**< The cell reference of the first cell in the range */
|
||||
uint16_t m_lastCol { 1 }; /**< The cell reference of the last cell in the range */
|
||||
XLSharedStrings m_sharedStrings; /**< */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief The XLRowDataProxy is used as a proxy object when getting or setting row data. The class facilitates easy conversion
|
||||
* to/from containers.
|
||||
*/
|
||||
class OPENXLSX_EXPORT XLRowDataProxy
|
||||
{
|
||||
friend class XLRow;
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Destructor
|
||||
*/
|
||||
~XLRowDataProxy();
|
||||
|
||||
/**
|
||||
* @brief Copy assignment operator.
|
||||
* @param other Object to be copied.
|
||||
* @return A reference to the copied-to object.
|
||||
*/
|
||||
XLRowDataProxy& operator=(const XLRowDataProxy& other);
|
||||
|
||||
/**
|
||||
* @brief Assignment operator taking a std::vector of XLCellValues as an argument.
|
||||
* @param values A std::vector of XLCellValues representing the values to be assigned.
|
||||
* @return A reference to the copied-to object.
|
||||
*/
|
||||
XLRowDataProxy& operator=(const std::vector<XLCellValue>& values);
|
||||
|
||||
/**
|
||||
* @brief Assignment operator taking a std::vector of bool values as an argument.
|
||||
* @param values A std::vector of bool values representing the values to be assigned.
|
||||
* @return A reference to the copied-to object.
|
||||
*/
|
||||
XLRowDataProxy& operator=(const std::vector<bool>& values);
|
||||
|
||||
/**
|
||||
* @brief Templated assignment operator taking any container supporting bidirectional iterators.
|
||||
* @tparam T The container and value type (will be auto deducted by the compiler).
|
||||
* @param values The container of the values to be assigned.
|
||||
* @return A reference to the copied-to object.
|
||||
* @throws XLOverflowError if size of container exceeds maximum number of columns.
|
||||
*/
|
||||
template<typename T,
|
||||
typename std::enable_if<!std::is_same_v<T, XLRowDataProxy> &&
|
||||
std::is_base_of_v<typename std::bidirectional_iterator_tag,
|
||||
typename std::iterator_traits<typename T::iterator>::iterator_category>,
|
||||
T>::type* = nullptr>
|
||||
XLRowDataProxy& operator=(const T& values)
|
||||
{
|
||||
if (values.size() > MAX_COLS) throw XLOverflowError("Container size exceeds maximum number of columns.");
|
||||
if (values.size() == 0) return *this;
|
||||
|
||||
// ===== If the container value_type is XLCellValue, the values can be copied directly.
|
||||
if constexpr (std::is_same_v<typename T::value_type, XLCellValue>) {
|
||||
// ===== First, delete the values in the first N columns.
|
||||
deleteCellValues(values.size());
|
||||
|
||||
// ===== Then, prepend new cell nodes to current row node
|
||||
auto colNo = values.size();
|
||||
for (auto value = values.rbegin(); value != values.rend(); ++value) { // NOLINT
|
||||
prependCellValue(*value, colNo);
|
||||
--colNo;
|
||||
}
|
||||
}
|
||||
|
||||
// ===== If the container value_type is a POD type, use the overloaded operator= on each cell.
|
||||
else {
|
||||
auto range = XLRowDataRange(*m_rowNode, 1, values.size(), getSharedStrings());
|
||||
auto dst = range.begin();
|
||||
auto src = values.begin();
|
||||
|
||||
while (true) {
|
||||
dst->value() = *src;
|
||||
++src;
|
||||
if (src == values.end()) break;
|
||||
++dst;
|
||||
}
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Implicit conversion to std::vector of XLCellValues.
|
||||
* @return A std::vector of XLCellValues.
|
||||
*/
|
||||
operator std::vector<XLCellValue>() const; // NOLINT
|
||||
|
||||
/**
|
||||
* @brief Implicit conversion to std::deque of XLCellValues.
|
||||
* @return A std::deque of XLCellValues.
|
||||
*/
|
||||
operator std::deque<XLCellValue>() const; // NOLINT
|
||||
|
||||
/**
|
||||
* @brief Implicit conversion to std::list of XLCellValues.
|
||||
* @return A std::list of XLCellValues.
|
||||
*/
|
||||
operator std::list<XLCellValue>() const; // NOLINT
|
||||
|
||||
/**
|
||||
* @brief Explicit conversion operator.
|
||||
* @details This function calls the convertContainer template function to convert the row data to the container
|
||||
* stipulated by the client. The reason that this function is marked explicit is that the implicit conversion operators
|
||||
* above will be ambiguous.
|
||||
* @tparam Container The container (and value) type to convert the row data to.
|
||||
* @return The required container with the row data.
|
||||
*/
|
||||
template<
|
||||
typename Container,
|
||||
typename std::enable_if<!std::is_same_v<Container, XLRowDataProxy> &&
|
||||
std::is_base_of_v<typename std::bidirectional_iterator_tag,
|
||||
typename std::iterator_traits<typename Container::iterator>::iterator_category>,
|
||||
Container>::type* = nullptr>
|
||||
explicit operator Container() const
|
||||
{
|
||||
return convertContainer<Container>();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Clears all values for the current row.
|
||||
*/
|
||||
void clear();
|
||||
|
||||
private:
|
||||
//---------- Private Member Functions ---------- //
|
||||
|
||||
/**
|
||||
* @brief Constructor.
|
||||
* @param row Pointer to the parent XLRow object.
|
||||
* @param rowNode Pointer to the underlying XML node representing the row.
|
||||
*/
|
||||
XLRowDataProxy(XLRow* row, XMLNode* rowNode);
|
||||
|
||||
/**
|
||||
* @brief Copy constructor.
|
||||
* @param other Object to be copied.
|
||||
* @note The copy constructor is private in order to prevent use of the auto keyword in client code.
|
||||
*/
|
||||
XLRowDataProxy(const XLRowDataProxy& other);
|
||||
|
||||
/**
|
||||
* @brief Move constructor.
|
||||
* @param other Object to be moved.
|
||||
* @note Made private, as move construction should only be allowed when the parent object is moved. Disallowed for client code.
|
||||
*/
|
||||
XLRowDataProxy(XLRowDataProxy&& other) noexcept;
|
||||
|
||||
/**
|
||||
* @brief Move assignment operator.
|
||||
* @param other Object to be moved.
|
||||
* @return Reference to the moved-to object.
|
||||
* @note Made private, as move assignment is disallowed for client code.
|
||||
*/
|
||||
XLRowDataProxy& operator=(XLRowDataProxy&& other) noexcept;
|
||||
|
||||
/**
|
||||
* @brief Get the cell values for the row.
|
||||
* @return A std::vector of XLCellValues.
|
||||
*/
|
||||
std::vector<XLCellValue> getValues() const;
|
||||
|
||||
/**
|
||||
* @brief Helper function for getting a pointer to the shared strings repository.
|
||||
* @return A pointer to an XLSharedStrings object.
|
||||
*/
|
||||
XLSharedStrings getSharedStrings() const;
|
||||
|
||||
/**
|
||||
* @brief Convenience function for erasing the first 'count' numbers of values in the row.
|
||||
* @param count The number of values to erase.
|
||||
*/
|
||||
void deleteCellValues(uint16_t count);
|
||||
|
||||
/**
|
||||
* @brief Convenience function for prepending a row value with a given column number.
|
||||
* @param value The XLCellValue object.
|
||||
* @param col The column of the value.
|
||||
*/
|
||||
void prependCellValue(const XLCellValue& value, uint16_t col);
|
||||
|
||||
/**
|
||||
* @brief Convenience function for converting the row data to a user-supplied container.
|
||||
* @details This function can convert row data to any user-supplied container that adheres to the design
|
||||
* of STL containers and supports bidirectional iterators. This could be std::vector, std::deque, or
|
||||
* std::list, but any container with the same interface should work.
|
||||
* @tparam Container The container (and value) type to be returned.
|
||||
* @return The row data in the required format.
|
||||
* @throws bad_variant_access if Container::value type is not XLCellValue and does not match the type contained.
|
||||
*/
|
||||
template<
|
||||
typename Container,
|
||||
typename std::enable_if<!std::is_same_v<Container, XLRowDataProxy> &&
|
||||
std::is_base_of_v<typename std::bidirectional_iterator_tag,
|
||||
typename std::iterator_traits<typename Container::iterator>::iterator_category>,
|
||||
Container>::type* = nullptr>
|
||||
Container convertContainer() const
|
||||
{
|
||||
Container c;
|
||||
auto it = std::inserter(c, c.end());
|
||||
for (const auto& v : getValues()) {
|
||||
// ===== If the value_type of the container is XLCellValue, the value can be assigned directly.
|
||||
if constexpr (std::is_same_v<typename Container::value_type, XLCellValue>) *it++ = v;
|
||||
|
||||
// ===== If the value_type is something else, the underlying value has to be extracted from the XLCellValue object.
|
||||
// ===== Note that if the type contained in the XLCellValue object does not match the value_type, a bad_variant_access
|
||||
// ===== exception will be thrown.
|
||||
else
|
||||
*it++ = v.get<typename Container::value_type>();
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
//---------- Private Member Variables ---------- //
|
||||
|
||||
XLRow* m_row { nullptr }; /**< Pointer to the parent XLRow object. */
|
||||
XMLNode* m_rowNode { nullptr }; /**< Pointer the the XML node representing the row. */
|
||||
};
|
||||
|
||||
} // namespace OpenXLSX
|
||||
|
||||
#pragma warning(pop)
|
||||
#endif // OPENXLSX_XLROWDATA_HPP
|
||||
+159
@@ -0,0 +1,159 @@
|
||||
/*
|
||||
|
||||
____ ____ ___ ____ ____ ____ ___
|
||||
6MMMMb `MM( )M' `MM' 6MMMMb\`MM( )M'
|
||||
8P Y8 `MM. d' MM 6M' ` `MM. d'
|
||||
6M Mb __ ____ ____ ___ __ `MM. d' MM MM `MM. d'
|
||||
MM MM `M6MMMMb 6MMMMb `MM 6MMb `MM. d' MM YM. `MM. d'
|
||||
MM MM MM' `Mb 6M' `Mb MMM9 `Mb `MMd MM YMMMMb `MMd
|
||||
MM MM MM MM MM MM MM' MM dMM. MM `Mb dMM.
|
||||
MM MM MM MM MMMMMMMM MM MM d'`MM. MM MM d'`MM.
|
||||
YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM.
|
||||
8b d8 MM. ,M9 YM d9 MM MM d' `MM. MM / L ,M9 d' `MM.
|
||||
YMMMM9 MMYMMM9 YMMMM9 _MM_ _MM_M(_ _)MM_ _MMMMMMM MYMMMM9 _M(_ _)MM_
|
||||
MM
|
||||
MM
|
||||
_MM_
|
||||
|
||||
Copyright (c) 2018, Kenneth Troldal Balslev
|
||||
|
||||
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.
|
||||
- Neither the name of the author nor the
|
||||
names of any 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 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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef OPENXLSX_XLSHAREDSTRINGS_HPP
|
||||
#define OPENXLSX_XLSHAREDSTRINGS_HPP
|
||||
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4251)
|
||||
#pragma warning(disable : 4275)
|
||||
|
||||
#include <deque>
|
||||
#include <string>
|
||||
|
||||
// ===== OpenXLSX Includes ===== //
|
||||
#include "OpenXLSX-Exports.hpp"
|
||||
#include "XLXmlFile.hpp"
|
||||
|
||||
namespace OpenXLSX
|
||||
{
|
||||
/**
|
||||
* @brief This class encapsulate the Excel concept of Shared Strings. In Excel, instead of havig individual strings
|
||||
* in each cell, cells have a reference to an entry in the SharedStrings register. This results in smalle file
|
||||
* sizes, as repeated strings are referenced easily.
|
||||
*/
|
||||
class OPENXLSX_EXPORT XLSharedStrings : public XLXmlFile
|
||||
{
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
// Public Member Functions
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief
|
||||
*/
|
||||
XLSharedStrings() = default;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param xmlData
|
||||
*/
|
||||
explicit XLSharedStrings(XLXmlData* xmlData, std::deque<std::string> *stringCache);
|
||||
|
||||
/**
|
||||
* @brief Destructor
|
||||
*/
|
||||
~XLSharedStrings();
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param other
|
||||
*/
|
||||
XLSharedStrings(const XLSharedStrings& other) = default;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param other
|
||||
*/
|
||||
XLSharedStrings(XLSharedStrings&& other) noexcept = default;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param other
|
||||
* @return
|
||||
*/
|
||||
XLSharedStrings& operator=(const XLSharedStrings& other) = default;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param other
|
||||
* @return
|
||||
*/
|
||||
XLSharedStrings& operator=(XLSharedStrings&& other) noexcept = default;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param str
|
||||
* @return
|
||||
*/
|
||||
int32_t getStringIndex(const std::string& str) const;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param str
|
||||
* @return
|
||||
*/
|
||||
bool stringExists(const std::string& str) const;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param index
|
||||
* @return
|
||||
*/
|
||||
const char* getString(uint32_t index) const;
|
||||
|
||||
/**
|
||||
* @brief Append a new string to the list of shared strings.
|
||||
* @param str The string to append.
|
||||
* @return A long int with the index of the appended string
|
||||
*/
|
||||
int32_t appendString(const std::string& str);
|
||||
|
||||
/**
|
||||
* @brief Clear the string at the given index.
|
||||
* @param index The index to clear.
|
||||
* @note There is no 'deleteString' member function, as deleting a shared string node will invalidate the
|
||||
* shared string indices for the cells in the spreadsheet. Instead use this member functions, which clears
|
||||
* the contents of the string, but keeps the XMLNode holding the string.
|
||||
*/
|
||||
void clearString(uint64_t index);
|
||||
|
||||
private:
|
||||
std::deque<std::string> *m_stringCache {}; /** < Each string must have an unchanging memory address; hence the use of std::deque */
|
||||
};
|
||||
} // namespace OpenXLSX
|
||||
|
||||
#pragma warning(pop)
|
||||
#endif // OPENXLSX_XLSHAREDSTRINGS_HPP
|
||||
Vendored
+737
@@ -0,0 +1,737 @@
|
||||
/*
|
||||
|
||||
____ ____ ___ ____ ____ ____ ___
|
||||
6MMMMb `MM( )M' `MM' 6MMMMb\`MM( )M'
|
||||
8P Y8 `MM. d' MM 6M' ` `MM. d'
|
||||
6M Mb __ ____ ____ ___ __ `MM. d' MM MM `MM. d'
|
||||
MM MM `M6MMMMb 6MMMMb `MM 6MMb `MM. d' MM YM. `MM. d'
|
||||
MM MM MM' `Mb 6M' `Mb MMM9 `Mb `MMd MM YMMMMb `MMd
|
||||
MM MM MM MM MM MM MM' MM dMM. MM `Mb dMM.
|
||||
MM MM MM MM MMMMMMMM MM MM d'`MM. MM MM d'`MM.
|
||||
YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM.
|
||||
8b d8 MM. ,M9 YM d9 MM MM d' `MM. MM / L ,M9 d' `MM.
|
||||
YMMMM9 MMYMMM9 YMMMM9 _MM_ _MM_M(_ _)MM_ _MMMMMMM MYMMMM9 _M(_ _)MM_
|
||||
MM
|
||||
MM
|
||||
_MM_
|
||||
|
||||
Copyright (c) 2018, Kenneth Troldal Balslev
|
||||
|
||||
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.
|
||||
- Neither the name of the author nor the
|
||||
names of any 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 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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef OPENXLSX_XLSHEET_HPP
|
||||
#define OPENXLSX_XLSHEET_HPP
|
||||
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4251)
|
||||
#pragma warning(disable : 4275)
|
||||
|
||||
// ===== External Includes ===== //
|
||||
#include <type_traits>
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
|
||||
// ===== OpenXLSX Includes ===== //
|
||||
#include "OpenXLSX-Exports.hpp"
|
||||
#include "XLCell.hpp"
|
||||
#include "XLCellReference.hpp"
|
||||
#include "XLColor.hpp"
|
||||
#include "XLColumn.hpp"
|
||||
#include "XLCommandQuery.hpp"
|
||||
#include "XLDocument.hpp"
|
||||
#include "XLException.hpp"
|
||||
#include "XLRow.hpp"
|
||||
#include "XLXmlFile.hpp"
|
||||
|
||||
namespace OpenXLSX
|
||||
{
|
||||
/**
|
||||
* @brief The XLSheetState is an enumeration of the possible (visibility) states, e.g. Visible or Hidden.
|
||||
*/
|
||||
enum class XLSheetState { Visible, Hidden, VeryHidden };
|
||||
|
||||
/**
|
||||
* @brief The XLSheetBase class is the base class for the XLWorksheet and XLChartsheet classes. However,
|
||||
* it is not a base class in the traditional sense. Rather, it provides common functionality that is
|
||||
* inherited via the CRTP (Curiously Recurring Template Pattern) pattern.
|
||||
* @tparam T Type that will inherit functionality. Restricted to types XLWorksheet and XLChartsheet.
|
||||
*/
|
||||
template<typename T, typename std::enable_if<std::is_same_v<T, XLWorksheet> || std::is_same_v<T, XLChartsheet>>::type* = nullptr>
|
||||
class OPENXLSX_EXPORT XLSheetBase : public XLXmlFile
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Constructor
|
||||
*/
|
||||
XLSheetBase() : XLXmlFile(nullptr) {};
|
||||
|
||||
/**
|
||||
* @brief The constructor. There are no default constructor, so all parameters must be provided for
|
||||
* constructing an XLAbstractSheet object. Since this is a pure abstract class, instantiation is only
|
||||
* possible via one of the derived classes.
|
||||
* @param xmlData
|
||||
*/
|
||||
explicit XLSheetBase(XLXmlData* xmlData) : XLXmlFile(xmlData) {};
|
||||
|
||||
/**
|
||||
* @brief The copy constructor.
|
||||
* @param other The object to be copied.
|
||||
* @note The default copy constructor is used, i.e. only shallow copying of pointer data members.
|
||||
*/
|
||||
XLSheetBase(const XLSheetBase& other) = default;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param other
|
||||
*/
|
||||
XLSheetBase(XLSheetBase&& other) noexcept = default;
|
||||
|
||||
/**
|
||||
* @brief The destructor
|
||||
* @note The default destructor is used, since cleanup of pointer data members is not required.
|
||||
*/
|
||||
~XLSheetBase() = default;
|
||||
|
||||
/**
|
||||
* @brief Assignment operator
|
||||
* @return A reference to the new object.
|
||||
* @note The default assignment operator is used, i.e. only shallow copying of pointer data members.
|
||||
*/
|
||||
XLSheetBase& operator=(const XLSheetBase&) = default;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param other
|
||||
* @return
|
||||
*/
|
||||
XLSheetBase& operator=(XLSheetBase&& other) noexcept = default;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @return
|
||||
*/
|
||||
XLSheetState visibility() const
|
||||
{
|
||||
XLQuery query(XLQueryType::QuerySheetVisibility);
|
||||
query.setParam("sheetID", relationshipID());
|
||||
auto state = parentDoc().execQuery(query).template result<std::string>();
|
||||
auto result = XLSheetState::Visible;
|
||||
|
||||
if (state == "visible" || state.empty()) {
|
||||
result = XLSheetState::Visible;
|
||||
}
|
||||
else if (state == "hidden") {
|
||||
result = XLSheetState::Hidden;
|
||||
}
|
||||
else if (state == "veryHidden") {
|
||||
result = XLSheetState::VeryHidden;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param state
|
||||
*/
|
||||
void setVisibility(XLSheetState state)
|
||||
{
|
||||
auto stateString = std::string();
|
||||
switch (state) {
|
||||
case XLSheetState::Visible:
|
||||
stateString = "visible";
|
||||
break;
|
||||
|
||||
case XLSheetState::Hidden:
|
||||
stateString = "hidden";
|
||||
break;
|
||||
|
||||
case XLSheetState::VeryHidden:
|
||||
stateString = "veryHidden";
|
||||
break;
|
||||
}
|
||||
|
||||
parentDoc().execCommand(XLCommand(XLCommandType::SetSheetVisibility)
|
||||
.setParam("sheetID", relationshipID())
|
||||
.setParam("sheetVisibility", stateString));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @return
|
||||
* @todo To be implemented.
|
||||
*/
|
||||
XLColor color() const
|
||||
{
|
||||
return static_cast<const T&>(*this).getColor_impl();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param color
|
||||
*/
|
||||
void setColor(const XLColor& color)
|
||||
{
|
||||
static_cast<T&>(*this).setColor_impl(color);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @return
|
||||
*/
|
||||
uint16_t index() const
|
||||
{
|
||||
// return uint16_t(std::stoi(parentDoc().execQuery(R"({ "query": "QuerySheetIndex", "sheetID": ")" + relationshipID() + "\"}")));
|
||||
|
||||
XLQuery query(XLQueryType::QuerySheetIndex);
|
||||
query.setParam("sheetID", relationshipID());
|
||||
return uint16_t(std::stoi(parentDoc().execQuery(query).template result<std::string>()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param index
|
||||
*/
|
||||
void setIndex(uint16_t index)
|
||||
{
|
||||
parentDoc().execCommand(XLCommand(XLCommandType::SetSheetIndex)
|
||||
.setParam("sheetID", relationshipID())
|
||||
.setParam("sheetIndex", index));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Method to retrieve the name of the sheet.
|
||||
* @return A std::string with the sheet name.
|
||||
*/
|
||||
std::string name() const
|
||||
{
|
||||
XLQuery query(XLQueryType::QuerySheetName);
|
||||
query.setParam("sheetID", relationshipID());
|
||||
return parentDoc().execQuery(query).template result<std::string>();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Method for renaming the sheet.
|
||||
* @param sheetName A std::string with the new name.
|
||||
*/
|
||||
void setName(const std::string& sheetName)
|
||||
{
|
||||
parentDoc().execCommand(XLCommand(XLCommandType::SetSheetName)
|
||||
.setParam("sheetID", relationshipID())
|
||||
.setParam("sheetName", name())
|
||||
.setParam("newName", sheetName));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @return
|
||||
*/
|
||||
bool isSelected() const
|
||||
{
|
||||
return static_cast<const T&>(*this).isSelected_impl();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param selected
|
||||
*/
|
||||
void setSelected(bool selected)
|
||||
{
|
||||
static_cast<T&>(*this).setSelected_impl(selected);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @return
|
||||
*/
|
||||
bool isActive() const
|
||||
{
|
||||
return static_cast<const T&>(*this).isActive_impl();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param active
|
||||
*/
|
||||
void setActive()
|
||||
{
|
||||
static_cast<T&>(*this).setActive_impl();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Method for cloning the sheet.
|
||||
* @param newName A std::string with the name of the clone
|
||||
* @return A pointer to the cloned object.
|
||||
* @note This is a pure abstract method. I.e. it is implemented in subclasses.
|
||||
*/
|
||||
void clone(const std::string& newName)
|
||||
{
|
||||
parentDoc().execCommand(XLCommand(XLCommandType::CloneSheet)
|
||||
.setParam("sheetID", relationshipID())
|
||||
.setParam("cloneName", newName));
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A class encapsulating an Excel worksheet. Access to XLWorksheet objects should be via the workbook object.
|
||||
*/
|
||||
class OPENXLSX_EXPORT XLWorksheet final : public XLSheetBase<XLWorksheet>
|
||||
{
|
||||
friend class XLCell;
|
||||
friend class XLRow;
|
||||
friend class XLWorkbook;
|
||||
friend class XLSheetBase<XLWorksheet>;
|
||||
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
// Public Member Functions
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Default constructor
|
||||
*/
|
||||
XLWorksheet() : XLSheetBase(nullptr) {};
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param xmlData
|
||||
*/
|
||||
explicit XLWorksheet(XLXmlData* xmlData);
|
||||
|
||||
/**
|
||||
* @brief Copy Constructor.
|
||||
* @note The copy constructor has been explicitly deleted.
|
||||
*/
|
||||
XLWorksheet(const XLWorksheet& other) = default;
|
||||
|
||||
/**
|
||||
* @brief Move Constructor.
|
||||
* @note The move constructor has been explicitly deleted.
|
||||
*/
|
||||
XLWorksheet(XLWorksheet&& other) = default;
|
||||
|
||||
/**
|
||||
* @brief Destructor.
|
||||
*/
|
||||
~XLWorksheet();
|
||||
|
||||
/**
|
||||
* @brief Copy assignment operator.
|
||||
* @note The copy assignment operator has been explicitly deleted.
|
||||
*/
|
||||
XLWorksheet& operator=(const XLWorksheet& other) = default;
|
||||
|
||||
/**
|
||||
* @brief Move assignment operator.
|
||||
* @note The move assignment operator has been explicitly deleted.
|
||||
*/
|
||||
XLWorksheet& operator=(XLWorksheet&& other) = default;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param ref
|
||||
* @return
|
||||
*/
|
||||
XLCell cell(const std::string& ref) const;
|
||||
|
||||
/**
|
||||
* @brief Get a pointer to the XLCell object for the given cell reference.
|
||||
* @param ref An XLCellReference object with the address of the cell to get.
|
||||
* @return A const reference to the requested XLCell object.
|
||||
*/
|
||||
XLCell cell(const XLCellReference& ref) const;
|
||||
|
||||
/**
|
||||
* @brief Get the cell at the given coordinates.
|
||||
* @param rowNumber The row number (index base 1).
|
||||
* @param columnNumber The column number (index base 1).
|
||||
* @return A reference to the XLCell object at the given coordinates.
|
||||
*/
|
||||
XLCell cell(uint32_t rowNumber, uint16_t columnNumber) const;
|
||||
|
||||
/**
|
||||
* @brief Get a range for the area currently in use (i.e. from cell A1 to the last cell being in use).
|
||||
* @return A const XLCellRange object with the entire range.
|
||||
*/
|
||||
XLCellRange range() const;
|
||||
|
||||
/**
|
||||
* @brief Get a range with the given coordinates.
|
||||
* @param topLeft An XLCellReference object with the coordinates to the top left cell.
|
||||
* @param bottomRight An XLCellReference object with the coordinates to the bottom right cell.
|
||||
* @return A const XLCellRange object with the requested range.
|
||||
*/
|
||||
XLCellRange range(const XLCellReference& topLeft, const XLCellReference& bottomRight) const;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @return
|
||||
*/
|
||||
XLRowRange rows() const;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param rowCount
|
||||
* @return
|
||||
*/
|
||||
XLRowRange rows(uint32_t rowCount) const;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param firstRow
|
||||
* @param lastRow
|
||||
* @return
|
||||
*/
|
||||
XLRowRange rows(uint32_t firstRow, uint32_t lastRow) const;
|
||||
|
||||
/**
|
||||
* @brief Get the row with the given row number.
|
||||
* @param rowNumber The number of the row to retrieve.
|
||||
* @return A pointer to the XLRow object.
|
||||
*/
|
||||
XLRow row(uint32_t rowNumber) const;
|
||||
|
||||
/**
|
||||
* @brief Get the column with the given column number.
|
||||
* @param columnNumber The number of the column to retrieve.
|
||||
* @return A pointer to the XLColumn object.
|
||||
*/
|
||||
XLColumn column(uint16_t columnNumber) const;
|
||||
|
||||
/**
|
||||
* @brief Get an XLCellReference to the last (bottom right) cell in the worksheet.
|
||||
* @return An XLCellReference for the last cell.
|
||||
*/
|
||||
XLCellReference lastCell() const noexcept;
|
||||
|
||||
/**
|
||||
* @brief Get the number of columns in the worksheet.
|
||||
* @return The number of columns.
|
||||
*/
|
||||
uint16_t columnCount() const noexcept;
|
||||
|
||||
/**
|
||||
* @brief Get the number of rows in the worksheet.
|
||||
* @return The number of rows.
|
||||
*/
|
||||
uint32_t rowCount() const noexcept;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param oldName
|
||||
* @param newName
|
||||
*/
|
||||
void updateSheetName(const std::string& oldName, const std::string& newName);
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @return
|
||||
*/
|
||||
XLColor getColor_impl() const;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param color
|
||||
*/
|
||||
void setColor_impl(const XLColor& color);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @return
|
||||
*/
|
||||
bool isSelected_impl() const;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param selected
|
||||
*/
|
||||
void setSelected_impl(bool selected);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @return
|
||||
*/
|
||||
bool isActive_impl() const;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param selected
|
||||
*/
|
||||
void setActive_impl();
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Class representing the an Excel chartsheet.
|
||||
* @todo This class is largely unimplemented and works just as a placeholder.
|
||||
*/
|
||||
class OPENXLSX_EXPORT XLChartsheet final : public XLSheetBase<XLChartsheet>
|
||||
{
|
||||
friend class XLSheetBase<XLChartsheet>;
|
||||
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
// Public Member Functions
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Default constructor
|
||||
*/
|
||||
XLChartsheet() : XLSheetBase(nullptr) {};
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param xmlData
|
||||
*/
|
||||
explicit XLChartsheet(XLXmlData* xmlData);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param other
|
||||
*/
|
||||
XLChartsheet(const XLChartsheet& other) = default;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param other
|
||||
*/
|
||||
XLChartsheet(XLChartsheet&& other) noexcept = default;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*/
|
||||
~XLChartsheet();
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @return
|
||||
*/
|
||||
XLChartsheet& operator=(const XLChartsheet& other) = default;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param other
|
||||
* @return
|
||||
*/
|
||||
XLChartsheet& operator=(XLChartsheet&& other) noexcept = default;
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @return
|
||||
*/
|
||||
XLColor getColor_impl() const;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param color
|
||||
*/
|
||||
void setColor_impl(const XLColor& color);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @return
|
||||
*/
|
||||
bool isSelected_impl() const;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param selected
|
||||
*/
|
||||
void setSelected_impl(bool selected);
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief The XLAbstractSheet is a generalized sheet class, which functions as superclass for specialized classes,
|
||||
* such as XLWorksheet. It implements functionality common to all sheet types. This is a pure abstract class,
|
||||
* so it cannot be instantiated.
|
||||
*/
|
||||
class OPENXLSX_EXPORT XLSheet final : public XLXmlFile
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief The constructor. There are no default constructor, so all parameters must be provided for
|
||||
* constructing an XLAbstractSheet object. Since this is a pure abstract class, instantiation is only
|
||||
* possible via one of the derived classes.
|
||||
* @param xmlData
|
||||
*/
|
||||
explicit XLSheet(XLXmlData* xmlData);
|
||||
|
||||
/**
|
||||
* @brief The copy constructor.
|
||||
* @param other The object to be copied.
|
||||
* @note The default copy constructor is used, i.e. only shallow copying of pointer data members.
|
||||
*/
|
||||
XLSheet(const XLSheet& other) = default;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param other
|
||||
*/
|
||||
XLSheet(XLSheet&& other) noexcept = default;
|
||||
|
||||
/**
|
||||
* @brief The destructor
|
||||
* @note The default destructor is used, since cleanup of pointer data members is not required.
|
||||
*/
|
||||
~XLSheet() = default;
|
||||
|
||||
/**
|
||||
* @brief Assignment operator
|
||||
* @return A reference to the new object.
|
||||
* @note The default assignment operator is used, i.e. only shallow copying of pointer data members.
|
||||
*/
|
||||
XLSheet& operator=(const XLSheet& other) = default;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param other
|
||||
* @return
|
||||
*/
|
||||
XLSheet& operator=(XLSheet&& other) noexcept = default;
|
||||
|
||||
/**
|
||||
* @brief Method for getting the current visibility state of the sheet.
|
||||
* @return An XLSheetState enum object, with the current sheet state.
|
||||
*/
|
||||
XLSheetState visibility() const;
|
||||
|
||||
/**
|
||||
* @brief Method for setting the state of the sheet.
|
||||
* @param state An XLSheetState enum object with the new state.
|
||||
* @bug For some reason, this method doesn't work. The data is written correctly to the xml file, but the sheet
|
||||
* is not hidden when opening the file in Excel.
|
||||
*/
|
||||
void setVisibility(XLSheetState state);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @return
|
||||
*/
|
||||
XLColor color() const;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param color
|
||||
*/
|
||||
void setColor(const XLColor& color);
|
||||
|
||||
/**
|
||||
* @brief Method for getting the index of the sheet.
|
||||
* @return An int with the index of the sheet.
|
||||
*/
|
||||
uint16_t index() const;
|
||||
|
||||
/**
|
||||
* @brief Method for setting the index of the sheet. This effectively moves the sheet to a different position.
|
||||
*/
|
||||
void setIndex(uint16_t index);
|
||||
|
||||
/**
|
||||
* @brief Method to retrieve the name of the sheet.
|
||||
* @return A std::string with the sheet name.
|
||||
*/
|
||||
std::string name() const;
|
||||
|
||||
/**
|
||||
* @brief Method for renaming the sheet.
|
||||
* @param name A std::string with the new name.
|
||||
*/
|
||||
void setName(const std::string& name);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param selected
|
||||
*/
|
||||
void setSelected(bool selected);
|
||||
|
||||
/**
|
||||
* @brief Method to get the type of the sheet.
|
||||
* @return An XLSheetType enum object with the sheet type.
|
||||
*/
|
||||
template<
|
||||
typename SheetType,
|
||||
typename std::enable_if<std::is_same_v<SheetType, XLWorksheet> || std::is_same_v<SheetType, XLChartsheet>>::type* = nullptr>
|
||||
bool isType() const
|
||||
{
|
||||
return std::holds_alternative<SheetType>(m_sheet);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Method for cloning the sheet.
|
||||
* @param newName A std::string with the name of the clone
|
||||
* @return A pointer to the cloned object.
|
||||
* @note This is a pure abstract method. I.e. it is implemented in subclasses.
|
||||
*/
|
||||
void clone(const std::string& newName);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @tparam T
|
||||
* @return
|
||||
*/
|
||||
template<typename T, typename std::enable_if<std::is_same_v<T, XLWorksheet> || std::is_same_v<T, XLChartsheet>>::type* = nullptr>
|
||||
T get() const
|
||||
{
|
||||
try {
|
||||
if constexpr (std::is_same<T, XLWorksheet>::value)
|
||||
return std::get<XLWorksheet>(m_sheet);
|
||||
|
||||
else if constexpr (std::is_same<T, XLChartsheet>::value)
|
||||
return std::get<XLChartsheet>(m_sheet);
|
||||
}
|
||||
|
||||
catch (const std::bad_variant_access&) {
|
||||
throw XLSheetError("XLSheet object does not contain the requested sheet type.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @return
|
||||
*/
|
||||
operator XLWorksheet() const; // NOLINT
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @return
|
||||
*/
|
||||
operator XLChartsheet() const; // NOLINT
|
||||
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
// Private Member Variables
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
private:
|
||||
std::variant<XLWorksheet, XLChartsheet> m_sheet; /**< */
|
||||
};
|
||||
} // namespace OpenXLSX
|
||||
|
||||
#pragma warning(pop)
|
||||
#endif // OPENXLSX_XLSHEET_HPP
|
||||
+373
@@ -0,0 +1,373 @@
|
||||
/*
|
||||
|
||||
____ ____ ___ ____ ____ ____ ___
|
||||
6MMMMb `MM( )M' `MM' 6MMMMb\`MM( )M'
|
||||
8P Y8 `MM. d' MM 6M' ` `MM. d'
|
||||
6M Mb __ ____ ____ ___ __ `MM. d' MM MM `MM. d'
|
||||
MM MM `M6MMMMb 6MMMMb `MM 6MMb `MM. d' MM YM. `MM. d'
|
||||
MM MM MM' `Mb 6M' `Mb MMM9 `Mb `MMd MM YMMMMb `MMd
|
||||
MM MM MM MM MM MM MM' MM dMM. MM `Mb dMM.
|
||||
MM MM MM MM MMMMMMMM MM MM d'`MM. MM MM d'`MM.
|
||||
YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM.
|
||||
8b d8 MM. ,M9 YM d9 MM MM d' `MM. MM / L ,M9 d' `MM.
|
||||
YMMMM9 MMYMMM9 YMMMM9 _MM_ _MM_M(_ _)MM_ _MMMMMMM MYMMMM9 _M(_ _)MM_
|
||||
MM
|
||||
MM
|
||||
_MM_
|
||||
|
||||
Copyright (c) 2018, Kenneth Troldal Balslev
|
||||
|
||||
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.
|
||||
- Neither the name of the author nor the
|
||||
names of any 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 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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef OPENXLSX_XLWORKBOOK_HPP
|
||||
#define OPENXLSX_XLWORKBOOK_HPP
|
||||
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4251)
|
||||
#pragma warning(disable : 4275)
|
||||
|
||||
// ===== External Includes ===== //
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
|
||||
// ===== OpenXLSX Includes ===== //
|
||||
#include "OpenXLSX-Exports.hpp"
|
||||
#include "XLCommandQuery.hpp"
|
||||
#include "XLContentTypes.hpp"
|
||||
#include "XLException.hpp"
|
||||
#include "XLRelationships.hpp"
|
||||
#include "XLXmlFile.hpp"
|
||||
|
||||
namespace OpenXLSX
|
||||
{
|
||||
class XLSharedStrings;
|
||||
|
||||
class XLSheet;
|
||||
|
||||
class XLWorksheet;
|
||||
|
||||
class XLChartsheet;
|
||||
|
||||
/**
|
||||
* @brief The XLSheetType class is an enumeration of the available sheet types, e.g. Worksheet (ordinary
|
||||
* spreadsheets), and Chartsheet (sheets with only a chart).
|
||||
*/
|
||||
enum class XLSheetType { Worksheet, Chartsheet, Dialogsheet, Macrosheet };
|
||||
|
||||
/**
|
||||
* @brief This class encapsulates the concept of a Workbook. It provides access to the individual sheets
|
||||
* (worksheets or chartsheets), as well as functionality for adding, deleting, moving and renaming sheets.
|
||||
*/
|
||||
class OPENXLSX_EXPORT XLWorkbook : public XLXmlFile
|
||||
{
|
||||
friend class XLSheet;
|
||||
friend class XLDocument;
|
||||
|
||||
public: // ---------- Public Member Functions ---------- //
|
||||
/**
|
||||
* @brief Default constructor. Creates an empty ('null') XLWorkbook object.
|
||||
*/
|
||||
XLWorkbook() = default;
|
||||
|
||||
/**
|
||||
* @brief Constructor. Takes a pointer to an XLXmlData object (stored in the parent XLDocument object).
|
||||
* @param xmlData A pointer to the underlying XLXmlData object, which holds the XML data.
|
||||
* @note Do not create an XLWorkbook object directly. Get access through the an XLDocument object.
|
||||
*/
|
||||
explicit XLWorkbook(XLXmlData* xmlData);
|
||||
|
||||
/**
|
||||
* @brief Copy Constructor.
|
||||
* @param other The XLWorkbook object to be copied.
|
||||
* @note The copy constructor has been explicitly defaulted.
|
||||
*/
|
||||
XLWorkbook(const XLWorkbook& other) = default;
|
||||
|
||||
/**
|
||||
* @brief Move constructor.
|
||||
* @param other The XLWorkbook to be moved.
|
||||
* @note The move constructor has been explicitly defaulted.
|
||||
*/
|
||||
XLWorkbook(XLWorkbook&& other) = default;
|
||||
|
||||
/**
|
||||
* @brief Destructor
|
||||
* @note Default destructor specified
|
||||
*/
|
||||
~XLWorkbook();
|
||||
|
||||
/**
|
||||
* @brief Copy assignment operator.
|
||||
* @param other The XLWorkbook object to be assigned to the current.
|
||||
* @return A reference to *this
|
||||
* @note The copy assignment operator has been explicitly deleted, as XLWorkbook objects should not be copied.
|
||||
*/
|
||||
XLWorkbook& operator=(const XLWorkbook& other) = default;
|
||||
|
||||
/**
|
||||
* @brief Move assignment operator.
|
||||
* @param other The XLWorkbook to be move assigned.
|
||||
* @return A reference to *this
|
||||
* @note The move assignment operator has been explicitly deleted, as XLWorkbook objects should not be moved.
|
||||
*/
|
||||
XLWorkbook& operator=(XLWorkbook&& other) = default;
|
||||
|
||||
/**
|
||||
* @brief Get the sheet (worksheet or chartsheet) at the given index.
|
||||
* @param index The index at which the desired sheet is located.
|
||||
* @return A pointer to an XLAbstractSheet with the sheet at the index.
|
||||
* @note The index must be 1-based (rather than 0-based) as this is the default for Excel spreadsheets.
|
||||
*/
|
||||
XLSheet sheet(uint16_t index);
|
||||
|
||||
/**
|
||||
* @brief Get the sheet (worksheet or chartsheet) with the given name.
|
||||
* @param sheetName The name at which the desired sheet is located.
|
||||
* @return A pointer to an XLAbstractSheet with the sheet at the index.
|
||||
*/
|
||||
XLSheet sheet(const std::string& sheetName);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param sheetName
|
||||
* @return
|
||||
*/
|
||||
XLWorksheet worksheet(const std::string& sheetName);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param sheetName
|
||||
* @return
|
||||
*/
|
||||
XLChartsheet chartsheet(const std::string& sheetName);
|
||||
|
||||
/**
|
||||
* @brief Delete sheet (worksheet or chartsheet) from the workbook.
|
||||
* @param sheetName Name of the sheet to delete.
|
||||
* @throws XLException An exception will be thrown if trying to delete the last worksheet in the workbook
|
||||
* @warning A workbook must contain at least one worksheet. Trying to delete the last worksheet from the
|
||||
* workbook will trow an exception.
|
||||
*/
|
||||
void deleteSheet(const std::string& sheetName);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param sheetName
|
||||
*/
|
||||
void addWorksheet(const std::string& sheetName);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param existingName
|
||||
* @param newName
|
||||
*/
|
||||
void cloneSheet(const std::string& existingName, const std::string& newName);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param sheetName
|
||||
* @param index
|
||||
*/
|
||||
void setSheetIndex(const std::string& sheetName, unsigned int index);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param sheetName
|
||||
* @return
|
||||
*/
|
||||
unsigned int indexOfSheet(const std::string& sheetName) const;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param sheetName
|
||||
* @return
|
||||
*/
|
||||
XLSheetType typeOfSheet(const std::string& sheetName) const;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param index
|
||||
* @return
|
||||
*/
|
||||
XLSheetType typeOfSheet(unsigned int index) const;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @return
|
||||
*/
|
||||
unsigned int sheetCount() const;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @return
|
||||
*/
|
||||
unsigned int worksheetCount() const;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @return
|
||||
*/
|
||||
unsigned int chartsheetCount() const;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @return
|
||||
*/
|
||||
std::vector<std::string> sheetNames() const;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @return
|
||||
*/
|
||||
std::vector<std::string> worksheetNames() const;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @return
|
||||
*/
|
||||
std::vector<std::string> chartsheetNames() const;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param sheetName
|
||||
* @return
|
||||
*/
|
||||
bool sheetExists(const std::string& sheetName) const;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param sheetName
|
||||
* @return
|
||||
*/
|
||||
bool worksheetExists(const std::string& sheetName) const;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param sheetName
|
||||
* @return
|
||||
*/
|
||||
bool chartsheetExists(const std::string& sheetName) const;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param oldName
|
||||
* @param newName
|
||||
*/
|
||||
void updateSheetReferences(const std::string& oldName, const std::string& newName);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @return
|
||||
*/
|
||||
XLSharedStrings sharedStrings();
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @return
|
||||
*/
|
||||
bool hasSharedStrings() const;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*/
|
||||
void deleteNamedRanges();
|
||||
|
||||
/**
|
||||
* @brief set a flag to force full calculation upon loading the file in Excel
|
||||
*/
|
||||
void setFullCalculationOnLoad();
|
||||
|
||||
private: // ---------- Private Member Functions ---------- //
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @return
|
||||
*/
|
||||
uint16_t createInternalSheetID();
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param sheetName
|
||||
* @return
|
||||
*/
|
||||
std::string sheetID(const std::string& sheetName);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param sheetID
|
||||
* @return
|
||||
*/
|
||||
std::string sheetName(const std::string& sheetID) const;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param sheetID
|
||||
* @return
|
||||
*/
|
||||
std::string sheetVisibility(const std::string& sheetID) const;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param sheetName
|
||||
* @param internalID
|
||||
*/
|
||||
void prepareSheetMetadata(const std::string& sheetName, uint16_t internalID);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param sheetRID
|
||||
* @param newName
|
||||
*/
|
||||
void setSheetName(const std::string& sheetRID, const std::string& newName);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param sheetRID
|
||||
* @param state
|
||||
*/
|
||||
void setSheetVisibility(const std::string& sheetRID, const std::string& state);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param sheetRID
|
||||
* @return
|
||||
*/
|
||||
bool sheetIsActive(const std::string& sheetRID) const;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param sheetRID
|
||||
* @param state
|
||||
*/
|
||||
void setSheetActive(const std::string& sheetRID);
|
||||
|
||||
|
||||
};
|
||||
} // namespace OpenXLSX
|
||||
|
||||
#pragma warning(pop)
|
||||
#endif // OPENXLSX_XLWORKBOOK_HPP
|
||||
Vendored
+202
@@ -0,0 +1,202 @@
|
||||
/*
|
||||
|
||||
____ ____ ___ ____ ____ ____ ___
|
||||
6MMMMb `MM( )M' `MM' 6MMMMb\`MM( )M'
|
||||
8P Y8 `MM. d' MM 6M' ` `MM. d'
|
||||
6M Mb __ ____ ____ ___ __ `MM. d' MM MM `MM. d'
|
||||
MM MM `M6MMMMb 6MMMMb `MM 6MMb `MM. d' MM YM. `MM. d'
|
||||
MM MM MM' `Mb 6M' `Mb MMM9 `Mb `MMd MM YMMMMb `MMd
|
||||
MM MM MM MM MM MM MM' MM dMM. MM `Mb dMM.
|
||||
MM MM MM MM MMMMMMMM MM MM d'`MM. MM MM d'`MM.
|
||||
YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM.
|
||||
8b d8 MM. ,M9 YM d9 MM MM d' `MM. MM / L ,M9 d' `MM.
|
||||
YMMMM9 MMYMMM9 YMMMM9 _MM_ _MM_M(_ _)MM_ _MMMMMMM MYMMMM9 _M(_ _)MM_
|
||||
MM
|
||||
MM
|
||||
_MM_
|
||||
|
||||
Copyright (c) 2018, Kenneth Troldal Balslev
|
||||
|
||||
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.
|
||||
- Neither the name of the author nor the
|
||||
names of any 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 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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef OPENXLSX_XLXMLDATA_HPP
|
||||
#define OPENXLSX_XLXMLDATA_HPP
|
||||
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4251)
|
||||
#pragma warning(disable : 4275)
|
||||
|
||||
// ===== External Includes ===== //
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
// ===== OpenXLSX Includes ===== //
|
||||
#include "OpenXLSX-Exports.hpp"
|
||||
#include "XLContentTypes.hpp"
|
||||
#include "XLXmlParser.hpp"
|
||||
|
||||
namespace OpenXLSX
|
||||
{
|
||||
/**
|
||||
* @brief The XLXmlData class encapsulates the properties and behaviour of the .xml files in an .xlsx file zip
|
||||
* package. Objects of the XLXmlData type are intended to be stored centrally in an XLDocument object, from where
|
||||
* they can be retrieved by other objects that encapsulates the behaviour of Excel elements, such as XLWorkbook
|
||||
* and XLWorksheet.
|
||||
*/
|
||||
class OPENXLSX_EXPORT XLXmlData final
|
||||
{
|
||||
public:
|
||||
// ===== PUBLIC MEMBER FUNCTIONS ===== //
|
||||
|
||||
/**
|
||||
* @brief Default constructor. All member variables are default constructed. Except for
|
||||
* the raw XML data, none of the member variables can be modified after construction. Hence, objects created
|
||||
* using the default constructor can only serve as null objects and targets for the move assignemnt operator.
|
||||
*/
|
||||
XLXmlData() = default;
|
||||
|
||||
/**
|
||||
* @brief Constructor. This constructor creates objects with the given parameters. the xmlId and the xmlType
|
||||
* parameters have default values. These are only useful for relationship (.rels) files and the
|
||||
* [Content_Types].xml file located in the root directory of the zip package.
|
||||
* @param parentDoc A pointer to the parent XLDocument object.
|
||||
* @param xmlPath A std::string with the file path in zip package.
|
||||
* @param xmlId A std::string with the relationship ID of the file (used in the XLRelationships class)
|
||||
* @param xmlType The type of object the XML file represents, e.g. XLWorkbook or XLWorksheet.
|
||||
*/
|
||||
XLXmlData(XLDocument* parentDoc,
|
||||
const std::string& xmlPath,
|
||||
const std::string& xmlId = "",
|
||||
XLContentType xmlType = XLContentType::Unknown);
|
||||
|
||||
/**
|
||||
* @brief Default destructor. The XLXmlData does not manage any dynamically allocated resources, so a default
|
||||
* destructor will suffice.
|
||||
*/
|
||||
~XLXmlData();
|
||||
|
||||
/**
|
||||
* @brief Copy constructor. The m_xmlDoc data member is a XMLDocument object, which is non-copyable. Hence,
|
||||
* the XLXmlData objects have a explicitly deleted copy constructor.
|
||||
* @param other
|
||||
*/
|
||||
XLXmlData(const XLXmlData& other) = delete;
|
||||
|
||||
/**
|
||||
* @brief Move constructor. All data members are trivially movable. Hence an explicitly defaulted move
|
||||
* constructor is sufficient.
|
||||
* @param other
|
||||
*/
|
||||
XLXmlData(XLXmlData&& other) noexcept = default;
|
||||
|
||||
/**
|
||||
* @brief Copy assignment operator. The m_xmlDoc data member is a XMLDocument object, which is non-copyable.
|
||||
* Hence, the XLXmlData objects have a explicitly deleted copy assignment operator.
|
||||
*/
|
||||
XLXmlData& operator=(const XLXmlData& other) = delete;
|
||||
|
||||
/**
|
||||
* @brief Move assignment operator. All data members are trivially movable. Hence an explicitly defaulted move
|
||||
* constructor is sufficient.
|
||||
* @param other the XLXmlData object to be moved from.
|
||||
* @return A reference to the moved-to object.
|
||||
*/
|
||||
XLXmlData& operator=(XLXmlData&& other) noexcept = default;
|
||||
|
||||
/**
|
||||
* @brief Set the raw data for the underlying XML document. Being able to set the XML data directly is useful
|
||||
* when creating a new file using a XML file template. E.g., when creating a new worksheet, the XML code for
|
||||
* a minimum viable XLWorksheet object can be added using this function.
|
||||
* @param data A std::string with the raw XML text.
|
||||
*/
|
||||
void setRawData(const std::string& data);
|
||||
|
||||
/**
|
||||
* @brief Get the raw data for the underlying XML document. This function will retrieve the raw XML text data
|
||||
* from the underlying XMLDocument object. This will mainly be used when saving data to the .xlsx package
|
||||
* using the save function in the XLDocument class.
|
||||
* @return A std::string with the raw XML text data.
|
||||
*/
|
||||
std::string getRawData() const;
|
||||
|
||||
/**
|
||||
* @brief Access the parent XLDocument object.
|
||||
* @return A pointer to the parent XLDocument object.
|
||||
*/
|
||||
XLDocument* getParentDoc();
|
||||
|
||||
/**
|
||||
* @brief Access the parent XLDocument object.
|
||||
* @return A const pointer to the parent XLDocument object.
|
||||
*/
|
||||
const XLDocument* getParentDoc() const;
|
||||
|
||||
/**
|
||||
* @brief Retrieve the path of the XML data in the .xlsx zip archive.
|
||||
* @return A std::string with the path.
|
||||
*/
|
||||
std::string getXmlPath() const;
|
||||
|
||||
/**
|
||||
* @brief Retrieve the relationship ID of the XML file.
|
||||
* @return A std::string with the relationship ID.
|
||||
*/
|
||||
std::string getXmlID() const;
|
||||
|
||||
/**
|
||||
* @brief Retrieve the type represented by the XML data.
|
||||
* @return A XLContentType getValue representing the type.
|
||||
*/
|
||||
XLContentType getXmlType() const;
|
||||
|
||||
/**
|
||||
* @brief Access the underlying XMLDocument object.
|
||||
* @return A pointer to the XMLDocument object.
|
||||
*/
|
||||
XMLDocument* getXmlDocument();
|
||||
|
||||
/**
|
||||
* @brief Access the underlying XMLDocument object.
|
||||
* @return A const pointer to the XMLDocument object.
|
||||
*/
|
||||
const XMLDocument* getXmlDocument() const;
|
||||
|
||||
private:
|
||||
// ===== PRIVATE MEMBER VARIABLES ===== //
|
||||
|
||||
XLDocument* m_parentDoc {}; /**< A pointer to the parent XLDocument object. >*/
|
||||
std::string m_xmlPath {}; /**< The path of the XML data in the .xlsx zip archive. >*/
|
||||
std::string m_xmlID {}; /**< The relationship ID of the XML data. >*/
|
||||
XLContentType m_xmlType {}; /**< The type represented by the XML data. >*/
|
||||
mutable std::unique_ptr<XMLDocument> m_xmlDoc; /**< The underlying XMLDocument object. >*/
|
||||
};
|
||||
} // namespace OpenXLSX
|
||||
|
||||
#pragma warning(pop)
|
||||
#endif // OPENXLSX_XLXMLDATA_HPP
|
||||
Vendored
+163
@@ -0,0 +1,163 @@
|
||||
/*
|
||||
|
||||
____ ____ ___ ____ ____ ____ ___
|
||||
6MMMMb `MM( )M' `MM' 6MMMMb\`MM( )M'
|
||||
8P Y8 `MM. d' MM 6M' ` `MM. d'
|
||||
6M Mb __ ____ ____ ___ __ `MM. d' MM MM `MM. d'
|
||||
MM MM `M6MMMMb 6MMMMb `MM 6MMb `MM. d' MM YM. `MM. d'
|
||||
MM MM MM' `Mb 6M' `Mb MMM9 `Mb `MMd MM YMMMMb `MMd
|
||||
MM MM MM MM MM MM MM' MM dMM. MM `Mb dMM.
|
||||
MM MM MM MM MMMMMMMM MM MM d'`MM. MM MM d'`MM.
|
||||
YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM.
|
||||
8b d8 MM. ,M9 YM d9 MM MM d' `MM. MM / L ,M9 d' `MM.
|
||||
YMMMM9 MMYMMM9 YMMMM9 _MM_ _MM_M(_ _)MM_ _MMMMMMM MYMMMM9 _M(_ _)MM_
|
||||
MM
|
||||
MM
|
||||
_MM_
|
||||
|
||||
Copyright (c) 2018, Kenneth Troldal Balslev
|
||||
|
||||
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.
|
||||
- Neither the name of the author nor the
|
||||
names of any 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 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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef OPENXLSX_XLXMLFILE_HPP
|
||||
#define OPENXLSX_XLXMLFILE_HPP
|
||||
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4251)
|
||||
#pragma warning(disable : 4275)
|
||||
|
||||
// ===== OpenXLSX Includes ===== //
|
||||
#include "OpenXLSX-Exports.hpp"
|
||||
#include "XLXmlParser.hpp"
|
||||
|
||||
namespace OpenXLSX
|
||||
{
|
||||
class XLXmlData;
|
||||
class XLDocument;
|
||||
|
||||
/**
|
||||
* @brief The XLXmlFile class provides an interface for derived classes to use.
|
||||
* It functions as an ancestor to all classes which are represented by an .xml file in an .xlsx package.
|
||||
* @warning The XLXmlFile class is not intended to be instantiated on it's own, but to provide an interface for
|
||||
* derived classes. Also, it should not be used polymorphically. For that reason, the destructor is not declared virtual.
|
||||
*/
|
||||
class OPENXLSX_EXPORT XLXmlFile
|
||||
{
|
||||
public: // ===== PUBLIC MEMBER FUNCTIONS
|
||||
/**
|
||||
* @brief Default constructor.
|
||||
*/
|
||||
XLXmlFile() = default;
|
||||
|
||||
/**
|
||||
* @brief Constructor. Creates an object based on the xmlData input.
|
||||
* @param xmlData An XLXmlData object with the XML data to be represented by the object.
|
||||
*/
|
||||
explicit XLXmlFile(XLXmlData* xmlData);
|
||||
|
||||
/**
|
||||
* @brief Copy constructor. Default implementation used.
|
||||
* @param other The object to copy.
|
||||
*/
|
||||
XLXmlFile(const XLXmlFile& other) = default;
|
||||
|
||||
/**
|
||||
* @brief Move constructor. Default implementation used.
|
||||
* @param other The object to move.
|
||||
*/
|
||||
XLXmlFile(XLXmlFile&& other) noexcept = default;
|
||||
|
||||
/**
|
||||
* @brief Destructor. Default implementation used.
|
||||
*/
|
||||
~XLXmlFile();
|
||||
|
||||
/**
|
||||
* @brief The copy assignment operator. The default implementation has been used.
|
||||
* @param other The object to copy.
|
||||
* @return A reference to the new object.
|
||||
*/
|
||||
XLXmlFile& operator=(const XLXmlFile& other) = default;
|
||||
|
||||
/**
|
||||
* @brief The move assignment operator. The default implementation has been used.
|
||||
* @param other The object to move.
|
||||
* @return A reference to the new object.
|
||||
*/
|
||||
XLXmlFile& operator=(XLXmlFile&& other) noexcept = default;
|
||||
|
||||
protected: // ===== PROTECTED MEMBER FUNCTIONS
|
||||
/**
|
||||
* @brief Method for getting the XML data represented by the object.
|
||||
* @return A std::string with the XML data.
|
||||
*/
|
||||
std::string xmlData() const;
|
||||
|
||||
/**
|
||||
* @brief Provide the XML data represented by the object.
|
||||
* @param xmlData A std::string with the XML data.
|
||||
*/
|
||||
void setXmlData(const std::string& xmlData);
|
||||
|
||||
/**
|
||||
* @brief This function returns the relationship ID (the ID used in the XLRelationships objects) for the object.
|
||||
* @return A std::string with the ID. Not all spreadsheet objects may have a relationship ID. In those cases an empty string is
|
||||
* returned.
|
||||
*/
|
||||
std::string relationshipID() const;
|
||||
|
||||
/**
|
||||
* @brief This function provides access to the parent XLDocument object.
|
||||
* @return A reference to the parent XLDocument object.
|
||||
*/
|
||||
XLDocument& parentDoc();
|
||||
|
||||
/**
|
||||
* @brief This function provides access to the parent XLDocument object.
|
||||
* @return A const reference to the parent XLDocument object.
|
||||
*/
|
||||
const XLDocument& parentDoc() const;
|
||||
|
||||
/**
|
||||
* @brief This function provides access to the underlying XMLDocument object.
|
||||
* @return A reference to the XMLDocument object.
|
||||
*/
|
||||
XMLDocument& xmlDocument();
|
||||
|
||||
/**
|
||||
* @brief This function provides access to the underlying XMLDocument object.
|
||||
* @return A const reference to the XMLDocument object.
|
||||
*/
|
||||
const XMLDocument& xmlDocument() const;
|
||||
|
||||
protected: // ===== PRIVATE MEMBER VARIABLES
|
||||
XLXmlData* m_xmlData { nullptr }; /**< The underlying XML data object. */
|
||||
};
|
||||
} // namespace OpenXLSX
|
||||
|
||||
#pragma warning(pop)
|
||||
#endif // OPENXLSX_XLXMLFILE_HPP
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
|
||||
____ ____ ___ ____ ____ ____ ___
|
||||
6MMMMb `MM( )M' `MM' 6MMMMb\`MM( )M'
|
||||
8P Y8 `MM. d' MM 6M' ` `MM. d'
|
||||
6M Mb __ ____ ____ ___ __ `MM. d' MM MM `MM. d'
|
||||
MM MM `M6MMMMb 6MMMMb `MM 6MMb `MM. d' MM YM. `MM. d'
|
||||
MM MM MM' `Mb 6M' `Mb MMM9 `Mb `MMd MM YMMMMb `MMd
|
||||
MM MM MM MM MM MM MM' MM dMM. MM `Mb dMM.
|
||||
MM MM MM MM MMMMMMMM MM MM d'`MM. MM MM d'`MM.
|
||||
YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM.
|
||||
8b d8 MM. ,M9 YM d9 MM MM d' `MM. MM / L ,M9 d' `MM.
|
||||
YMMMM9 MMYMMM9 YMMMM9 _MM_ _MM_M(_ _)MM_ _MMMMMMM MYMMMM9 _M(_ _)MM_
|
||||
MM
|
||||
MM
|
||||
_MM_
|
||||
|
||||
Copyright (c) 2018, Kenneth Troldal Balslev
|
||||
|
||||
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.
|
||||
- Neither the name of the author nor the
|
||||
names of any 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 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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef OPENXLSX_XLXMLPARSER_HPP
|
||||
#define OPENXLSX_XLXMLPARSER_HPP
|
||||
|
||||
namespace pugi
|
||||
{
|
||||
class xml_node;
|
||||
class xml_attribute;
|
||||
class xml_document;
|
||||
} // namespace pugi
|
||||
|
||||
namespace OpenXLSX
|
||||
{
|
||||
using XMLNode = pugi::xml_node;
|
||||
using XMLAttribute = pugi::xml_attribute;
|
||||
using XMLDocument = pugi::xml_document;
|
||||
} // namespace OpenXLSX
|
||||
#endif // OPENXLSX_XLXMLPARSER_HPP
|
||||
+169
@@ -0,0 +1,169 @@
|
||||
/*
|
||||
|
||||
____ ____ ___ ____ ____ ____ ___
|
||||
6MMMMb `MM( )M' `MM' 6MMMMb\`MM( )M'
|
||||
8P Y8 `MM. d' MM 6M' ` `MM. d'
|
||||
6M Mb __ ____ ____ ___ __ `MM. d' MM MM `MM. d'
|
||||
MM MM `M6MMMMb 6MMMMb `MM 6MMb `MM. d' MM YM. `MM. d'
|
||||
MM MM MM' `Mb 6M' `Mb MMM9 `Mb `MMd MM YMMMMb `MMd
|
||||
MM MM MM MM MM MM MM' MM dMM. MM `Mb dMM.
|
||||
MM MM MM MM MMMMMMMM MM MM d'`MM. MM MM d'`MM.
|
||||
YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM.
|
||||
8b d8 MM. ,M9 YM d9 MM MM d' `MM. MM / L ,M9 d' `MM.
|
||||
YMMMM9 MMYMMM9 YMMMM9 _MM_ _MM_M(_ _)MM_ _MMMMMMM MYMMMM9 _M(_ _)MM_
|
||||
MM
|
||||
MM
|
||||
_MM_
|
||||
|
||||
Copyright (c) 2018, Kenneth Troldal Balslev
|
||||
|
||||
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.
|
||||
- Neither the name of the author nor the
|
||||
names of any 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 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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef OPENXLSX_XLZIPARCHIVE_HPP
|
||||
#define OPENXLSX_XLZIPARCHIVE_HPP
|
||||
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4251)
|
||||
#pragma warning(disable : 4275)
|
||||
|
||||
// ===== OpenXLSX Includes ===== //
|
||||
#include "OpenXLSX-Exports.hpp"
|
||||
|
||||
namespace Zippy
|
||||
{
|
||||
class ZipArchive;
|
||||
} // namespace Zippy
|
||||
|
||||
namespace OpenXLSX
|
||||
{
|
||||
/**
|
||||
* @brief
|
||||
*/
|
||||
class OPENXLSX_EXPORT XLZipArchive
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief
|
||||
*/
|
||||
XLZipArchive();
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param other
|
||||
*/
|
||||
XLZipArchive(const XLZipArchive& other) = default;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param other
|
||||
*/
|
||||
XLZipArchive(XLZipArchive&& other) = default;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*/
|
||||
~XLZipArchive();
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param other
|
||||
* @return
|
||||
*/
|
||||
XLZipArchive& operator=(const XLZipArchive& other) = default;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param other
|
||||
* @return
|
||||
*/
|
||||
XLZipArchive& operator=(XLZipArchive&& other) = default;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @return
|
||||
*/
|
||||
explicit operator bool() const;
|
||||
|
||||
bool isValid() const;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @return
|
||||
*/
|
||||
bool isOpen() const;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param fileName
|
||||
*/
|
||||
void open(const std::string& fileName);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*/
|
||||
void close();
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param path
|
||||
*/
|
||||
void save(const std::string& path = "");
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param name
|
||||
* @param data
|
||||
*/
|
||||
void addEntry(const std::string& name, const std::string& data);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param entryName
|
||||
*/
|
||||
void deleteEntry(const std::string& entryName);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param name
|
||||
* @return
|
||||
*/
|
||||
std::string getEntry(const std::string& name);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param entryName
|
||||
* @return
|
||||
*/
|
||||
bool hasEntry(const std::string& entryName);
|
||||
|
||||
private:
|
||||
std::shared_ptr<Zippy::ZipArchive> m_archive; /**< */
|
||||
};
|
||||
} // namespace OpenXLSX
|
||||
|
||||
#pragma warning(pop)
|
||||
#endif // OPENXLSX_XLZIPARCHIVE_HPP
|
||||
Vendored
+215
@@ -0,0 +1,215 @@
|
||||
/*
|
||||
|
||||
____ ____ ___ ____ ____ ____ ___
|
||||
6MMMMb `MM( )M' `MM' 6MMMMb\`MM( )M'
|
||||
8P Y8 `MM. d' MM 6M' ` `MM. d'
|
||||
6M Mb __ ____ ____ ___ __ `MM. d' MM MM `MM. d'
|
||||
MM MM `M6MMMMb 6MMMMb `MM 6MMb `MM. d' MM YM. `MM. d'
|
||||
MM MM MM' `Mb 6M' `Mb MMM9 `Mb `MMd MM YMMMMb `MMd
|
||||
MM MM MM MM MM MM MM' MM dMM. MM `Mb dMM.
|
||||
MM MM MM MM MMMMMMMM MM MM d'`MM. MM MM d'`MM.
|
||||
YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM.
|
||||
8b d8 MM. ,M9 YM d9 MM MM d' `MM. MM / L ,M9 d' `MM.
|
||||
YMMMM9 MMYMMM9 YMMMM9 _MM_ _MM_M(_ _)MM_ _MMMMMMM MYMMMM9 _M(_ _)MM_
|
||||
MM
|
||||
MM
|
||||
_MM_
|
||||
|
||||
Copyright (c) 2018, Kenneth Troldal Balslev
|
||||
|
||||
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.
|
||||
- Neither the name of the author nor the
|
||||
names of any 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 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.
|
||||
|
||||
*/
|
||||
|
||||
// ===== External Includes ===== //
|
||||
#include <pugixml.hpp>
|
||||
|
||||
// ===== OpenXLSX Includes ===== //
|
||||
#include "XLCell.hpp"
|
||||
#include "XLCellRange.hpp"
|
||||
#include "utilities/XLUtilities.hpp"
|
||||
|
||||
using namespace OpenXLSX;
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
XLCell::XLCell()
|
||||
: m_cellNode(nullptr),
|
||||
m_valueProxy(XLCellValueProxy(this, m_cellNode.get())),
|
||||
m_formulaProxy(XLFormulaProxy(this, m_cellNode.get()))
|
||||
{}
|
||||
|
||||
/**
|
||||
* @details This constructor creates a XLCell object based on the cell XMLNode input parameter, and is
|
||||
* intended for use when the corresponding cell XMLNode already exist.
|
||||
* If a cell XMLNode does not exist (i.e., the cell is empty), use the relevant constructor to create an XLCell
|
||||
* from a XLCellReference parameter.
|
||||
*/
|
||||
XLCell::XLCell(const XMLNode& cellNode, const XLSharedStrings& sharedStrings)
|
||||
: m_cellNode(std::make_unique<XMLNode>(cellNode)),
|
||||
m_sharedStrings(sharedStrings),
|
||||
m_valueProxy(XLCellValueProxy(this, m_cellNode.get())),
|
||||
m_formulaProxy(XLFormulaProxy(this, m_cellNode.get()))
|
||||
{}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
XLCell::XLCell(const XLCell& other)
|
||||
: m_cellNode(other.m_cellNode ? std::make_unique<XMLNode>(*other.m_cellNode) : nullptr),
|
||||
m_sharedStrings(other.m_sharedStrings),
|
||||
m_valueProxy(XLCellValueProxy(this, m_cellNode.get())),
|
||||
m_formulaProxy(XLFormulaProxy(this, m_cellNode.get()))
|
||||
{}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
XLCell::XLCell(XLCell&& other) noexcept
|
||||
: m_cellNode(std::move(other.m_cellNode)),
|
||||
m_sharedStrings(std::move(other.m_sharedStrings)),
|
||||
m_valueProxy(XLCellValueProxy(this, m_cellNode.get())),
|
||||
m_formulaProxy(XLFormulaProxy(this, m_cellNode.get()))
|
||||
{}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
XLCell::~XLCell() = default;
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
XLCell& XLCell::operator=(const XLCell& other)
|
||||
{
|
||||
if (&other != this) {
|
||||
XLCell temp = other;
|
||||
std::swap(*this, temp);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
XLCell& XLCell::operator=(XLCell&& other) noexcept
|
||||
{
|
||||
if (&other != this) {
|
||||
m_cellNode = std::move(other.m_cellNode);
|
||||
m_sharedStrings = other.m_sharedStrings;
|
||||
m_valueProxy = XLCellValueProxy(this, m_cellNode.get());
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
XLCell::operator bool() const
|
||||
{
|
||||
return m_cellNode && *m_cellNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @details This function returns a const reference to the cellReference property.
|
||||
*/
|
||||
XLCellReference XLCell::cellReference() const
|
||||
{
|
||||
if (!*this) throw XLInternalError("XLCell object has not been properly initiated.");
|
||||
return XLCellReference{m_cellNode->attribute("r").value()};
|
||||
}
|
||||
|
||||
/**
|
||||
* @details This function returns a const reference to the cell reference by the offset from the current one.
|
||||
*/
|
||||
XLCell XLCell::offset(uint16_t rowOffset, uint16_t colOffset) const
|
||||
{
|
||||
if (!*this) throw XLInternalError("XLCell object has not been properly initiated.");
|
||||
XLCellReference offsetRef(cellReference().row() + rowOffset, cellReference().column() + colOffset);
|
||||
auto rownode = getRowNode(m_cellNode->parent().parent(), offsetRef.row());
|
||||
auto cellnode = getCellNode(rownode, offsetRef.column());
|
||||
return XLCell{cellnode, m_sharedStrings};
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
bool XLCell::hasFormula() const
|
||||
{
|
||||
if (!*this) return false;
|
||||
return m_cellNode->child("f") != nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
XLFormulaProxy& XLCell::formula()
|
||||
{
|
||||
if (!*this) throw XLInternalError("XLCell object has not been properly initiated.");
|
||||
return m_formulaProxy;
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
const XLFormulaProxy& XLCell::formula() const
|
||||
{
|
||||
if (!*this) throw XLInternalError("XLCell object has not been properly initiated.");
|
||||
return m_formulaProxy;
|
||||
}
|
||||
|
||||
/**
|
||||
* @pre
|
||||
* @post
|
||||
*/
|
||||
XLCellValueProxy& XLCell::value()
|
||||
{
|
||||
if (!*this) throw XLInternalError("XLCell object has not been properly initiated.");
|
||||
return m_valueProxy;
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
* @pre
|
||||
* @post
|
||||
*/
|
||||
const XLCellValueProxy& XLCell::value() const
|
||||
{
|
||||
if (!*this) throw XLInternalError("XLCell object has not been properly initiated.");
|
||||
return m_valueProxy;
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
* @pre
|
||||
* @post
|
||||
*/
|
||||
bool XLCell::isEqual(const XLCell& lhs, const XLCell& rhs)
|
||||
{
|
||||
return *lhs.m_cellNode == *rhs.m_cellNode;
|
||||
}
|
||||
+220
@@ -0,0 +1,220 @@
|
||||
/*
|
||||
|
||||
____ ____ ___ ____ ____ ____ ___
|
||||
6MMMMb `MM( )M' `MM' 6MMMMb\`MM( )M'
|
||||
8P Y8 `MM. d' MM 6M' ` `MM. d'
|
||||
6M Mb __ ____ ____ ___ __ `MM. d' MM MM `MM. d'
|
||||
MM MM `M6MMMMb 6MMMMb `MM 6MMb `MM. d' MM YM. `MM. d'
|
||||
MM MM MM' `Mb 6M' `Mb MMM9 `Mb `MMd MM YMMMMb `MMd
|
||||
MM MM MM MM MM MM MM' MM dMM. MM `Mb dMM.
|
||||
MM MM MM MM MMMMMMMM MM MM d'`MM. MM MM d'`MM.
|
||||
YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM.
|
||||
8b d8 MM. ,M9 YM d9 MM MM d' `MM. MM / L ,M9 d' `MM.
|
||||
YMMMM9 MMYMMM9 YMMMM9 _MM_ _MM_M(_ _)MM_ _MMMMMMM MYMMMM9 _M(_ _)MM_
|
||||
MM
|
||||
MM
|
||||
_MM_
|
||||
|
||||
Copyright (c) 2018, Kenneth Troldal Balslev
|
||||
|
||||
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.
|
||||
- Neither the name of the author nor the
|
||||
names of any 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 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.
|
||||
|
||||
*/
|
||||
|
||||
// ===== External Includes ===== //
|
||||
#include <pugixml.hpp>
|
||||
|
||||
// ===== OpenXLSX Includes ===== //
|
||||
#include "XLCellIterator.hpp"
|
||||
#include "XLCellRange.hpp"
|
||||
#include "XLCellReference.hpp"
|
||||
#include "XLException.hpp"
|
||||
|
||||
using namespace OpenXLSX;
|
||||
|
||||
namespace OpenXLSX
|
||||
{
|
||||
XMLNode getRowNode(XMLNode sheetDataNode, uint32_t rowNumber);
|
||||
XMLNode getCellNode(XMLNode rowNode, uint16_t columnNumber);
|
||||
} // namespace OpenXLSX
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
XLCellIterator::XLCellIterator(const XLCellRange& cellRange, XLIteratorLocation loc)
|
||||
: m_dataNode(std::make_unique<XMLNode>(*cellRange.m_dataNode)),
|
||||
m_topLeft(cellRange.m_topLeft),
|
||||
m_bottomRight(cellRange.m_bottomRight),
|
||||
m_sharedStrings(cellRange.m_sharedStrings)
|
||||
{
|
||||
if (loc == XLIteratorLocation::End)
|
||||
m_currentCell = XLCell();
|
||||
else {
|
||||
m_currentCell = XLCell(getCellNode(getRowNode(*m_dataNode, m_topLeft.row()), m_topLeft.column()), m_sharedStrings);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
XLCellIterator::~XLCellIterator() = default;
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
XLCellIterator::XLCellIterator(const XLCellIterator& other)
|
||||
: m_dataNode(std::make_unique<XMLNode>(*other.m_dataNode)),
|
||||
m_topLeft(other.m_topLeft),
|
||||
m_bottomRight(other.m_bottomRight),
|
||||
m_currentCell(other.m_currentCell),
|
||||
m_sharedStrings(other.m_sharedStrings)
|
||||
{}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
XLCellIterator::XLCellIterator(XLCellIterator&& other) noexcept = default;
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
XLCellIterator& XLCellIterator::operator=(const XLCellIterator& other)
|
||||
{
|
||||
if (&other != this) {
|
||||
*m_dataNode = *other.m_dataNode;
|
||||
m_topLeft = other.m_topLeft;
|
||||
m_bottomRight = other.m_bottomRight;
|
||||
m_currentCell = other.m_currentCell;
|
||||
m_sharedStrings = other.m_sharedStrings;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
XLCellIterator& XLCellIterator::operator=(XLCellIterator&& other) noexcept = default;
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
XLCellIterator& XLCellIterator::operator++()
|
||||
{
|
||||
auto ref = m_currentCell.cellReference();
|
||||
|
||||
// ===== Determine the cell reference for the next cell.
|
||||
if (ref.column() < m_bottomRight.column())
|
||||
ref = XLCellReference(ref.row(), ref.column() + 1);
|
||||
else if (ref == m_bottomRight)
|
||||
m_endReached = true;
|
||||
else
|
||||
ref = XLCellReference(ref.row() + 1, m_topLeft.column());
|
||||
|
||||
if (m_endReached)
|
||||
m_currentCell = XLCell();
|
||||
else if (ref > m_bottomRight || ref.row() == m_currentCell.cellReference().row()) {
|
||||
auto node = m_currentCell.m_cellNode->next_sibling();
|
||||
if (!node || XLCellReference(node.attribute("r").value()) != ref) {
|
||||
node = m_currentCell.m_cellNode->parent().insert_child_after("c", *m_currentCell.m_cellNode);
|
||||
node.append_attribute("r").set_value(ref.address().c_str());
|
||||
}
|
||||
m_currentCell = XLCell(node, m_sharedStrings);
|
||||
}
|
||||
else if (ref.row() > m_currentCell.cellReference().row()) {
|
||||
auto rowNode = m_currentCell.m_cellNode->parent().next_sibling();
|
||||
if (!rowNode || rowNode.attribute("r").as_ullong() != ref.row()) {
|
||||
rowNode = m_currentCell.m_cellNode->parent().parent().insert_child_after("row", m_currentCell.m_cellNode->parent());
|
||||
rowNode.append_attribute("r").set_value(ref.row());
|
||||
// getRowNode(*m_dataNode, ref.row());
|
||||
}
|
||||
|
||||
m_currentCell = XLCell(getCellNode(rowNode, ref.column()), m_sharedStrings);
|
||||
}
|
||||
else
|
||||
throw XLInternalError("An internal error occured");
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
XLCellIterator XLCellIterator::operator++(int) // NOLINT
|
||||
{
|
||||
auto oldIter(*this);
|
||||
++(*this);
|
||||
return oldIter;
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
XLCell& XLCellIterator::operator*()
|
||||
{
|
||||
return m_currentCell;
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
XLCellIterator::pointer XLCellIterator::operator->()
|
||||
{
|
||||
return &m_currentCell;
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
bool XLCellIterator::operator==(const XLCellIterator& rhs) const
|
||||
{
|
||||
if (m_currentCell && !rhs.m_currentCell)
|
||||
return false;
|
||||
if (!m_currentCell && !rhs.m_currentCell)
|
||||
return true;
|
||||
return m_currentCell == rhs.m_currentCell;
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
bool XLCellIterator::operator!=(const XLCellIterator& rhs) const
|
||||
{
|
||||
return !(*this == rhs);
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
* @todo This implementation is rather ineffecient. Consider an alternative implementation.
|
||||
*/
|
||||
uint64_t XLCellIterator::distance(const XLCellIterator& last)
|
||||
{
|
||||
uint64_t result = 0;
|
||||
while (*this != last) {
|
||||
++result;
|
||||
++(*this);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
+179
@@ -0,0 +1,179 @@
|
||||
/*
|
||||
|
||||
____ ____ ___ ____ ____ ____ ___
|
||||
6MMMMb `MM( )M' `MM' 6MMMMb\`MM( )M'
|
||||
8P Y8 `MM. d' MM 6M' ` `MM. d'
|
||||
6M Mb __ ____ ____ ___ __ `MM. d' MM MM `MM. d'
|
||||
MM MM `M6MMMMb 6MMMMb `MM 6MMb `MM. d' MM YM. `MM. d'
|
||||
MM MM MM' `Mb 6M' `Mb MMM9 `Mb `MMd MM YMMMMb `MMd
|
||||
MM MM MM MM MM MM MM' MM dMM. MM `Mb dMM.
|
||||
MM MM MM MM MMMMMMMM MM MM d'`MM. MM MM d'`MM.
|
||||
YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM.
|
||||
8b d8 MM. ,M9 YM d9 MM MM d' `MM. MM / L ,M9 d' `MM.
|
||||
YMMMM9 MMYMMM9 YMMMM9 _MM_ _MM_M(_ _)MM_ _MMMMMMM MYMMMM9 _M(_ _)MM_
|
||||
MM
|
||||
MM
|
||||
_MM_
|
||||
|
||||
Copyright (c) 2018, Kenneth Troldal Balslev
|
||||
|
||||
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.
|
||||
- Neither the name of the author nor the
|
||||
names of any 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 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.
|
||||
|
||||
*/
|
||||
|
||||
// ===== External Includes ===== //
|
||||
#include <pugixml.hpp>
|
||||
#include <stdexcept>
|
||||
|
||||
// ===== OpenXLSX Includes ===== //
|
||||
#include "XLCellRange.hpp"
|
||||
|
||||
using namespace OpenXLSX;
|
||||
|
||||
/**
|
||||
* @details From the two XLCellReference objects, the constructor calculates the dimensions of the range.
|
||||
* If the range exceeds the current bounds of the spreadsheet, the spreadsheet is resized to fit.
|
||||
* @pre
|
||||
* @post
|
||||
*/
|
||||
XLCellRange::XLCellRange(const XMLNode& dataNode,
|
||||
const XLCellReference& topLeft,
|
||||
const XLCellReference& bottomRight,
|
||||
const XLSharedStrings& sharedStrings)
|
||||
: m_dataNode(std::make_unique<XMLNode>(dataNode)),
|
||||
m_topLeft(topLeft),
|
||||
m_bottomRight(bottomRight),
|
||||
m_sharedStrings(sharedStrings)
|
||||
{}
|
||||
|
||||
/**
|
||||
* @details
|
||||
* @pre
|
||||
* @post
|
||||
*/
|
||||
XLCellRange::XLCellRange(const XLCellRange& other)
|
||||
: m_dataNode(std::make_unique<XMLNode>(*other.m_dataNode)),
|
||||
m_topLeft(other.m_topLeft),
|
||||
m_bottomRight(other.m_bottomRight),
|
||||
m_sharedStrings(other.m_sharedStrings)
|
||||
{}
|
||||
|
||||
/**
|
||||
* @details
|
||||
* @pre
|
||||
* @post
|
||||
*/
|
||||
XLCellRange::XLCellRange(XLCellRange&& other) noexcept = default;
|
||||
|
||||
/**
|
||||
* @details
|
||||
* @pre
|
||||
* @post
|
||||
*/
|
||||
XLCellRange::~XLCellRange() = default;
|
||||
|
||||
/**
|
||||
* @details
|
||||
* @pre
|
||||
* @post
|
||||
*/
|
||||
XLCellRange& XLCellRange::operator=(const XLCellRange& other)
|
||||
{
|
||||
if (&other != this) {
|
||||
*m_dataNode = *other.m_dataNode;
|
||||
m_topLeft = other.m_topLeft;
|
||||
m_bottomRight = other.m_bottomRight;
|
||||
m_sharedStrings = other.m_sharedStrings;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
* @pre
|
||||
* @post
|
||||
*/
|
||||
XLCellRange& XLCellRange::operator=(XLCellRange&& other) noexcept
|
||||
{
|
||||
if (&other != this) {
|
||||
*m_dataNode = *other.m_dataNode;
|
||||
m_topLeft = other.m_topLeft;
|
||||
m_bottomRight = other.m_bottomRight;
|
||||
m_sharedStrings = other.m_sharedStrings;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
* @pre
|
||||
* @post
|
||||
*/
|
||||
uint32_t XLCellRange::numRows() const
|
||||
{
|
||||
return m_bottomRight.row() + 1 - m_topLeft.row();
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
* @pre
|
||||
* @post
|
||||
*/
|
||||
uint16_t XLCellRange::numColumns() const
|
||||
{
|
||||
return m_bottomRight.column() + 1 - m_topLeft.column();
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
* @pre
|
||||
* @post
|
||||
*/
|
||||
XLCellIterator XLCellRange::begin() const
|
||||
{
|
||||
return XLCellIterator(*this, XLIteratorLocation::Begin);
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
* @pre
|
||||
* @post
|
||||
*/
|
||||
XLCellIterator XLCellRange::end() const
|
||||
{
|
||||
return XLCellIterator(*this, XLIteratorLocation::End);
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
* @pre
|
||||
* @post
|
||||
*/
|
||||
void XLCellRange::clear()
|
||||
{
|
||||
for(auto& cell: *this) cell.value().clear();
|
||||
}
|
||||
+354
@@ -0,0 +1,354 @@
|
||||
/*
|
||||
|
||||
____ ____ ___ ____ ____ ____ ___
|
||||
6MMMMb `MM( )M' `MM' 6MMMMb\`MM( )M'
|
||||
8P Y8 `MM. d' MM 6M' ` `MM. d'
|
||||
6M Mb __ ____ ____ ___ __ `MM. d' MM MM `MM. d'
|
||||
MM MM `M6MMMMb 6MMMMb `MM 6MMb `MM. d' MM YM. `MM. d'
|
||||
MM MM MM' `Mb 6M' `Mb MMM9 `Mb `MMd MM YMMMMb `MMd
|
||||
MM MM MM MM MM MM MM' MM dMM. MM `Mb dMM.
|
||||
MM MM MM MM MMMMMMMM MM MM d'`MM. MM MM d'`MM.
|
||||
YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM.
|
||||
8b d8 MM. ,M9 YM d9 MM MM d' `MM. MM / L ,M9 d' `MM.
|
||||
YMMMM9 MMYMMM9 YMMMM9 _MM_ _MM_M(_ _)MM_ _MMMMMMM MYMMMM9 _M(_ _)MM_
|
||||
MM
|
||||
MM
|
||||
_MM_
|
||||
|
||||
Copyright (c) 2018, Kenneth Troldal Balslev
|
||||
|
||||
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.
|
||||
- Neither the name of the author nor the
|
||||
names of any 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 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.
|
||||
|
||||
*/
|
||||
|
||||
// ===== External Includes ===== //
|
||||
#include <array>
|
||||
#include <cmath>
|
||||
#ifdef CHARCONV_ENABLED
|
||||
# include <charconv>
|
||||
#endif
|
||||
|
||||
// ===== OpenXLSX Includes ===== //
|
||||
#include "XLCellReference.hpp"
|
||||
#include "XLConstants.hpp"
|
||||
#include "XLException.hpp"
|
||||
|
||||
using namespace OpenXLSX;
|
||||
|
||||
constexpr uint8_t alphabetSize = 26;
|
||||
|
||||
constexpr uint8_t asciiOffset = 64;
|
||||
|
||||
namespace {
|
||||
bool addressIsValid(uint32_t row, uint16_t column) {
|
||||
return !(row < 1 || row > OpenXLSX::MAX_ROWS || column < 1 || column > OpenXLSX::MAX_COLS);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
/**
|
||||
* @details The constructor creates a new XLCellReference from a string, e.g. 'A1'. If there's no input,
|
||||
* the default reference will be cell A1.
|
||||
*/
|
||||
XLCellReference::XLCellReference(const std::string& cellAddress)
|
||||
{
|
||||
if (!cellAddress.empty()) setAddress(cellAddress);
|
||||
if (!addressIsValid(m_row, m_column)) {
|
||||
m_row = 1;
|
||||
m_column = 1;
|
||||
m_cellAddress = "A1";
|
||||
throw XLCellAddressError("Cell reference is invalid");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @details This constructor creates a new XLCellReference from a given row and column number, e.g. 1,1 (=A1)
|
||||
* @todo consider swapping the arguments.
|
||||
*/
|
||||
XLCellReference::XLCellReference(uint32_t row, uint16_t column){
|
||||
if (!addressIsValid(row, column)) throw XLCellAddressError("Cell reference is invalid");
|
||||
setRowAndColumn(row, column);
|
||||
}
|
||||
|
||||
/**
|
||||
* @details This constructor creates a new XLCellReference from a row number and the column name (e.g. 1, A)
|
||||
* @todo consider swapping the arguments.
|
||||
*/
|
||||
XLCellReference::XLCellReference(uint32_t row, const std::string& column) {
|
||||
if (!addressIsValid(row, columnAsNumber(column))) throw XLCellAddressError("Cell reference is invalid");
|
||||
setRowAndColumn(row, columnAsNumber(column));
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
XLCellReference::XLCellReference(const XLCellReference& other) = default;
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
XLCellReference::XLCellReference(XLCellReference&& other) noexcept = default;
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
XLCellReference::~XLCellReference() = default;
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
XLCellReference& XLCellReference::operator=(const XLCellReference& other) = default;
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
XLCellReference& XLCellReference::operator=(XLCellReference&& other) noexcept = default;
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
XLCellReference& XLCellReference::operator++()
|
||||
{
|
||||
if (m_column < MAX_COLS) {
|
||||
setColumn(m_column + 1);
|
||||
}
|
||||
else if (m_column == MAX_COLS && m_row < MAX_ROWS) {
|
||||
m_column = 1;
|
||||
setRow(m_row + 1);
|
||||
}
|
||||
else if (m_column == MAX_COLS && m_row == MAX_ROWS) {
|
||||
m_column = 1;
|
||||
m_row = 1;
|
||||
m_cellAddress = "A1";
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
XLCellReference XLCellReference::operator++(int) { // NOLINT
|
||||
auto oldRef(*this);
|
||||
++(*this);
|
||||
return oldRef;
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
XLCellReference& XLCellReference::operator--()
|
||||
{
|
||||
if (m_column > 1) {
|
||||
setColumn(m_column - 1);
|
||||
}
|
||||
else if (m_column == 1 && m_row > 1) {
|
||||
m_column = MAX_COLS;
|
||||
setRow(m_row - 1);
|
||||
}
|
||||
else if (m_column == 1 && m_row == 1) {
|
||||
m_column = MAX_COLS;
|
||||
m_row = MAX_ROWS;
|
||||
m_cellAddress = "XFD1048576";
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
XLCellReference XLCellReference::operator--(int) {// NOLINT
|
||||
auto oldRef(*this);
|
||||
--(*this);
|
||||
return oldRef;
|
||||
}
|
||||
|
||||
/**
|
||||
* @details Returns the m_row property.
|
||||
*/
|
||||
uint32_t XLCellReference::row() const
|
||||
{
|
||||
return m_row;
|
||||
}
|
||||
|
||||
/**
|
||||
* @details Sets the row of the XLCellReference objects. If the number is larger than 16384 (the maximum),
|
||||
* the row is set to 16384.
|
||||
*/
|
||||
void XLCellReference::setRow(uint32_t row)
|
||||
{
|
||||
if(!addressIsValid(row, m_column)) throw XLCellAddressError("Cell reference is invalid");
|
||||
|
||||
m_row = row;
|
||||
m_cellAddress = columnAsString(m_column) + rowAsString(m_row);
|
||||
}
|
||||
|
||||
/**
|
||||
* @details Returns the m_column property.
|
||||
*/
|
||||
uint16_t XLCellReference::column() const
|
||||
{
|
||||
return m_column;
|
||||
}
|
||||
|
||||
/**
|
||||
* @details Sets the column of the XLCellReference object. If the number is larger than 1048576 (the maximum),
|
||||
* the column is set to 1048576.
|
||||
*/
|
||||
void XLCellReference::setColumn(uint16_t column)
|
||||
{
|
||||
if(!addressIsValid(m_row, column)) throw XLCellAddressError("Cell reference is invalid");
|
||||
|
||||
m_column = column;
|
||||
m_cellAddress = columnAsString(m_column) + rowAsString(m_row);
|
||||
}
|
||||
|
||||
/**
|
||||
* @details Sets row and column of the XLCellReference object. Checks that row and column is less than
|
||||
* or equal to the maximum row and column numbers allowed by Excel.
|
||||
*/
|
||||
void XLCellReference::setRowAndColumn(uint32_t row, uint16_t column)
|
||||
{
|
||||
if (!addressIsValid(row, column)) throw XLCellAddressError("Cell reference is invalid");
|
||||
|
||||
m_row = row;
|
||||
m_column = column;
|
||||
m_cellAddress = columnAsString(m_column) + rowAsString(m_row);
|
||||
}
|
||||
|
||||
/**
|
||||
* @details Returns the m_cellAddress property.
|
||||
*/
|
||||
std::string XLCellReference::address() const
|
||||
{
|
||||
return m_cellAddress;
|
||||
}
|
||||
|
||||
/**
|
||||
* @details Sets the address of the XLCellReference object, e.g. 'B2'. Checks that row and column is less than
|
||||
* or equal to the maximum row and column numbers allowed by Excel.
|
||||
*/
|
||||
void XLCellReference::setAddress(const std::string& address)
|
||||
{
|
||||
auto coordinates = coordinatesFromAddress(address);
|
||||
m_row = coordinates.first;
|
||||
m_column = coordinates.second;
|
||||
m_cellAddress = address;
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
std::string XLCellReference::rowAsString(uint32_t row)
|
||||
{
|
||||
#ifdef CHARCONV_ENABLED
|
||||
std::array<char, 7> str {}; // NOLINT
|
||||
auto* p = std::to_chars(str.data(), str.data() + str.size(), row).ptr;
|
||||
return std::string{str.data(), static_cast<uint16_t>(p - str.data())};
|
||||
#else
|
||||
std::string result;
|
||||
while (row != 0) {
|
||||
int rem = row % 10;
|
||||
result += (rem > 9) ? (rem - 10) + 'a' : rem + '0';
|
||||
row = row / 10;
|
||||
}
|
||||
|
||||
for (int i = 0; i < result.length() / 2; i++) std::swap(result[i], result[result.length() - i - 1]);
|
||||
|
||||
return result;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
uint32_t XLCellReference::rowAsNumber(const std::string& row)
|
||||
{
|
||||
#ifdef CHARCONV_ENABLED
|
||||
uint32_t value = 0;
|
||||
std::from_chars(row.data(), row.data() + row.size(), value); // NOLINT
|
||||
return value;
|
||||
#else
|
||||
return stoul(row);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @details Helper method to calculate the column letter from column number.
|
||||
*/
|
||||
std::string XLCellReference::columnAsString(uint16_t column)
|
||||
{
|
||||
std::string result;
|
||||
|
||||
// ===== If there is one letter in the Column Name:
|
||||
if (column <= alphabetSize) result += char(column + asciiOffset);
|
||||
|
||||
// ===== If there are two letters in the Column Name:
|
||||
else if (column > alphabetSize && column <= alphabetSize * (alphabetSize + 1)) {
|
||||
result += char((column - (alphabetSize + 1)) / alphabetSize + asciiOffset + 1);
|
||||
result += char((column - (alphabetSize + 1)) % alphabetSize + asciiOffset + 1);
|
||||
}
|
||||
|
||||
// ===== If there is three letters in the Column Name:
|
||||
else {
|
||||
result += char((column - 703) / (alphabetSize * alphabetSize) + asciiOffset + 1); // NOLINT
|
||||
result += char(((column - 703) / alphabetSize) % alphabetSize + asciiOffset + 1); // NOLINT
|
||||
result += char((column - 703) % alphabetSize + asciiOffset + 1); // NOLINT
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @details Helper method to calculate the column number from column letter.
|
||||
*/
|
||||
uint16_t XLCellReference::columnAsNumber(const std::string& column)
|
||||
{
|
||||
uint16_t result = 0;
|
||||
|
||||
for (int16_t i = static_cast<int16_t>(column.size() - 1), j = 0; i >= 0; --i, ++j) { // NOLINT
|
||||
result += static_cast<uint16_t>((column[static_cast<uint64_t>(i)] - asciiOffset) * std::pow(alphabetSize, j));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @details Helper method for calculating the coordinates from the cell address.
|
||||
* @todo Consider checking if the given address is valid.
|
||||
*/
|
||||
XLCoordinates XLCellReference::coordinatesFromAddress(const std::string& address)
|
||||
{
|
||||
uint64_t letterCount = 0;
|
||||
for (auto letter : address) {
|
||||
if (letter >= 65) // NOLINT
|
||||
++letterCount;
|
||||
else if (letter <= 57) // NOLINT
|
||||
break;
|
||||
}
|
||||
|
||||
auto numberCount = address.size() - letterCount;
|
||||
|
||||
return std::make_pair(rowAsNumber(address.substr(letterCount, numberCount)), columnAsNumber(address.substr(0, letterCount)));
|
||||
}
|
||||
+463
@@ -0,0 +1,463 @@
|
||||
//
|
||||
// Created by Kenneth Balslev on 19/08/2020.
|
||||
//
|
||||
|
||||
// ===== External Includes ===== //
|
||||
#include <pugixml.hpp>
|
||||
|
||||
// ===== OpenXLSX Includes ===== //
|
||||
#include "XLCell.hpp"
|
||||
#include "XLCellValue.hpp"
|
||||
#include "XLException.hpp"
|
||||
|
||||
using namespace OpenXLSX;
|
||||
|
||||
/**
|
||||
* @details Constructor. Default implementation has been used.
|
||||
* @pre
|
||||
* @post
|
||||
*/
|
||||
XLCellValue::XLCellValue() = default;
|
||||
|
||||
/**
|
||||
* @details Copy constructor. The default implementation will be used.
|
||||
* @pre The object to be copied must be valid.
|
||||
* @post A valid copy is constructed.
|
||||
*/
|
||||
XLCellValue::XLCellValue(const OpenXLSX::XLCellValue& other) = default;
|
||||
|
||||
/**
|
||||
* @details Move constructor. The default implementation will be used.
|
||||
* @pre The object to be copied must be valid.
|
||||
* @post A valid copy is constructed.
|
||||
*/
|
||||
XLCellValue::XLCellValue(OpenXLSX::XLCellValue&& other) noexcept = default;
|
||||
|
||||
/**
|
||||
* @details Destructor. The default implementation will be used
|
||||
* @pre None.
|
||||
* @post The object is destructed.
|
||||
*/
|
||||
XLCellValue::~XLCellValue() = default;
|
||||
|
||||
/**
|
||||
* @details Copy assignment operator. The default implementation will be used.
|
||||
* @pre The object to be copied must be a valid object.
|
||||
* @post A the copied-to object is valid.
|
||||
*/
|
||||
XLCellValue& OpenXLSX::XLCellValue::operator=(const OpenXLSX::XLCellValue& other) = default;
|
||||
|
||||
/**
|
||||
* @details Move assignment operator. The default implementation will be used.
|
||||
* @pre The object to be moved must be a valid object.
|
||||
* @post The moved-to object is valid.
|
||||
*/
|
||||
XLCellValue& OpenXLSX::XLCellValue::operator=(OpenXLSX::XLCellValue&& other) noexcept = default;
|
||||
|
||||
/**
|
||||
* @details Clears the contents of the XLCellValue object. Setting the value to an empty string is not sufficient
|
||||
* (as an empty string is still a valid string). The m_type variable must also be set to XLValueType::Empty.
|
||||
* @pre
|
||||
* @post
|
||||
*/
|
||||
XLCellValue& XLCellValue::clear()
|
||||
{
|
||||
m_type = XLValueType::Empty;
|
||||
m_value = std::string("");
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @details Sets the value type to XLValueType::Error. The value will be set to an empty string.
|
||||
* @pre
|
||||
* @post
|
||||
*/
|
||||
XLCellValue& XLCellValue::setError(const std::string &error)
|
||||
{
|
||||
m_type = XLValueType::Error;
|
||||
m_value = error;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @details Get the value type of the current object.
|
||||
* @pre
|
||||
* @post
|
||||
*/
|
||||
XLValueType XLCellValue::type() const
|
||||
{
|
||||
return m_type;
|
||||
}
|
||||
|
||||
/**
|
||||
* @details Get the value type of the current object, as a string representation
|
||||
* @pre
|
||||
* @post
|
||||
*/
|
||||
std::string XLCellValue::typeAsString() const
|
||||
{
|
||||
switch (type()) {
|
||||
case XLValueType::Empty:
|
||||
return "empty";
|
||||
case XLValueType::Boolean:
|
||||
return "boolean";
|
||||
case XLValueType::Integer:
|
||||
return "integer";
|
||||
case XLValueType::Float:
|
||||
return "float";
|
||||
case XLValueType::String:
|
||||
return "string";
|
||||
default:
|
||||
return "error";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @details Constructor
|
||||
* @pre The cell and cellNode pointers must not be nullptr and must point to valid objects.
|
||||
* @post A valid XLCellValueProxy has been created.
|
||||
*/
|
||||
XLCellValueProxy::XLCellValueProxy(XLCell* cell, XMLNode* cellNode) : m_cell(cell), m_cellNode(cellNode)
|
||||
{
|
||||
assert(cell); // NOLINT
|
||||
// assert(cellNode); // NOLINT
|
||||
// assert(!cellNode->empty()); // NOLINT
|
||||
}
|
||||
|
||||
/**
|
||||
* @details Destructor. Default implementation has been used.
|
||||
* @pre
|
||||
* @post
|
||||
*/
|
||||
XLCellValueProxy::~XLCellValueProxy() = default;
|
||||
|
||||
/**
|
||||
* @details Copy constructor. Default implementation has been used.
|
||||
* @pre
|
||||
* @post
|
||||
*/
|
||||
XLCellValueProxy::XLCellValueProxy(const XLCellValueProxy& other) = default;
|
||||
|
||||
/**
|
||||
* @details Move constructor. Default implementation has been used.
|
||||
* @pre
|
||||
* @post
|
||||
*/
|
||||
XLCellValueProxy::XLCellValueProxy(XLCellValueProxy&& other) noexcept = default;
|
||||
|
||||
/**
|
||||
* @details Copy assignment operator. The function is implemented in terms of the templated
|
||||
* value assignment operators, i.e. it is the XLCellValue that is that is copied,
|
||||
* not the object itself.
|
||||
* @pre
|
||||
* @post
|
||||
*/
|
||||
XLCellValueProxy& XLCellValueProxy::operator=(const XLCellValueProxy& other)
|
||||
{
|
||||
if (&other != this) {
|
||||
*this = other.getValue();
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @details Move assignment operator. Default implementation has been used.
|
||||
* @pre
|
||||
* @post
|
||||
*/
|
||||
XLCellValueProxy& XLCellValueProxy::operator=(XLCellValueProxy&& other) noexcept = default;
|
||||
|
||||
/**
|
||||
* @details Implicitly convert the XLCellValueProxy object to a XLCellValue object.
|
||||
* @pre
|
||||
* @post
|
||||
*/
|
||||
XLCellValueProxy::operator XLCellValue()
|
||||
{
|
||||
return getValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* @details Clear the contents of the cell. This removes all children of the cell node.
|
||||
* @pre The m_cellNode must not be null, and must point to a valid XML cell node object.
|
||||
* @post The cell node must be valid, but empty.
|
||||
*/
|
||||
XLCellValueProxy& XLCellValueProxy::clear()
|
||||
{
|
||||
// ===== Check that the m_cellNode is valid.
|
||||
assert(m_cellNode); // NOLINT
|
||||
assert(!m_cellNode->empty()); // NOLINT
|
||||
|
||||
// ===== Remove the type attribute
|
||||
m_cellNode->remove_attribute("t");
|
||||
|
||||
// ===== Disable space preservation (only relevant for strings).
|
||||
m_cellNode->remove_attribute(" xml:space");
|
||||
|
||||
// ===== Remove the value node.
|
||||
m_cellNode->remove_child("v");
|
||||
return *this;
|
||||
}
|
||||
/**
|
||||
* @details Set the cell value to a error state. This will remove all children and attributes, except
|
||||
* the type attribute, which is set to "e"
|
||||
* @pre The m_cellNode must not be null, and must point to a valid XML cell node object.
|
||||
* @post The cell node must be valid.
|
||||
*/
|
||||
XLCellValueProxy& XLCellValueProxy::setError(const std::string &error)
|
||||
{
|
||||
// ===== Check that the m_cellNode is valid.
|
||||
assert(m_cellNode); // NOLINT
|
||||
assert(!m_cellNode->empty()); // NOLINT
|
||||
|
||||
// ===== If the cell node doesn't have a type attribute, create it.
|
||||
if (!m_cellNode->attribute("t")) m_cellNode->append_attribute("t");
|
||||
|
||||
// ===== Set the type to "e", i.e. error
|
||||
m_cellNode->attribute("t").set_value("e");
|
||||
|
||||
// ===== If the cell node doesn't have a value child node, create it.
|
||||
if (!m_cellNode->child("v")) m_cellNode->append_child("v");
|
||||
|
||||
// ===== Set the child value to the error
|
||||
m_cellNode->child("v").text().set(error.c_str());
|
||||
|
||||
// ===== Disable space preservation (only relevant for strings).
|
||||
m_cellNode->remove_attribute(" xml:space");
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @details Get the value type for the cell.
|
||||
* @pre The m_cellNode must not be null, and must point to a valid XML cell node object.
|
||||
* @post No change should be made.
|
||||
*/
|
||||
XLValueType XLCellValueProxy::type() const
|
||||
{
|
||||
// ===== Check that the m_cellNode is valid.
|
||||
assert(m_cellNode); // NOLINT
|
||||
assert(!m_cellNode->empty()); // NOLINT
|
||||
|
||||
// ===== If neither a Type attribute or a getValue node is present, the cell is empty.
|
||||
if (!m_cellNode->attribute("t") && !m_cellNode->child("v")) return XLValueType::Empty;
|
||||
|
||||
// ===== If a Type attribute is not present, but a value node is, the cell contains a number.
|
||||
if ((!m_cellNode->attribute("t") || (strcmp(m_cellNode->attribute("t").value(), "n") == 0 && m_cellNode->child("v") != nullptr))) {
|
||||
std::string numberString = m_cellNode->child("v").text().get();
|
||||
if (numberString.find('.') != std::string::npos || numberString.find("E-") != std::string::npos ||
|
||||
numberString.find("e-") != std::string::npos)
|
||||
return XLValueType::Float;
|
||||
return XLValueType::Integer;
|
||||
}
|
||||
|
||||
// ===== If the cell is of type "s", the cell contains a shared string.
|
||||
if (m_cellNode->attribute("t") != nullptr && strcmp(m_cellNode->attribute("t").value(), "s") == 0)
|
||||
return XLValueType::String; // NOLINT
|
||||
|
||||
// ===== If the cell is of type "inlineStr", the cell contains an inline string.
|
||||
if (m_cellNode->attribute("t") != nullptr && strcmp(m_cellNode->attribute("t").value(), "inlineStr") == 0)
|
||||
return XLValueType::String;
|
||||
|
||||
// ===== If the cell is of type "str", the cell contains an ordinary string.
|
||||
if (m_cellNode->attribute("t") != nullptr && strcmp(m_cellNode->attribute("t").value(), "str") == 0)
|
||||
return XLValueType::String;
|
||||
|
||||
// ===== If the cell is of type "b", the cell contains a boolean.
|
||||
if (m_cellNode->attribute("t") != nullptr && strcmp(m_cellNode->attribute("t").value(), "b") == 0)
|
||||
return XLValueType::Boolean;
|
||||
|
||||
// ===== Otherwise, the cell contains an error.
|
||||
return XLValueType::Error; // the m_typeAttribute has the ValueAsString "e"
|
||||
}
|
||||
|
||||
/**
|
||||
* @details Get the value type of the current object, as a string representation.
|
||||
* @pre
|
||||
* @post
|
||||
*/
|
||||
std::string XLCellValueProxy::typeAsString() const
|
||||
{
|
||||
switch (type()) {
|
||||
case XLValueType::Empty:
|
||||
return "empty";
|
||||
case XLValueType::Boolean:
|
||||
return "boolean";
|
||||
case XLValueType::Integer:
|
||||
return "integer";
|
||||
case XLValueType::Float:
|
||||
return "float";
|
||||
case XLValueType::String:
|
||||
return "string";
|
||||
default:
|
||||
return "error";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @details Set cell to an integer value. This is private helper function for setting the cell value
|
||||
* directly in the underlying XML file.
|
||||
* @pre The m_cellNode must not be null, and must point to a valid XMLNode object.
|
||||
* @post The underlying XMLNode has been updated correctly, representing an integer value.
|
||||
*/
|
||||
void XLCellValueProxy::setInteger(int64_t numberValue)
|
||||
{
|
||||
// ===== Check that the m_cellNode is valid.
|
||||
assert(m_cellNode); // NOLINT
|
||||
assert(!m_cellNode->empty()); // NOLINT
|
||||
|
||||
// ===== If the cell node doesn't have a value child node, create it.
|
||||
if (!m_cellNode->child("v")) m_cellNode->append_child("v");
|
||||
|
||||
// ===== The type ("t") attribute is not required for number values.
|
||||
m_cellNode->remove_attribute("t");
|
||||
|
||||
// ===== Set the text of the value node.
|
||||
m_cellNode->child("v").text().set(numberValue);
|
||||
|
||||
// ===== Disable space preservation (only relevant for strings).
|
||||
m_cellNode->child("v").remove_attribute(m_cellNode->child("v").attribute("xml:space"));
|
||||
}
|
||||
|
||||
/**
|
||||
* @details Set the cell to a bool value. This is private helper function for setting the cell value
|
||||
* directly in the underlying XML file.
|
||||
* @pre The m_cellNode must not be null, and must point to a valid XMLNode object.
|
||||
* @post The underlying XMLNode has been updated correctly, representing an bool value.
|
||||
*/
|
||||
void XLCellValueProxy::setBoolean(bool numberValue)
|
||||
{
|
||||
// ===== Check that the m_cellNode is valid.
|
||||
assert(m_cellNode); // NOLINT
|
||||
assert(!m_cellNode->empty()); // NOLINT
|
||||
|
||||
// ===== If the cell node doesn't have a type child node, create it.
|
||||
if (!m_cellNode->attribute("t")) m_cellNode->append_attribute("t");
|
||||
|
||||
// ===== If the cell node doesn't have a value child node, create it.
|
||||
if (!m_cellNode->child("v")) m_cellNode->append_child("v");
|
||||
|
||||
// ===== Set the type attribute.
|
||||
m_cellNode->attribute("t").set_value("b");
|
||||
|
||||
// ===== Set the text of the value node.
|
||||
m_cellNode->child("v").text().set(numberValue ? 1 : 0);
|
||||
|
||||
// ===== Disable space preservation (only relevant for strings).
|
||||
m_cellNode->child("v").remove_attribute(m_cellNode->child("v").attribute("xml:space"));
|
||||
}
|
||||
|
||||
/**
|
||||
* @details Set the cell to a floating point value. This is private helper function for setting the cell value
|
||||
* directly in the underlying XML file.
|
||||
* @pre The m_cellNode must not be null, and must point to a valid XMLNode object.
|
||||
* @post The underlying XMLNode has been updated correctly, representing a floating point value.
|
||||
*/
|
||||
void XLCellValueProxy::setFloat(double numberValue)
|
||||
{
|
||||
// check for nan / inf
|
||||
if (std::isfinite(numberValue)) {
|
||||
// ===== Check that the m_cellNode is valid.
|
||||
assert(m_cellNode); // NOLINT
|
||||
assert(!m_cellNode->empty()); // NOLINT
|
||||
|
||||
// ===== If the cell node doesn't have a value child node, create it.
|
||||
if (!m_cellNode->child("v")) m_cellNode->append_child("v");
|
||||
|
||||
// ===== The type ("t") attribute is not required for number values.
|
||||
m_cellNode->remove_attribute("t");
|
||||
|
||||
// ===== Set the text of the value node.
|
||||
m_cellNode->child("v").text().set(numberValue);
|
||||
|
||||
// ===== Disable space preservation (only relevant for strings).
|
||||
m_cellNode->child("v").remove_attribute(m_cellNode->child("v").attribute("xml:space"));
|
||||
}
|
||||
else {
|
||||
setError("#NUM!");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @details Set the cell to a string value. This is private helper function for setting the cell value
|
||||
* directly in the underlying XML file.
|
||||
* @pre The m_cellNode must not be null, and must point to a valid XMLNode object.
|
||||
* @post The underlying XMLNode has been updated correctly, representing a string value.
|
||||
*/
|
||||
void XLCellValueProxy::setString(const char* stringValue)
|
||||
{
|
||||
// ===== Check that the m_cellNode is valid.
|
||||
assert(m_cellNode); // NOLINT
|
||||
assert(!m_cellNode->empty()); // NOLINT
|
||||
|
||||
// ===== If the cell node doesn't have a type child node, create it.
|
||||
if (!m_cellNode->attribute("t")) m_cellNode->append_attribute("t");
|
||||
|
||||
// ===== If the cell node doesn't have a value child node, create it.
|
||||
if (!m_cellNode->child("v")) m_cellNode->append_child("v");
|
||||
|
||||
// ===== Set the type attribute.
|
||||
m_cellNode->attribute("t").set_value("s");
|
||||
|
||||
// ===== Get or create the index in the XLSharedStrings object.
|
||||
auto index = (m_cell->m_sharedStrings.stringExists(stringValue) ? m_cell->m_sharedStrings.getStringIndex(stringValue)
|
||||
: m_cell->m_sharedStrings.appendString(stringValue));
|
||||
|
||||
// ===== Set the text of the value node.
|
||||
m_cellNode->child("v").text().set(index);
|
||||
|
||||
// IMPLEMENTATION FOR EMBEDDED STRINGS:
|
||||
// m_cellNode->attribute("t").set_value("str");
|
||||
// m_cellNode->child("v").text().set(stringValue);
|
||||
//
|
||||
// auto s = std::string_view(stringValue);
|
||||
// if (s.front() == ' ' || s.back() == ' ') {
|
||||
// if (!m_cellNode->attribute("xml:space")) m_cellNode->append_attribute("xml:space");
|
||||
// m_cellNode->attribute("xml:space").set_value("preserve");
|
||||
// }
|
||||
}
|
||||
|
||||
/**
|
||||
* @details Get a copy of the XLCellValue object for the cell. This is private helper function for returning an
|
||||
* XLCellValue object corresponding to the cell value.
|
||||
* @pre The m_cellNode must not be null, and must point to a valid XMLNode object.
|
||||
* @post No changes should be made.
|
||||
*/
|
||||
XLCellValue XLCellValueProxy::getValue() const
|
||||
{
|
||||
// ===== Check that the m_cellNode is valid.
|
||||
assert(m_cellNode); // NOLINT
|
||||
assert(!m_cellNode->empty()); // NOLINT
|
||||
|
||||
switch (type()) {
|
||||
case XLValueType::Empty:
|
||||
return XLCellValue().clear();
|
||||
|
||||
case XLValueType::Float:
|
||||
return XLCellValue { m_cellNode->child("v").text().as_double() };
|
||||
|
||||
case XLValueType::Integer:
|
||||
return XLCellValue { m_cellNode->child("v").text().as_llong() };
|
||||
|
||||
case XLValueType::String:
|
||||
if (strcmp(m_cellNode->attribute("t").value(), "s") == 0)
|
||||
return XLCellValue { m_cell->m_sharedStrings.getString(static_cast<uint32_t>(m_cellNode->child("v").text().as_ullong())) };
|
||||
else if (strcmp(m_cellNode->attribute("t").value(), "str") == 0)
|
||||
return XLCellValue { m_cellNode->child("v").text().get() };
|
||||
else if (strcmp(m_cellNode->attribute("t").value(), "inlineStr") == 0)
|
||||
return XLCellValue { m_cellNode->child("is").child("t").text().get() };
|
||||
else
|
||||
throw XLInternalError("Unknown string type");
|
||||
|
||||
case XLValueType::Boolean:
|
||||
return XLCellValue { m_cellNode->child("v").text().as_bool() };
|
||||
|
||||
case XLValueType::Error:
|
||||
return XLCellValue().setError(m_cellNode->child("v").text().as_string());
|
||||
|
||||
default:
|
||||
return XLCellValue().setError("");
|
||||
}
|
||||
}
|
||||
Vendored
+216
@@ -0,0 +1,216 @@
|
||||
/*
|
||||
|
||||
____ ____ ___ ____ ____ ____ ___
|
||||
6MMMMb `MM( )M' `MM' 6MMMMb\`MM( )M'
|
||||
8P Y8 `MM. d' MM 6M' ` `MM. d'
|
||||
6M Mb __ ____ ____ ___ __ `MM. d' MM MM `MM. d'
|
||||
MM MM `M6MMMMb 6MMMMb `MM 6MMb `MM. d' MM YM. `MM. d'
|
||||
MM MM MM' `Mb 6M' `Mb MMM9 `Mb `MMd MM YMMMMb `MMd
|
||||
MM MM MM MM MM MM MM' MM dMM. MM `Mb dMM.
|
||||
MM MM MM MM MMMMMMMM MM MM d'`MM. MM MM d'`MM.
|
||||
YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM.
|
||||
8b d8 MM. ,M9 YM d9 MM MM d' `MM. MM / L ,M9 d' `MM.
|
||||
YMMMM9 MMYMMM9 YMMMM9 _MM_ _MM_M(_ _)MM_ _MMMMMMM MYMMMM9 _M(_ _)MM_
|
||||
MM
|
||||
MM
|
||||
_MM_
|
||||
|
||||
Copyright (c) 2018, Kenneth Troldal Balslev
|
||||
|
||||
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.
|
||||
- Neither the name of the author nor the
|
||||
names of any 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 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.
|
||||
|
||||
*/
|
||||
|
||||
// ===== External Includes ===== //
|
||||
#include <algorithm>
|
||||
#include <sstream>
|
||||
|
||||
// ===== OpenXLSX Includes ===== //
|
||||
#include "XLColor.hpp"
|
||||
#include "XLException.hpp"
|
||||
|
||||
using namespace OpenXLSX;
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
XLColor::XLColor() = default;
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
XLColor::XLColor(uint8_t alpha, uint8_t red, uint8_t green, uint8_t blue) : m_alpha(alpha), m_red(red), m_green(green), m_blue(blue) {}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
XLColor::XLColor(uint8_t red, uint8_t green, uint8_t blue) : m_red(red), m_green(green), m_blue(blue) {}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
XLColor::XLColor(const std::string& hexCode)
|
||||
{
|
||||
set(hexCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
XLColor::XLColor(const XLColor& other) = default;
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
XLColor::XLColor(XLColor&& other) noexcept = default;
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
XLColor::~XLColor() = default;
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
XLColor& XLColor::operator=(const XLColor& other) = default;
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
XLColor& XLColor::operator=(XLColor&& other) noexcept = default;
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
void XLColor::set(uint8_t alpha, uint8_t red, uint8_t green, uint8_t blue)
|
||||
{
|
||||
m_alpha = alpha;
|
||||
m_red = red;
|
||||
m_green = green;
|
||||
m_blue = blue;
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
void XLColor::set(uint8_t red, uint8_t green, uint8_t blue)
|
||||
{
|
||||
m_red = red;
|
||||
m_green = green;
|
||||
m_blue = blue;
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
void XLColor::set(const std::string& hexCode)
|
||||
{
|
||||
std::string alpha;
|
||||
std::string red;
|
||||
std::string green;
|
||||
std::string blue;
|
||||
|
||||
auto temp = hex();
|
||||
|
||||
const int hexCodeSizeWithoutAlpha = 6;
|
||||
const int hexCodeSizeWithAlpha = 8;
|
||||
|
||||
if (hexCode.size() == hexCodeSizeWithoutAlpha) {
|
||||
alpha = hex().substr(0, 2);
|
||||
red = hexCode.substr(0, 2);
|
||||
green = hexCode.substr(2, 2);
|
||||
blue = hexCode.substr(4, 2);
|
||||
}
|
||||
|
||||
else if (hexCode.size() == hexCodeSizeWithAlpha) {
|
||||
alpha = hexCode.substr(0, 2);
|
||||
red = hexCode.substr(2, 2);
|
||||
green = hexCode.substr(4, 2);
|
||||
blue = hexCode.substr(6, 2); //NOLINT
|
||||
}
|
||||
else
|
||||
throw XLInputError("Invalid color code");
|
||||
|
||||
const int hexBase = 16;
|
||||
m_alpha = static_cast<uint8_t>(stoul(alpha, nullptr, hexBase));
|
||||
m_red = static_cast<uint8_t>(stoul(red, nullptr, hexBase));
|
||||
m_green = static_cast<uint8_t>(stoul(green, nullptr, hexBase));
|
||||
m_blue = static_cast<uint8_t>(stoul(blue, nullptr, hexBase));
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
uint8_t XLColor::alpha() const
|
||||
{
|
||||
return m_alpha;
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
uint8_t XLColor::red() const
|
||||
{
|
||||
return m_red;
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
uint8_t XLColor::green() const
|
||||
{
|
||||
return m_green;
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
uint8_t XLColor::blue() const
|
||||
{
|
||||
return m_blue;
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
std::string XLColor::hex() const
|
||||
{
|
||||
std::stringstream str;
|
||||
const int hexBase = 16;
|
||||
|
||||
if (m_alpha < hexBase) str << "0";
|
||||
str << std::hex << static_cast<int>(m_alpha);
|
||||
|
||||
if (m_red < hexBase) str << "0";
|
||||
str << std::hex << static_cast<int>(m_red);
|
||||
|
||||
if (m_green < hexBase) str << "0";
|
||||
str << std::hex << static_cast<int>(m_green);
|
||||
|
||||
if (m_blue < hexBase) str << "0";
|
||||
str << std::hex << static_cast<int>(m_blue);
|
||||
|
||||
return (str.str());
|
||||
}
|
||||
Vendored
+125
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
|
||||
____ ____ ___ ____ ____ ____ ___
|
||||
6MMMMb `MM( )M' `MM' 6MMMMb\`MM( )M'
|
||||
8P Y8 `MM. d' MM 6M' ` `MM. d'
|
||||
6M Mb __ ____ ____ ___ __ `MM. d' MM MM `MM. d'
|
||||
MM MM `M6MMMMb 6MMMMb `MM 6MMb `MM. d' MM YM. `MM. d'
|
||||
MM MM MM' `Mb 6M' `Mb MMM9 `Mb `MMd MM YMMMMb `MMd
|
||||
MM MM MM MM MM MM MM' MM dMM. MM `Mb dMM.
|
||||
MM MM MM MM MMMMMMMM MM MM d'`MM. MM MM d'`MM.
|
||||
YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM.
|
||||
8b d8 MM. ,M9 YM d9 MM MM d' `MM. MM / L ,M9 d' `MM.
|
||||
YMMMM9 MMYMMM9 YMMMM9 _MM_ _MM_M(_ _)MM_ _MMMMMMM MYMMMM9 _M(_ _)MM_
|
||||
MM
|
||||
MM
|
||||
_MM_
|
||||
|
||||
Copyright (c) 2018, Kenneth Troldal Balslev
|
||||
|
||||
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.
|
||||
- Neither the name of the author nor the
|
||||
names of any 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 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.
|
||||
|
||||
*/
|
||||
|
||||
// ===== External Includes ===== //
|
||||
#include <pugixml.hpp>
|
||||
|
||||
// ===== OpenXLSX Includes ===== //
|
||||
#include "XLColumn.hpp"
|
||||
|
||||
using namespace OpenXLSX;
|
||||
|
||||
/**
|
||||
* @details Assumes each node only has data for one column.
|
||||
*/
|
||||
XLColumn::XLColumn(const XMLNode& columnNode) : m_columnNode(std::make_unique<XMLNode>(columnNode)) {}
|
||||
|
||||
XLColumn::XLColumn(const XLColumn& other) : m_columnNode(std::make_unique<XMLNode>(*other.m_columnNode)) {}
|
||||
|
||||
XLColumn::XLColumn(XLColumn&& other) noexcept = default;
|
||||
|
||||
XLColumn::~XLColumn() = default;
|
||||
|
||||
XLColumn& XLColumn::operator=(const XLColumn& other)
|
||||
{
|
||||
if (&other != this) *m_columnNode = *other.m_columnNode;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
float XLColumn::width() const
|
||||
{
|
||||
return columnNode().attribute("width").as_float();
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
void XLColumn::setWidth(float width) // NOLINT
|
||||
{
|
||||
// Set the 'Width' attribute for the Cell. If it does not exist, create it.
|
||||
auto widthAtt = columnNode().attribute("width");
|
||||
if (!widthAtt) widthAtt = columnNode().append_attribute("width");
|
||||
|
||||
widthAtt.set_value(width);
|
||||
|
||||
// Set the 'customWidth' attribute for the Cell. If it does not exist, create it.
|
||||
auto customAtt = columnNode().attribute("customWidth");
|
||||
if (!customAtt) customAtt = columnNode().append_attribute("customWidth");
|
||||
|
||||
customAtt.set_value("1");
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
bool XLColumn::isHidden() const
|
||||
{
|
||||
return columnNode().attribute("hidden").as_bool();
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
void XLColumn::setHidden(bool state) // NOLINT
|
||||
{
|
||||
auto hiddenAtt = columnNode().attribute("hidden");
|
||||
if (!hiddenAtt) hiddenAtt = columnNode().append_attribute("hidden");
|
||||
|
||||
if (state)
|
||||
hiddenAtt.set_value("1");
|
||||
else
|
||||
hiddenAtt.set_value("0");
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
XMLNode& XLColumn::columnNode() const
|
||||
{
|
||||
return *m_columnNode;
|
||||
}
|
||||
+303
@@ -0,0 +1,303 @@
|
||||
/*
|
||||
|
||||
____ ____ ___ ____ ____ ____ ___
|
||||
6MMMMb `MM( )M' `MM' 6MMMMb\`MM( )M'
|
||||
8P Y8 `MM. d' MM 6M' ` `MM. d'
|
||||
6M Mb __ ____ ____ ___ __ `MM. d' MM MM `MM. d'
|
||||
MM MM `M6MMMMb 6MMMMb `MM 6MMb `MM. d' MM YM. `MM. d'
|
||||
MM MM MM' `Mb 6M' `Mb MMM9 `Mb `MMd MM YMMMMb `MMd
|
||||
MM MM MM MM MM MM MM' MM dMM. MM `Mb dMM.
|
||||
MM MM MM MM MMMMMMMM MM MM d'`MM. MM MM d'`MM.
|
||||
YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM.
|
||||
8b d8 MM. ,M9 YM d9 MM MM d' `MM. MM / L ,M9 d' `MM.
|
||||
YMMMM9 MMYMMM9 YMMMM9 _MM_ _MM_M(_ _)MM_ _MMMMMMM MYMMMM9 _M(_ _)MM_
|
||||
MM
|
||||
MM
|
||||
_MM_
|
||||
|
||||
Copyright (c) 2018, Kenneth Troldal Balslev
|
||||
|
||||
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.
|
||||
- Neither the name of the author nor the
|
||||
names of any 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 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.
|
||||
|
||||
*/
|
||||
|
||||
// ===== External Includes ===== //
|
||||
#include <cstring>
|
||||
#include <pugixml.hpp>
|
||||
|
||||
// ===== OpenXLSX Includes ===== //
|
||||
#include "XLContentTypes.hpp"
|
||||
#include "XLDocument.hpp"
|
||||
|
||||
using namespace OpenXLSX;
|
||||
|
||||
namespace
|
||||
{
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
XLContentType GetTypeFromString(const std::string& typeString)
|
||||
{
|
||||
XLContentType type;
|
||||
|
||||
if (typeString == "application/vnd.ms-excel.Sheet.macroEnabled.main+xml")
|
||||
type = XLContentType::WorkbookMacroEnabled;
|
||||
else if (typeString == "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml")
|
||||
type = XLContentType::Workbook;
|
||||
else if (typeString == "application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml")
|
||||
type = XLContentType::Worksheet;
|
||||
else if (typeString == "application/vnd.openxmlformats-officedocument.spreadsheetml.chartsheet+xml")
|
||||
type = XLContentType::Chartsheet;
|
||||
else if (typeString == "application/vnd.openxmlformats-officedocument.spreadsheetml.externalLink+xml")
|
||||
type = XLContentType::ExternalLink;
|
||||
else if (typeString == "application/vnd.openxmlformats-officedocument.theme+xml")
|
||||
type = XLContentType::Theme;
|
||||
else if (typeString == "application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml")
|
||||
type = XLContentType::Styles;
|
||||
else if (typeString == "application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml")
|
||||
type = XLContentType::SharedStrings;
|
||||
else if (typeString == "application/vnd.openxmlformats-officedocument.drawing+xml")
|
||||
type = XLContentType::Drawing;
|
||||
else if (typeString == "application/vnd.openxmlformats-officedocument.drawingml.chart+xml")
|
||||
type = XLContentType::Chart;
|
||||
else if (typeString == "application/vnd.ms-office.chartstyle+xml")
|
||||
type = XLContentType::ChartStyle;
|
||||
else if (typeString == "application/vnd.ms-office.chartcolorstyle+xml")
|
||||
type = XLContentType::ChartColorStyle;
|
||||
else if (typeString == "application/vnd.ms-excel.controlproperties+xml")
|
||||
type = XLContentType::ControlProperties;
|
||||
else if (typeString == "application/vnd.openxmlformats-officedocument.spreadsheetml.calcChain+xml")
|
||||
type = XLContentType::CalculationChain;
|
||||
else if (typeString == "application/vnd.ms-office.vbaProject")
|
||||
type = XLContentType::VBAProject;
|
||||
else if (typeString == "application/vnd.openxmlformats-package.core-properties+xml")
|
||||
type = XLContentType::CoreProperties;
|
||||
else if (typeString == "application/vnd.openxmlformats-officedocument.extended-properties+xml")
|
||||
type = XLContentType::ExtendedProperties;
|
||||
else if (typeString == "application/vnd.openxmlformats-officedocument.custom-properties+xml")
|
||||
type = XLContentType::CustomProperties;
|
||||
else if (typeString == "application/vnd.openxmlformats-officedocument.spreadsheetml.comments+xml")
|
||||
type = XLContentType::Comments;
|
||||
else if (typeString == "application/vnd.openxmlformats-officedocument.spreadsheetml.table+xml")
|
||||
type = XLContentType::Table;
|
||||
else if (typeString == "application/vnd.openxmlformats-officedocument.vmlDrawing")
|
||||
type = XLContentType::VMLDrawing;
|
||||
else
|
||||
type = XLContentType::Unknown;
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
std::string GetStringFromType(XLContentType type)
|
||||
{
|
||||
std::string typeString;
|
||||
|
||||
if (type == XLContentType::WorkbookMacroEnabled)
|
||||
typeString = "application/vnd.ms-excel.Sheet.macroEnabled.main+xml";
|
||||
else if (type == XLContentType::Workbook)
|
||||
typeString = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml";
|
||||
else if (type == XLContentType::Worksheet)
|
||||
typeString = "application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml";
|
||||
else if (type == XLContentType::Chartsheet)
|
||||
typeString = "application/vnd.openxmlformats-officedocument.spreadsheetml.chartsheet+xml";
|
||||
else if (type == XLContentType::ExternalLink)
|
||||
typeString = "application/vnd.openxmlformats-officedocument.spreadsheetml.externalLink+xml";
|
||||
else if (type == XLContentType::Theme)
|
||||
typeString = "application/vnd.openxmlformats-officedocument.theme+xml";
|
||||
else if (type == XLContentType::Styles)
|
||||
typeString = "application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml";
|
||||
else if (type == XLContentType::SharedStrings)
|
||||
typeString = "application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml";
|
||||
else if (type == XLContentType::Drawing)
|
||||
typeString = "application/vnd.openxmlformats-officedocument.drawing+xml";
|
||||
else if (type == XLContentType::Chart)
|
||||
typeString = "application/vnd.openxmlformats-officedocument.drawingml.chart+xml";
|
||||
else if (type == XLContentType::ChartStyle)
|
||||
typeString = "application/vnd.ms-office.chartstyle+xml";
|
||||
else if (type == XLContentType::ChartColorStyle)
|
||||
typeString = "application/vnd.ms-office.chartcolorstyle+xml";
|
||||
else if (type == XLContentType::ControlProperties)
|
||||
typeString = "application/vnd.ms-excel.controlproperties+xml";
|
||||
else if (type == XLContentType::CalculationChain)
|
||||
typeString = "application/vnd.openxmlformats-officedocument.spreadsheetml.calcChain+xml";
|
||||
else if (type == XLContentType::VBAProject)
|
||||
typeString = "application/vnd.ms-office.vbaProject";
|
||||
else if (type == XLContentType::CoreProperties)
|
||||
typeString = "application/vnd.openxmlformats-package.core-properties+xml";
|
||||
else if (type == XLContentType::ExtendedProperties)
|
||||
typeString = "application/vnd.openxmlformats-officedocument.extended-properties+xml";
|
||||
else if (type == XLContentType::CustomProperties)
|
||||
typeString = "application/vnd.openxmlformats-officedocument.custom-properties+xml";
|
||||
else if (type == XLContentType::Comments)
|
||||
typeString = "application/vnd.openxmlformats-officedocument.spreadsheetml.comments+xml";
|
||||
else if (type == XLContentType::Table)
|
||||
typeString = "application/vnd.openxmlformats-officedocument.spreadsheetml.table+xml";
|
||||
else if (type == XLContentType::VMLDrawing)
|
||||
typeString = "application/vnd.openxmlformats-officedocument.vmlDrawing";
|
||||
else
|
||||
throw XLInternalError("Unknown ContentType");
|
||||
|
||||
return typeString;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
XLContentItem::XLContentItem() : m_contentNode(std::make_unique<XMLNode>()) {}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
XLContentItem::XLContentItem(const XMLNode& node) : m_contentNode(std::make_unique<XMLNode>(node)) {}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
XLContentItem::XLContentItem(const XLContentItem& other) : m_contentNode(std::make_unique<XMLNode>(*other.m_contentNode)) {}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
XLContentItem::XLContentItem(XLContentItem&& other) noexcept = default;
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
XLContentItem::~XLContentItem() = default;
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
XLContentItem& XLContentItem::operator=(const XLContentItem& other)
|
||||
{
|
||||
if (&other != this) *m_contentNode = *other.m_contentNode;
|
||||
return *this;
|
||||
}
|
||||
|
||||
XLContentItem& XLContentItem::operator=(XLContentItem&& other) noexcept = default;
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
XLContentType XLContentItem::type() const
|
||||
{
|
||||
return GetTypeFromString(m_contentNode->attribute("ContentType").value());
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
std::string XLContentItem::path() const
|
||||
{
|
||||
return m_contentNode->attribute("PartName").value();
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
XLContentTypes::XLContentTypes() = default;
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
XLContentTypes::XLContentTypes(XLXmlData* xmlData) : XLXmlFile(xmlData) {}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
XLContentTypes::~XLContentTypes() = default;
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
XLContentTypes::XLContentTypes(const XLContentTypes& other) = default;
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
XLContentTypes::XLContentTypes(XLContentTypes&& other) noexcept = default;
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
XLContentTypes& XLContentTypes::operator=(const XLContentTypes& other) = default;
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
XLContentTypes& XLContentTypes::operator=(XLContentTypes&& other) noexcept = default;
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
void XLContentTypes::addOverride(const std::string& path, XLContentType type)
|
||||
{
|
||||
std::string typeString = GetStringFromType(type);
|
||||
|
||||
auto node = xmlDocument().first_child().append_child("Override");
|
||||
node.append_attribute("PartName").set_value(path.c_str());
|
||||
node.append_attribute("ContentType").set_value(typeString.c_str());
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
void XLContentTypes::deleteOverride(const std::string& path)
|
||||
{
|
||||
xmlDocument().document_element().remove_child(xmlDocument().document_element().find_child_by_attribute("PartName", path.c_str()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
void XLContentTypes::deleteOverride(XLContentItem& item)
|
||||
{
|
||||
deleteOverride(item.path());
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
XLContentItem XLContentTypes::contentItem(const std::string& path)
|
||||
{
|
||||
return XLContentItem(xmlDocument().document_element().find_child_by_attribute("PartName", path.c_str()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
std::vector<XLContentItem> XLContentTypes::getContentItems()
|
||||
{
|
||||
std::vector<XLContentItem> result;
|
||||
for (auto item : xmlDocument().document_element().children()) {
|
||||
if (strcmp(item.name(), "Override") == 0) result.emplace_back(item);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
+249
@@ -0,0 +1,249 @@
|
||||
//
|
||||
// Created by Kenneth Balslev on 28/08/2021.
|
||||
//
|
||||
|
||||
#include "XLDateTime.hpp"
|
||||
#include "XLException.hpp"
|
||||
#include <string>
|
||||
#include <cmath>
|
||||
|
||||
namespace {
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param year
|
||||
* @return
|
||||
*/
|
||||
bool isLeapYear(int year) {
|
||||
|
||||
if (year == 1900) return true;
|
||||
if (year % 400 == 0 || (year % 4 == 0 && year % 100 != 0))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param month
|
||||
* @param year
|
||||
* @return
|
||||
*/
|
||||
int daysInMonth(int month, int year) {
|
||||
switch (month) {
|
||||
case 1:
|
||||
return 31;
|
||||
case 2:
|
||||
return (isLeapYear(year) ? 29 : 28);
|
||||
case 3:
|
||||
return 31;
|
||||
case 4:
|
||||
return 30;
|
||||
case 5:
|
||||
return 31;
|
||||
case 6:
|
||||
return 30;
|
||||
case 7:
|
||||
return 31;
|
||||
case 8:
|
||||
return 31;
|
||||
case 9:
|
||||
return 30;
|
||||
case 10:
|
||||
return 31;
|
||||
case 11:
|
||||
return 30;
|
||||
case 12:
|
||||
return 31;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param serial
|
||||
* @return
|
||||
*/
|
||||
int dayOfWeek(double serial) {
|
||||
auto day = static_cast<int32_t>(serial) % 7;
|
||||
return (day == 0 ? 6 : day - 1);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace OpenXLSX
|
||||
{
|
||||
/**
|
||||
* @details Conctructor. Default implementation.
|
||||
*/
|
||||
XLDateTime::XLDateTime() = default;
|
||||
|
||||
/**
|
||||
* @details Constructor taking an Excel date/time serial number as an argument.
|
||||
*/
|
||||
XLDateTime::XLDateTime(double serial) : m_serial(serial) {
|
||||
if (serial < 1.0) throw XLDateTimeError("Excel date/time serial number is invalid (must be >= 1.0.)");
|
||||
}
|
||||
|
||||
/**
|
||||
* @details Constructor taking a std::tm object as an argument.
|
||||
*/
|
||||
XLDateTime::XLDateTime(const std::tm& timepoint) {
|
||||
|
||||
// ===== Check validity of tm struct.
|
||||
// ===== Only year, month and day of the month are checked. Other variables are ignored.
|
||||
if (timepoint.tm_year < 0)
|
||||
throw XLDateTimeError("Invalid year. Must be >= 0.");
|
||||
if (timepoint.tm_mon < 0 || timepoint.tm_mon > 11)
|
||||
throw XLDateTimeError("Invalid month. Must be >= 0 or <= 11.");
|
||||
if (timepoint.tm_mday <= 0 || timepoint.tm_mday > daysInMonth(timepoint.tm_mon + 1, timepoint.tm_year + 1900))
|
||||
throw XLDateTimeError("Invalid day. Must be >= 1 or <= total days in the month.");
|
||||
|
||||
// ===== Count the number of days for full years past 1900
|
||||
for (int i = 0; i < timepoint.tm_year; ++i) {
|
||||
m_serial += (isLeapYear(1900 + i) ? 366 : 365);
|
||||
}
|
||||
|
||||
// ===== Count the number of days for full months of the last year
|
||||
for (int i = 0; i < timepoint.tm_mon; ++i) {
|
||||
m_serial += daysInMonth(i + 1, timepoint.tm_year + 1900);
|
||||
}
|
||||
|
||||
// ===== Add the number of days of the month, minus one.
|
||||
// ===== (The reason for the 'minus one' is that unlike the other fields in the struct,
|
||||
// ===== tm_day represents the date of a month, whereas the other fields typically
|
||||
// ===== represents the number of whole units since the start).
|
||||
m_serial += timepoint.tm_mday - 1;
|
||||
|
||||
// ===== Convert hour, minute and second to fraction of a full day.
|
||||
int32_t seconds = timepoint.tm_hour * 3600 + timepoint.tm_min * 60 + timepoint.tm_sec;
|
||||
m_serial += seconds / 86400.0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @details Constructor taking a unixtime format (seconds since 1/1/1970) as an argument.
|
||||
*/
|
||||
XLDateTime::XLDateTime(time_t unixtime) {
|
||||
// There are 86400 seconds in a day
|
||||
// There are 25569 days between 1/1/1970 and 30/12/1899 (the epoch used by Excel)
|
||||
m_serial = static_cast<double>(unixtime) / 86400 + 25569;
|
||||
}
|
||||
|
||||
/**
|
||||
* @details Copy constructor. Default implementation.
|
||||
*/
|
||||
XLDateTime::XLDateTime(const XLDateTime& other) = default;
|
||||
|
||||
/**
|
||||
* @details Move constructor. Default implementation.
|
||||
*/
|
||||
XLDateTime::XLDateTime(XLDateTime&& other) noexcept = default;
|
||||
|
||||
/**
|
||||
* @details Destructor. Default implementation.
|
||||
*/
|
||||
XLDateTime::~XLDateTime() = default;
|
||||
|
||||
/**
|
||||
* @details Copy assignment operator. Default implementation.
|
||||
*/
|
||||
XLDateTime& XLDateTime::operator=(const XLDateTime& other) = default;
|
||||
|
||||
/**
|
||||
* @details Move assignment operator. Default implementation.
|
||||
*/
|
||||
XLDateTime& XLDateTime::operator=(XLDateTime&& other) noexcept = default;
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
XLDateTime& XLDateTime::operator=(double serial)
|
||||
{
|
||||
XLDateTime temp(serial);
|
||||
std::swap(*this, temp);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
XLDateTime& XLDateTime::operator=(const std::tm& timepoint)
|
||||
{
|
||||
XLDateTime temp(timepoint);
|
||||
std::swap(*this, temp);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
XLDateTime::operator std::tm() const
|
||||
{
|
||||
return tm();
|
||||
}
|
||||
|
||||
/**
|
||||
* @details Get the time point as an Excel date/time serial number.
|
||||
*/
|
||||
double XLDateTime::serial() const
|
||||
{
|
||||
return m_serial;
|
||||
}
|
||||
|
||||
/**
|
||||
* @details Get the time point as a std::tm object.
|
||||
*/
|
||||
std::tm XLDateTime::tm() const
|
||||
{
|
||||
// ===== Create and initialize the resulting object.
|
||||
std::tm result {};
|
||||
result.tm_year = 0;
|
||||
result.tm_mon = 0;
|
||||
result.tm_mday = 0;
|
||||
result.tm_wday = 0;
|
||||
result.tm_yday = 0;
|
||||
result.tm_hour = 0;
|
||||
result.tm_min = 0;
|
||||
result.tm_sec = 0;
|
||||
result.tm_isdst = -1;
|
||||
double serial = m_serial;
|
||||
|
||||
// ===== Count the number of whole years since 1900.
|
||||
while (true) {
|
||||
auto days = (isLeapYear(result.tm_year + 1900) ? 366 : 365);
|
||||
if (days > serial) break;
|
||||
serial -= days;
|
||||
++result.tm_year;
|
||||
}
|
||||
|
||||
// ===== Calculate the day of the year, and the day of the week
|
||||
result.tm_yday = static_cast<int>(serial) - 1;
|
||||
result.tm_wday = dayOfWeek(m_serial);
|
||||
|
||||
// ===== Count the number of whole months in the year.
|
||||
while (true) {
|
||||
auto days = daysInMonth(result.tm_mon + 1, 1900 + result.tm_year);
|
||||
if (days > serial) break;
|
||||
serial -= days;
|
||||
++result.tm_mon;
|
||||
}
|
||||
|
||||
// ===== Calculate the number of days.
|
||||
result.tm_mday = static_cast<int>(serial);
|
||||
serial -= result.tm_mday;
|
||||
|
||||
// ===== Calculate the number of hours.
|
||||
result.tm_hour = static_cast<int>(serial * 24);
|
||||
serial -= (result.tm_hour / 24.0);
|
||||
|
||||
// ===== Calculate the number of minutes.
|
||||
result.tm_min = static_cast<int>(serial * 24 * 60);
|
||||
serial -= (result.tm_min / (24.0 * 60.0));
|
||||
|
||||
// ===== Calculate the number of seconds.
|
||||
result.tm_sec = static_cast<int>(lround(serial * 24 * 60 * 60));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace OpenXLSX
|
||||
+1028
File diff suppressed because it is too large
Load Diff
Vendored
+190
@@ -0,0 +1,190 @@
|
||||
//
|
||||
// Created by Kenneth Balslev on 27/08/2021.
|
||||
//
|
||||
|
||||
// ===== OpenXLSX Includes ===== //
|
||||
#include "XLFormula.hpp"
|
||||
#include <pugixml.hpp>
|
||||
|
||||
#include <cassert>
|
||||
|
||||
using namespace OpenXLSX;
|
||||
|
||||
/**
|
||||
* @details Constructor. Default implementation.
|
||||
*/
|
||||
XLFormula::XLFormula() = default;
|
||||
|
||||
/**
|
||||
* @details Copy constructor. Default implementation.
|
||||
*/
|
||||
XLFormula::XLFormula(const XLFormula& other) = default;
|
||||
|
||||
/**
|
||||
* @details Move constructor. Default implementation.
|
||||
*/
|
||||
XLFormula::XLFormula(XLFormula&& other) noexcept = default;
|
||||
|
||||
/**
|
||||
* @details Destructor. Default implementation.
|
||||
*/
|
||||
XLFormula::~XLFormula() = default;
|
||||
|
||||
/**
|
||||
* @details Copy assignment operator. Default implementation.
|
||||
*/
|
||||
XLFormula& XLFormula::operator=(const XLFormula& other) = default;
|
||||
|
||||
/**
|
||||
* @details Move assignment operator. Default implementation.
|
||||
*/
|
||||
XLFormula& XLFormula::operator=(XLFormula&& other) noexcept = default;
|
||||
|
||||
/**
|
||||
* @details Return the m_formulaString member variable.
|
||||
*/
|
||||
std::string XLFormula::get() const
|
||||
{
|
||||
return m_formulaString;
|
||||
}
|
||||
|
||||
/**
|
||||
* @details Set the m_formulaString member to an empty string.
|
||||
*/
|
||||
XLFormula& XLFormula::clear()
|
||||
{
|
||||
m_formulaString = "";
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
XLFormula::operator std::string() const
|
||||
{
|
||||
return get();
|
||||
}
|
||||
|
||||
/**
|
||||
* @details Constructor. Set the m_cell and m_cellNode objects.
|
||||
*/
|
||||
XLFormulaProxy::XLFormulaProxy(XLCell* cell, XMLNode* cellNode) : m_cell(cell), m_cellNode(cellNode)
|
||||
{
|
||||
assert(cell); // NOLINT
|
||||
}
|
||||
|
||||
/**
|
||||
* @details Destructor. Default implementation.
|
||||
*/
|
||||
XLFormulaProxy::~XLFormulaProxy() = default;
|
||||
|
||||
/**
|
||||
* @details Copy constructor. default implementation.
|
||||
*/
|
||||
XLFormulaProxy::XLFormulaProxy(const XLFormulaProxy& other) = default;
|
||||
|
||||
/**
|
||||
* @details Move constructor. Default implementation.
|
||||
*/
|
||||
XLFormulaProxy::XLFormulaProxy(XLFormulaProxy&& other) noexcept = default;
|
||||
|
||||
/**
|
||||
* @details Calls the templated string assignment operator.
|
||||
*/
|
||||
XLFormulaProxy& XLFormulaProxy::operator=(const XLFormulaProxy& other)
|
||||
{
|
||||
if (&other != this) {
|
||||
*this = other.getFormula();
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @details Move assignment operator. Default implementation.
|
||||
*/
|
||||
XLFormulaProxy& XLFormulaProxy::operator=(XLFormulaProxy&& other) noexcept = default;
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
XLFormulaProxy::operator std::string() const
|
||||
{
|
||||
return get();
|
||||
}
|
||||
|
||||
/**
|
||||
* @details Returns the underlying XLFormula object, by calling getFormula().
|
||||
*/
|
||||
XLFormulaProxy::operator XLFormula() const
|
||||
{
|
||||
return getFormula();
|
||||
}
|
||||
|
||||
/**
|
||||
* @details Call the .get() function in the underlying XLFormula object.
|
||||
*/
|
||||
std::string XLFormulaProxy::get() const
|
||||
{
|
||||
return getFormula().get();
|
||||
}
|
||||
|
||||
/**
|
||||
* @details If a formula node exists, it will be erased.
|
||||
*/
|
||||
XLFormulaProxy& XLFormulaProxy::clear()
|
||||
{
|
||||
// ===== Check that the m_cellNode is valid.
|
||||
assert(m_cellNode); // NOLINT
|
||||
assert(!m_cellNode->empty()); // NOLINT
|
||||
|
||||
// ===== Remove the value node.
|
||||
if (m_cellNode->child("f")) m_cellNode->remove_child("f");
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @details Convenience function for setting the formula. This method is called from the templated
|
||||
* string assignment operator.
|
||||
*/
|
||||
void XLFormulaProxy::setFormulaString(const char* formulaString) {
|
||||
// ===== Check that the m_cellNode is valid.
|
||||
assert(m_cellNode); // NOLINT
|
||||
assert(!m_cellNode->empty()); // NOLINT
|
||||
|
||||
// ===== If the cell node doesn't have a value child node, create it.
|
||||
if (!m_cellNode->child("f")) m_cellNode->append_child("f");
|
||||
if (!m_cellNode->child("v")) m_cellNode->append_child("v");
|
||||
|
||||
// ===== Remove the type and shared index attributes, if they exists.
|
||||
m_cellNode->child("f").remove_attribute("t");
|
||||
m_cellNode->child("f").remove_attribute("si");
|
||||
|
||||
// ===== Set the text of the value node.
|
||||
m_cellNode->child("f").text().set(formulaString);
|
||||
m_cellNode->child("v").text().set(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @details Creates and returns an XLFormula object, based on the formula string in the underlying
|
||||
* XML document.
|
||||
*/
|
||||
XLFormula XLFormulaProxy::getFormula() const
|
||||
{
|
||||
assert(m_cellNode); // NOLINT
|
||||
assert(!m_cellNode->empty()); // NOLINT
|
||||
|
||||
auto formulaNode = m_cellNode->child("f");
|
||||
|
||||
// ===== If the formula node doesn't exist, return an empty XLFormula object.
|
||||
if (!formulaNode)
|
||||
return XLFormula();
|
||||
|
||||
// ===== If the formula type is 'shared' or 'array', throw an exception.
|
||||
if (formulaNode.attribute("t") && std::string(formulaNode.attribute("t").value()) == "shared")
|
||||
throw XLFormulaError("Shared formulas not supported.");
|
||||
if (formulaNode.attribute("t") && std::string(formulaNode.attribute("t").value()) == "array")
|
||||
throw XLFormulaError("Array formulas not supported.");
|
||||
|
||||
return XLFormula(formulaNode.text().get());
|
||||
}
|
||||
+349
@@ -0,0 +1,349 @@
|
||||
/*
|
||||
|
||||
____ ____ ___ ____ ____ ____ ___
|
||||
6MMMMb `MM( )M' `MM' 6MMMMb\`MM( )M'
|
||||
8P Y8 `MM. d' MM 6M' ` `MM. d'
|
||||
6M Mb __ ____ ____ ___ __ `MM. d' MM MM `MM. d'
|
||||
MM MM `M6MMMMb 6MMMMb `MM 6MMb `MM. d' MM YM. `MM. d'
|
||||
MM MM MM' `Mb 6M' `Mb MMM9 `Mb `MMd MM YMMMMb `MMd
|
||||
MM MM MM MM MM MM MM' MM dMM. MM `Mb dMM.
|
||||
MM MM MM MM MMMMMMMM MM MM d'`MM. MM MM d'`MM.
|
||||
YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM.
|
||||
8b d8 MM. ,M9 YM d9 MM MM d' `MM. MM / L ,M9 d' `MM.
|
||||
YMMMM9 MMYMMM9 YMMMM9 _MM_ _MM_M(_ _)MM_ _MMMMMMM MYMMMM9 _M(_ _)MM_
|
||||
MM
|
||||
MM
|
||||
_MM_
|
||||
|
||||
Copyright (c) 2018, Kenneth Troldal Balslev
|
||||
|
||||
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.
|
||||
- Neither the name of the author nor the
|
||||
names of any 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 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.
|
||||
|
||||
*/
|
||||
|
||||
#include <pugixml.hpp>
|
||||
|
||||
// ===== External Includes ===== //
|
||||
#include "XLDocument.hpp"
|
||||
#include "XLProperties.hpp"
|
||||
|
||||
using namespace OpenXLSX;
|
||||
|
||||
namespace
|
||||
{
|
||||
inline XMLAttribute headingPairsSize(XMLNode docNode)
|
||||
{
|
||||
return docNode.child("HeadingPairs").first_child().attribute("size");
|
||||
}
|
||||
|
||||
inline XMLNode headingPairsCategories(XMLNode docNode)
|
||||
{
|
||||
return docNode.child("HeadingPairs").first_child().first_child();
|
||||
}
|
||||
|
||||
inline XMLNode headingPairsCounts(XMLNode docNode)
|
||||
{
|
||||
return headingPairsCategories(docNode).next_sibling();
|
||||
}
|
||||
|
||||
inline XMLNode sheetNames(XMLNode docNode)
|
||||
{
|
||||
return docNode.child("TitlesOfParts").first_child();
|
||||
}
|
||||
|
||||
inline XMLAttribute sheetCount(XMLNode docNode)
|
||||
{
|
||||
return sheetNames(docNode).attribute("size");
|
||||
}
|
||||
} // namespace
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
XLProperties::XLProperties(XLXmlData* xmlData) : XLXmlFile(xmlData) {}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
XLProperties::~XLProperties() = default;
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
void XLProperties::setProperty(const std::string& name, const std::string& value)
|
||||
{
|
||||
if (!m_xmlData) return;
|
||||
XMLNode node;
|
||||
if (xmlDocument().first_child().child(name.c_str()) != nullptr)
|
||||
node = xmlDocument().first_child().child(name.c_str());
|
||||
else
|
||||
node = xmlDocument().first_child().prepend_child(name.c_str());
|
||||
|
||||
node.text().set(value.c_str());
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
void XLProperties::setProperty(const std::string& name, int value)
|
||||
{
|
||||
setProperty(name, std::to_string(value));
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
void XLProperties::setProperty(const std::string& name, double value)
|
||||
{
|
||||
setProperty(name, std::to_string(value));
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
std::string XLProperties::property(const std::string& name) const
|
||||
{
|
||||
if (!m_xmlData) return "";
|
||||
auto property = xmlDocument().first_child().child(name.c_str());
|
||||
if (!property) {
|
||||
property = xmlDocument().first_child().append_child(name.c_str());
|
||||
}
|
||||
|
||||
return property.text().get();
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
void XLProperties::deleteProperty(const std::string& name)
|
||||
{
|
||||
if (!m_xmlData) return;
|
||||
auto property = xmlDocument().first_child().child(name.c_str());
|
||||
if (property != nullptr) xmlDocument().first_child().remove_child(property);
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
XLAppProperties::XLAppProperties(XLXmlData* xmlData) : XLXmlFile(xmlData) {}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
XLAppProperties::~XLAppProperties() = default;
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
void XLAppProperties::addSheetName(const std::string& title)
|
||||
{
|
||||
if (!m_xmlData) return;
|
||||
auto theNode = sheetNames(xmlDocument().document_element()).append_child("vt:lpstr");
|
||||
theNode.text().set(title.c_str());
|
||||
sheetCount(xmlDocument().document_element()).set_value(sheetCount(xmlDocument().document_element()).as_uint() + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
void XLAppProperties::deleteSheetName(const std::string& title)
|
||||
{
|
||||
if (!m_xmlData) return;
|
||||
for (auto& iter : sheetNames(xmlDocument().document_element()).children()) {
|
||||
if (iter.child_value() == title) {
|
||||
sheetNames(xmlDocument().document_element()).remove_child(iter);
|
||||
sheetCount(xmlDocument().document_element()).set_value(sheetCount(xmlDocument().document_element()).as_uint() - 1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
void XLAppProperties::setSheetName(const std::string& oldTitle, const std::string& newTitle)
|
||||
{
|
||||
if (!m_xmlData) return;
|
||||
for (auto& iter : sheetNames(xmlDocument().document_element())) {
|
||||
if (iter.child_value() == oldTitle) {
|
||||
iter.text().set(newTitle.c_str());
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
void XLAppProperties::addHeadingPair(const std::string& name, int value)
|
||||
{
|
||||
if (!m_xmlData) return;
|
||||
for (auto& item : headingPairsCategories(xmlDocument().document_element()).children()) {
|
||||
if (item.child_value() == name) return;
|
||||
}
|
||||
|
||||
auto pairCategory = headingPairsCategories(xmlDocument().document_element()).append_child("vt:lpstr");
|
||||
pairCategory.set_value(name.c_str());
|
||||
|
||||
auto pairCount = headingPairsCounts(xmlDocument().document_element()).append_child("vt:i4");
|
||||
pairCount.set_value(std::to_string(value).c_str());
|
||||
|
||||
headingPairsSize(xmlDocument().document_element())
|
||||
.set_value(std::distance(headingPairsCategories(xmlDocument().document_element()).begin(),
|
||||
headingPairsCategories(xmlDocument().document_element()).end()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
void XLAppProperties::deleteHeadingPair(const std::string& name)
|
||||
{
|
||||
if (!m_xmlData) return;
|
||||
auto category = headingPairsCategories(xmlDocument().document_element()).begin();
|
||||
auto count = headingPairsCounts(xmlDocument().document_element()).begin();
|
||||
while (category != headingPairsCategories(xmlDocument().document_element()).end() &&
|
||||
count != headingPairsCounts(xmlDocument().document_element()).end())
|
||||
{
|
||||
if (category->child_value() == name) {
|
||||
headingPairsCategories(xmlDocument().document_element()).remove_child(*category);
|
||||
headingPairsCounts(xmlDocument().document_element()).remove_child(*count);
|
||||
break;
|
||||
}
|
||||
++category;
|
||||
++count;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
void XLAppProperties::setHeadingPair(const std::string& name, int newValue)
|
||||
{
|
||||
if (!m_xmlData) return;
|
||||
auto category = headingPairsCategories(xmlDocument().document_element()).begin();
|
||||
auto count = headingPairsCounts(xmlDocument().document_element()).begin();
|
||||
while (category != headingPairsCategories(xmlDocument().document_element()).end() &&
|
||||
count != headingPairsCounts(xmlDocument().document_element()).end())
|
||||
{
|
||||
if (category->child_value() == name) {
|
||||
count->text().set(std::to_string(newValue).c_str());
|
||||
break;
|
||||
}
|
||||
++category;
|
||||
++count;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
void XLAppProperties::setProperty(const std::string& name, const std::string& value)
|
||||
{
|
||||
if (!m_xmlData) return;
|
||||
auto property = xmlDocument().first_child().child(name.c_str());
|
||||
if (!property) xmlDocument().first_child().append_child(name.c_str());
|
||||
property.text().set(value.c_str());
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
std::string XLAppProperties::property(const std::string& name) const
|
||||
{
|
||||
if (!m_xmlData) return "";
|
||||
auto property = xmlDocument().first_child().child(name.c_str());
|
||||
if (!property) xmlDocument().first_child().append_child(name.c_str());
|
||||
|
||||
return property.text().get();
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
void XLAppProperties::deleteProperty(const std::string& name)
|
||||
{
|
||||
if (!m_xmlData) return;
|
||||
auto property = xmlDocument().first_child().child(name.c_str());
|
||||
if (!property) return;
|
||||
|
||||
xmlDocument().first_child().remove_child(property);
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
void XLAppProperties::appendSheetName(const std::string& sheetName)
|
||||
{
|
||||
if (!m_xmlData) return;
|
||||
auto theNode = sheetNames(xmlDocument().document_element()).append_child("vt:lpstr");
|
||||
theNode.text().set(sheetName.c_str());
|
||||
sheetCount(xmlDocument().document_element()).set_value(sheetCount(xmlDocument().document_element()).as_uint() + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
void XLAppProperties::prependSheetName(const std::string& sheetName)
|
||||
{
|
||||
if (!m_xmlData) return;
|
||||
auto theNode = sheetNames(xmlDocument().document_element()).prepend_child("vt:lpstr");
|
||||
theNode.text().set(sheetName.c_str());
|
||||
sheetCount(xmlDocument().document_element()).set_value(sheetCount(xmlDocument().document_element()).as_uint() + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
void XLAppProperties::insertSheetName(const std::string& sheetName, unsigned int index)
|
||||
{
|
||||
if (!m_xmlData) return;
|
||||
if (index <= 1) {
|
||||
prependSheetName(sheetName);
|
||||
return;
|
||||
}
|
||||
|
||||
if (index > sheetCount(xmlDocument().document_element()).as_uint()) {
|
||||
appendSheetName(sheetName);
|
||||
return;
|
||||
}
|
||||
|
||||
auto curNode = sheetNames(xmlDocument().document_element()).first_child();
|
||||
unsigned idx = 1;
|
||||
while (curNode != nullptr) {
|
||||
if (idx == index) break;
|
||||
curNode = curNode.next_sibling();
|
||||
++idx;
|
||||
}
|
||||
|
||||
if (!curNode) {
|
||||
appendSheetName(sheetName);
|
||||
return;
|
||||
}
|
||||
|
||||
auto theNode = sheetNames(xmlDocument().document_element()).insert_child_before("vt:lpstr", curNode);
|
||||
theNode.text().set(sheetName.c_str());
|
||||
|
||||
sheetCount(xmlDocument().document_element()).set_value(sheetCount(xmlDocument().document_element()).as_uint() + 1);
|
||||
}
|
||||
+301
@@ -0,0 +1,301 @@
|
||||
/*
|
||||
|
||||
____ ____ ___ ____ ____ ____ ___
|
||||
6MMMMb `MM( )M' `MM' 6MMMMb\`MM( )M'
|
||||
8P Y8 `MM. d' MM 6M' ` `MM. d'
|
||||
6M Mb __ ____ ____ ___ __ `MM. d' MM MM `MM. d'
|
||||
MM MM `M6MMMMb 6MMMMb `MM 6MMb `MM. d' MM YM. `MM. d'
|
||||
MM MM MM' `Mb 6M' `Mb MMM9 `Mb `MMd MM YMMMMb `MMd
|
||||
MM MM MM MM MM MM MM' MM dMM. MM `Mb dMM.
|
||||
MM MM MM MM MMMMMMMM MM MM d'`MM. MM MM d'`MM.
|
||||
YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM.
|
||||
8b d8 MM. ,M9 YM d9 MM MM d' `MM. MM / L ,M9 d' `MM.
|
||||
YMMMM9 MMYMMM9 YMMMM9 _MM_ _MM_M(_ _)MM_ _MMMMMMM MYMMMM9 _M(_ _)MM_
|
||||
MM
|
||||
MM
|
||||
_MM_
|
||||
|
||||
Copyright (c) 2018, Kenneth Troldal Balslev
|
||||
|
||||
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.
|
||||
- Neither the name of the author nor the
|
||||
names of any 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 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.
|
||||
|
||||
*/
|
||||
|
||||
// ===== External Includes ===== //
|
||||
#include <algorithm>
|
||||
#include <pugixml.hpp>
|
||||
|
||||
// ===== OpenXLSX Includes ===== //
|
||||
#include "XLDocument.hpp"
|
||||
#include "XLRelationships.hpp"
|
||||
|
||||
using namespace OpenXLSX;
|
||||
|
||||
namespace
|
||||
{
|
||||
XLRelationshipType GetTypeFromString(const std::string& typeString)
|
||||
{
|
||||
XLRelationshipType type;
|
||||
|
||||
if (typeString == "http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties")
|
||||
type = XLRelationshipType::ExtendedProperties;
|
||||
else if (typeString == "http://schemas.openxmlformats.org/officeDocument/2006/relationships/custom-properties")
|
||||
type = XLRelationshipType::CustomProperties;
|
||||
else if (typeString == "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument")
|
||||
type = XLRelationshipType::Workbook;
|
||||
else if (typeString == "http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties")
|
||||
type = XLRelationshipType::CoreProperties;
|
||||
else if (typeString == "http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet")
|
||||
type = XLRelationshipType::Worksheet;
|
||||
else if (typeString == "http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles")
|
||||
type = XLRelationshipType::Styles;
|
||||
else if (typeString == "http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings")
|
||||
type = XLRelationshipType::SharedStrings;
|
||||
else if (typeString == "http://schemas.openxmlformats.org/officeDocument/2006/relationships/calcChain")
|
||||
type = XLRelationshipType::CalculationChain;
|
||||
else if (typeString == "http://schemas.microsoft.com/office/2006/relationships/vbaProject")
|
||||
type = XLRelationshipType::VBAProject;
|
||||
else if (typeString == "http://schemas.openxmlformats.org/officeDocument/2006/relationships/externalLink")
|
||||
type = XLRelationshipType::ExternalLink;
|
||||
else if (typeString == "http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme")
|
||||
type = XLRelationshipType::Theme;
|
||||
else if (typeString == "http://schemas.openxmlformats.org/officeDocument/2006/relationships/chartsheet")
|
||||
type = XLRelationshipType::Chartsheet;
|
||||
else if (typeString == "http://schemas.microsoft.com/office/2011/relationships/chartStyle")
|
||||
type = XLRelationshipType::ChartStyle;
|
||||
else if (typeString == "http://schemas.microsoft.com/office/2011/relationships/chartColorStyle")
|
||||
type = XLRelationshipType::ChartColorStyle;
|
||||
else if (typeString == "http://schemas.openxmlformats.org/officeDocument/2006/relationships/drawing")
|
||||
type = XLRelationshipType::Drawing;
|
||||
else if (typeString == "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image")
|
||||
type = XLRelationshipType::Image;
|
||||
else if (typeString == "http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart")
|
||||
type = XLRelationshipType::Chart;
|
||||
else if (typeString == "http://schemas.openxmlformats.org/officeDocument/2006/relationships/externalLinkPath")
|
||||
type = XLRelationshipType::ExternalLinkPath;
|
||||
else if (typeString == "http://schemas.openxmlformats.org/officeDocument/2006/relationships/printerSettings")
|
||||
type = XLRelationshipType::PrinterSettings;
|
||||
else if (typeString == "http://schemas.openxmlformats.org/officeDocument/2006/relationships/vmlDrawing")
|
||||
type = XLRelationshipType::VMLDrawing;
|
||||
else if (typeString == "http://schemas.openxmlformats.org/officeDocument/2006/relationships/ctrlProp")
|
||||
type = XLRelationshipType::ControlProperties;
|
||||
else
|
||||
type = XLRelationshipType::Unknown;
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
std::string GetStringFromType(XLRelationshipType type)
|
||||
{
|
||||
std::string typeString;
|
||||
|
||||
if (type == XLRelationshipType::ExtendedProperties)
|
||||
typeString = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties";
|
||||
else if (type == XLRelationshipType::CustomProperties)
|
||||
typeString = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/custom-properties";
|
||||
else if (type == XLRelationshipType::Workbook)
|
||||
typeString = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument";
|
||||
else if (type == XLRelationshipType::CoreProperties)
|
||||
typeString = "http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties";
|
||||
else if (type == XLRelationshipType::Worksheet)
|
||||
typeString = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet";
|
||||
else if (type == XLRelationshipType::Styles)
|
||||
typeString = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles";
|
||||
else if (type == XLRelationshipType::SharedStrings)
|
||||
typeString = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings";
|
||||
else if (type == XLRelationshipType::CalculationChain)
|
||||
typeString = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/calcChain";
|
||||
else if (type == XLRelationshipType::VBAProject)
|
||||
typeString = "http://schemas.microsoft.com/office/2006/relationships/vbaProject";
|
||||
else if (type == XLRelationshipType::ExternalLink)
|
||||
typeString = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/externalLink";
|
||||
else if (type == XLRelationshipType::Theme)
|
||||
typeString = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme";
|
||||
else if (type == XLRelationshipType::Chartsheet)
|
||||
typeString = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/chartsheet";
|
||||
else if (type == XLRelationshipType::ChartStyle)
|
||||
typeString = "http://schemas.microsoft.com/office/2011/relationships/chartStyle";
|
||||
else if (type == XLRelationshipType::ChartColorStyle)
|
||||
typeString = "http://schemas.microsoft.com/office/2011/relationships/chartColorStyle";
|
||||
else if (type == XLRelationshipType::Drawing)
|
||||
typeString = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/drawing";
|
||||
else if (type == XLRelationshipType::Image)
|
||||
typeString = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image";
|
||||
else if (type == XLRelationshipType::Chart)
|
||||
typeString = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart";
|
||||
else if (type == XLRelationshipType::ExternalLinkPath)
|
||||
typeString = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/externalLinkPath";
|
||||
else if (type == XLRelationshipType::PrinterSettings)
|
||||
typeString = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/printerSettings";
|
||||
else if (type == XLRelationshipType::VMLDrawing)
|
||||
typeString = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/vmlDrawing";
|
||||
else if (type == XLRelationshipType::ControlProperties)
|
||||
typeString = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/ctrlProp";
|
||||
else
|
||||
throw XLInternalError("RelationshipType not recognized!");
|
||||
|
||||
return typeString;
|
||||
}
|
||||
|
||||
uint32_t GetNewRelsID(XMLNode relationshipsNode)
|
||||
{
|
||||
return static_cast<uint32_t>(stoi(std::string(std::max_element(relationshipsNode.children().begin(),
|
||||
relationshipsNode.children().end(),
|
||||
[](XMLNode a, XMLNode b) {
|
||||
return stoi(std::string(a.attribute("Id").value()).substr(3)) <
|
||||
stoi(std::string(b.attribute("Id").value()).substr(3));
|
||||
})
|
||||
->attribute("Id")
|
||||
.value())
|
||||
.substr(3)) +
|
||||
1);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
XLRelationshipItem::XLRelationshipItem() : m_relationshipNode(std::make_unique<XMLNode>()) {}
|
||||
|
||||
/**
|
||||
* @details Constructor. Initializes the member variables for the new XLRelationshipItem object.
|
||||
*/
|
||||
XLRelationshipItem::XLRelationshipItem(const XMLNode& node) : m_relationshipNode(std::make_unique<XMLNode>(node)) {}
|
||||
|
||||
XLRelationshipItem::~XLRelationshipItem() = default;
|
||||
|
||||
XLRelationshipItem::XLRelationshipItem(const XLRelationshipItem& other)
|
||||
: m_relationshipNode(std::make_unique<XMLNode>(*other.m_relationshipNode))
|
||||
{}
|
||||
|
||||
XLRelationshipItem& XLRelationshipItem::operator=(const XLRelationshipItem& other)
|
||||
{
|
||||
if (&other != this) *m_relationshipNode = *other.m_relationshipNode;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @details Returns the m_relationshipType member variable by getValue.
|
||||
*/
|
||||
XLRelationshipType XLRelationshipItem::type() const
|
||||
{
|
||||
return GetTypeFromString(m_relationshipNode->attribute("Type").value());
|
||||
}
|
||||
|
||||
/**
|
||||
* @details Returns the m_relationshipTarget member variable by getValue.
|
||||
*/
|
||||
std::string XLRelationshipItem::target() const
|
||||
{
|
||||
return m_relationshipNode->attribute("Target").value();
|
||||
}
|
||||
|
||||
/**
|
||||
* @details Returns the m_relationshipId member variable by getValue.
|
||||
*/
|
||||
std::string XLRelationshipItem::id() const
|
||||
{
|
||||
return m_relationshipNode->attribute("Id").value();
|
||||
}
|
||||
|
||||
/**
|
||||
* @details Creates a XLRelationships object, which will read the XML file with the given path
|
||||
*/
|
||||
XLRelationships::XLRelationships(XLXmlData* xmlData) : XLXmlFile(xmlData) {}
|
||||
|
||||
XLRelationships::~XLRelationships() = default;
|
||||
|
||||
/**
|
||||
* @details Returns the XLRelationshipItem with the given ID, by looking it up in the m_relationships map.
|
||||
*/
|
||||
XLRelationshipItem XLRelationships::relationshipById(const std::string& id) const
|
||||
{
|
||||
return XLRelationshipItem(xmlDocument().document_element().find_child_by_attribute("Id", id.c_str()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @details Returns the XLRelationshipItem with the requested target, by iterating through the items.
|
||||
*/
|
||||
XLRelationshipItem XLRelationships::relationshipByTarget(const std::string& target) const
|
||||
{
|
||||
return XLRelationshipItem(xmlDocument().document_element().find_child_by_attribute("Target", target.c_str()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @details Returns a const reference to the internal datastructure (std::map)
|
||||
*/
|
||||
std::vector<XLRelationshipItem> XLRelationships::relationships() const
|
||||
{
|
||||
auto result = std::vector<XLRelationshipItem>();
|
||||
for (const auto& item : xmlDocument().document_element().children()) result.emplace_back(XLRelationshipItem(item));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void XLRelationships::deleteRelationship(const std::string& relID)
|
||||
{
|
||||
xmlDocument().document_element().remove_child(xmlDocument().document_element().find_child_by_attribute("Id", relID.c_str()));
|
||||
}
|
||||
|
||||
void XLRelationships::deleteRelationship(const XLRelationshipItem& item)
|
||||
{
|
||||
deleteRelationship(item.id());
|
||||
}
|
||||
|
||||
/**
|
||||
* @details Adds a new relationship by creating new XML node in the .rels file and creating a new XLRelationshipItem
|
||||
* based on the newly created node.
|
||||
*/
|
||||
XLRelationshipItem XLRelationships::addRelationship(XLRelationshipType type, const std::string& target)
|
||||
{
|
||||
std::string typeString = GetStringFromType(type);
|
||||
|
||||
std::string id = "rId" + std::to_string(GetNewRelsID(xmlDocument().document_element()));
|
||||
|
||||
// Create new node in the .rels file
|
||||
auto node = xmlDocument().document_element().append_child("Relationship");
|
||||
node.append_attribute("Id").set_value(id.c_str());
|
||||
node.append_attribute("Type").set_value(typeString.c_str());
|
||||
node.append_attribute("Target").set_value(target.c_str());
|
||||
|
||||
if (type == XLRelationshipType::ExternalLinkPath) {
|
||||
node.append_attribute("TargetMode").set_value("External");
|
||||
}
|
||||
|
||||
return XLRelationshipItem(node);
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
bool XLRelationships::targetExists(const std::string& target) const
|
||||
{
|
||||
return xmlDocument().document_element().find_child_by_attribute("Target", target.c_str()) != nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
bool XLRelationships::idExists(const std::string& id) const
|
||||
{
|
||||
return xmlDocument().document_element().find_child_by_attribute("Id", id.c_str()) != nullptr;
|
||||
}
|
||||
Vendored
+558
@@ -0,0 +1,558 @@
|
||||
/*
|
||||
|
||||
____ ____ ___ ____ ____ ____ ___
|
||||
6MMMMb `MM( )M' `MM' 6MMMMb\`MM( )M'
|
||||
8P Y8 `MM. d' MM 6M' ` `MM. d'
|
||||
6M Mb __ ____ ____ ___ __ `MM. d' MM MM `MM. d'
|
||||
MM MM `M6MMMMb 6MMMMb `MM 6MMb `MM. d' MM YM. `MM. d'
|
||||
MM MM MM' `Mb 6M' `Mb MMM9 `Mb `MMd MM YMMMMb `MMd
|
||||
MM MM MM MM MM MM MM' MM dMM. MM `Mb dMM.
|
||||
MM MM MM MM MMMMMMMM MM MM d'`MM. MM MM d'`MM.
|
||||
YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM.
|
||||
8b d8 MM. ,M9 YM d9 MM MM d' `MM. MM / L ,M9 d' `MM.
|
||||
YMMMM9 MMYMMM9 YMMMM9 _MM_ _MM_M(_ _)MM_ _MMMMMMM MYMMMM9 _M(_ _)MM_
|
||||
MM
|
||||
MM
|
||||
_MM_
|
||||
|
||||
Copyright (c) 2018, Kenneth Troldal Balslev
|
||||
|
||||
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.
|
||||
- Neither the name of the author nor the
|
||||
names of any 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 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.
|
||||
|
||||
*/
|
||||
|
||||
// ===== External Includes ===== //
|
||||
#include <pugixml.hpp>
|
||||
|
||||
// ===== OpenXLSX Includes ===== //
|
||||
#include "XLCell.hpp"
|
||||
#include "XLCellReference.hpp"
|
||||
#include "XLRow.hpp"
|
||||
|
||||
#include "utilities/XLUtilities.hpp"
|
||||
|
||||
// ========== XLRow ======================================================== //
|
||||
namespace OpenXLSX
|
||||
{
|
||||
/**
|
||||
* @details
|
||||
* @pre
|
||||
* @post
|
||||
*/
|
||||
XLRow::XLRow() : m_rowNode(nullptr),
|
||||
m_rowDataProxy(this, m_rowNode.get()) {}
|
||||
|
||||
/**
|
||||
* @details Constructs a new XLRow object from information in the underlying XML file. A pointer to the corresponding
|
||||
* node in the underlying XML file must be provided.
|
||||
* @pre
|
||||
* @post
|
||||
*/
|
||||
XLRow::XLRow(const XMLNode& rowNode, const XLSharedStrings& sharedStrings)
|
||||
: m_rowNode(std::make_unique<XMLNode>(rowNode)),
|
||||
m_sharedStrings(sharedStrings),
|
||||
m_rowDataProxy(this, m_rowNode.get())
|
||||
{}
|
||||
|
||||
/**
|
||||
* @details
|
||||
* @pre
|
||||
* @post
|
||||
*/
|
||||
XLRow::XLRow(const XLRow& other)
|
||||
: m_rowNode(other.m_rowNode ? std::make_unique<XMLNode>(*other.m_rowNode) : nullptr),
|
||||
m_sharedStrings(other.m_sharedStrings),
|
||||
m_rowDataProxy(this, m_rowNode.get())
|
||||
{}
|
||||
|
||||
/**
|
||||
* @details Because the m_rowDataProxy variable is tied to an exact XLRow object, the move operation is
|
||||
* not a 'pure' move, as a new XLRowDataProxy has to be constructed.
|
||||
* @pre
|
||||
* @post
|
||||
*/
|
||||
XLRow::XLRow(XLRow&& other) noexcept
|
||||
: m_rowNode(std::move(other.m_rowNode)),
|
||||
m_sharedStrings(std::move(other.m_sharedStrings)),
|
||||
m_rowDataProxy(this, m_rowNode.get())
|
||||
{}
|
||||
|
||||
/**
|
||||
* @details
|
||||
* @pre
|
||||
* @post
|
||||
*/
|
||||
XLRow::~XLRow() = default;
|
||||
|
||||
/**
|
||||
* @details
|
||||
* @pre
|
||||
* @post
|
||||
*/
|
||||
XLRow& XLRow::operator=(const XLRow& other)
|
||||
{
|
||||
if (&other != this) {
|
||||
auto temp = XLRow(other);
|
||||
std::swap(*this, temp);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @details Because the m_rowDataProxy variable is tied to an exact XLRow object, the move operation is
|
||||
* not a 'pure' move, as a new XLRowDataProxy has to be constructed.
|
||||
* @pre
|
||||
* @post
|
||||
*/
|
||||
XLRow& XLRow::operator=(XLRow&& other) noexcept
|
||||
{
|
||||
if (&other != this) {
|
||||
m_rowNode = std::move(other.m_rowNode);
|
||||
m_sharedStrings = other.m_sharedStrings;
|
||||
m_rowDataProxy = XLRowDataProxy(this, m_rowNode.get());
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @details Returns the m_height member by getValue.
|
||||
* @pre
|
||||
* @post
|
||||
*/
|
||||
double XLRow::height() const
|
||||
{
|
||||
return m_rowNode->attribute("ht").as_double(15.0); // NOLINT
|
||||
}
|
||||
|
||||
/**
|
||||
* @details Set the height of the row. This is done by setting the getValue of the 'ht' attribute and setting the
|
||||
* 'customHeight' attribute to true.
|
||||
* @pre
|
||||
* @post
|
||||
*/
|
||||
void XLRow::setHeight(float height)
|
||||
{
|
||||
// Set the 'ht' attribute for the Cell. If it does not exist, create it.
|
||||
if (!m_rowNode->attribute("ht"))
|
||||
m_rowNode->append_attribute("ht") = height;
|
||||
else
|
||||
m_rowNode->attribute("ht").set_value(height);
|
||||
|
||||
// Set the 'customHeight' attribute. If it does not exist, create it.
|
||||
if (!m_rowNode->attribute("customHeight"))
|
||||
m_rowNode->append_attribute("customHeight") = 1;
|
||||
else
|
||||
m_rowNode->attribute("customHeight").set_value(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @details Return the m_descent member by getValue.
|
||||
* @pre
|
||||
* @post
|
||||
*/
|
||||
float XLRow::descent() const
|
||||
{
|
||||
return m_rowNode->attribute("x14ac:dyDescent").as_float(0.25); // NOLINT
|
||||
}
|
||||
|
||||
/**
|
||||
* @details Set the descent by setting the 'x14ac:dyDescent' attribute in the XML file
|
||||
* @pre
|
||||
* @post
|
||||
*/
|
||||
void XLRow::setDescent(float descent)
|
||||
{
|
||||
// Set the 'x14ac:dyDescent' attribute. If it does not exist, create it.
|
||||
if (!m_rowNode->attribute("x14ac:dyDescent"))
|
||||
m_rowNode->append_attribute("x14ac:dyDescent") = descent;
|
||||
else
|
||||
m_rowNode->attribute("x14ac:dyDescent") = descent;
|
||||
}
|
||||
|
||||
/**
|
||||
* @details Determine if the row is hidden or not.
|
||||
* @pre
|
||||
* @post
|
||||
*/
|
||||
bool XLRow::isHidden() const
|
||||
{
|
||||
return m_rowNode->attribute("hidden").as_bool(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @details Set the hidden state by setting the 'hidden' attribute to true or false.
|
||||
* @pre
|
||||
* @post
|
||||
*/
|
||||
void XLRow::setHidden(bool state)
|
||||
{
|
||||
// Set the 'hidden' attribute. If it does not exist, create it.
|
||||
if (!m_rowNode->attribute("hidden"))
|
||||
m_rowNode->append_attribute("hidden") = static_cast<int>(state);
|
||||
else
|
||||
m_rowNode->attribute("hidden").set_value(static_cast<int>(state));
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
* @pre
|
||||
* @post
|
||||
*/
|
||||
uint64_t XLRow::rowNumber() const
|
||||
{
|
||||
return m_rowNode->attribute("r").as_ullong();
|
||||
}
|
||||
|
||||
/**
|
||||
* @details Get the number of cells in the row, by returning the size of the m_cells vector.
|
||||
* @pre
|
||||
* @post
|
||||
*/
|
||||
unsigned int XLRow::cellCount() const
|
||||
{
|
||||
if (!m_rowNode->last_child())
|
||||
return 0;
|
||||
return XLCellReference(m_rowNode->last_child().attribute("r").value()).column();
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
* @pre
|
||||
* @post
|
||||
*/
|
||||
XLRowDataProxy& XLRow::values()
|
||||
{
|
||||
return m_rowDataProxy;
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
* @pre
|
||||
* @post
|
||||
*/
|
||||
const XLRowDataProxy& XLRow::values() const
|
||||
{
|
||||
return m_rowDataProxy;
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
* @pre
|
||||
* @post
|
||||
*/
|
||||
XLRowDataRange XLRow::cells() const
|
||||
{
|
||||
return XLRowDataRange(*m_rowNode, 1, XLCellReference(m_rowNode->last_child().attribute("r").value()).column(), m_sharedStrings);
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
* @pre
|
||||
* @post
|
||||
*/
|
||||
XLRowDataRange XLRow::cells(uint16_t cellCount) const
|
||||
{
|
||||
return XLRowDataRange(*m_rowNode, 1, cellCount, m_sharedStrings);
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
* @pre
|
||||
* @post
|
||||
*/
|
||||
XLRowDataRange XLRow::cells(uint16_t firstCell, uint16_t lastCell) const
|
||||
{
|
||||
return XLRowDataRange(*m_rowNode, firstCell, lastCell, m_sharedStrings);
|
||||
}
|
||||
|
||||
bool XLRow::isEqual(const XLRow& lhs, const XLRow& rhs)
|
||||
{
|
||||
if (lhs.m_rowNode && !rhs.m_rowNode)
|
||||
return false;
|
||||
if (!lhs.m_rowNode && !rhs.m_rowNode)
|
||||
return true;
|
||||
return *lhs.m_rowNode == *rhs.m_rowNode;
|
||||
}
|
||||
|
||||
bool XLRow::isLessThan(const XLRow& lhs, const XLRow& rhs)
|
||||
{
|
||||
return *lhs.m_rowNode < *rhs.m_rowNode;
|
||||
}
|
||||
|
||||
} // namespace OpenXLSX
|
||||
|
||||
// ========== XLRowIterator ================================================ //
|
||||
namespace OpenXLSX
|
||||
{
|
||||
/**
|
||||
* @details
|
||||
* @pre
|
||||
* @post
|
||||
*/
|
||||
XLRowIterator::XLRowIterator(const XLRowRange& rowRange, XLIteratorLocation loc)
|
||||
: m_dataNode(std::make_unique<XMLNode>(*rowRange.m_dataNode)),
|
||||
m_firstRow(rowRange.m_firstRow),
|
||||
m_lastRow(rowRange.m_lastRow),
|
||||
m_sharedStrings(rowRange.m_sharedStrings)
|
||||
{
|
||||
if (loc == XLIteratorLocation::End)
|
||||
m_currentRow = XLRow();
|
||||
else {
|
||||
m_currentRow = XLRow(getRowNode(*m_dataNode, m_firstRow), m_sharedStrings);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
* @pre
|
||||
* @post
|
||||
*/
|
||||
XLRowIterator::~XLRowIterator() = default;
|
||||
|
||||
/**
|
||||
* @details
|
||||
* @pre
|
||||
* @post
|
||||
*/
|
||||
XLRowIterator::XLRowIterator(const XLRowIterator& other)
|
||||
: m_dataNode(std::make_unique<XMLNode>(*other.m_dataNode)),
|
||||
m_firstRow(other.m_firstRow),
|
||||
m_lastRow(other.m_lastRow),
|
||||
m_currentRow(other.m_currentRow),
|
||||
m_sharedStrings(other.m_sharedStrings)
|
||||
{}
|
||||
|
||||
/**
|
||||
* @details
|
||||
* @pre
|
||||
* @post
|
||||
*/
|
||||
XLRowIterator::XLRowIterator(XLRowIterator&& other) noexcept = default;
|
||||
|
||||
/**
|
||||
* @details
|
||||
* @pre
|
||||
* @post
|
||||
*/
|
||||
XLRowIterator& XLRowIterator::operator=(const XLRowIterator& other)
|
||||
{
|
||||
if (&other != this) {
|
||||
auto temp = XLRowIterator(other);
|
||||
std::swap(*this, temp);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
* @pre
|
||||
* @post
|
||||
*/
|
||||
XLRowIterator& XLRowIterator::operator=(XLRowIterator&& other) noexcept = default;
|
||||
|
||||
/**
|
||||
* @details
|
||||
* @pre
|
||||
* @post
|
||||
*/
|
||||
XLRowIterator& XLRowIterator::operator++()
|
||||
{
|
||||
auto rowNumber = m_currentRow.rowNumber() + 1;
|
||||
auto rowNode = m_currentRow.m_rowNode->next_sibling();
|
||||
|
||||
if (rowNumber > m_lastRow)
|
||||
m_currentRow = XLRow();
|
||||
|
||||
else if (!rowNode || rowNode.attribute("r").as_ullong() != rowNumber) {
|
||||
rowNode = m_dataNode->insert_child_after("row", *m_currentRow.m_rowNode);
|
||||
rowNode.append_attribute("r").set_value(rowNumber);
|
||||
m_currentRow = XLRow(rowNode, m_sharedStrings);
|
||||
}
|
||||
|
||||
else
|
||||
m_currentRow = XLRow(rowNode, m_sharedStrings);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
* @pre
|
||||
* @post
|
||||
*/
|
||||
XLRowIterator XLRowIterator::operator++(int) // NOLINT
|
||||
{
|
||||
auto oldIter(*this);
|
||||
++(*this);
|
||||
return oldIter;
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
* @pre
|
||||
* @post
|
||||
*/
|
||||
XLRow& XLRowIterator::operator*()
|
||||
{
|
||||
return m_currentRow;
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
* @pre
|
||||
* @post
|
||||
*/
|
||||
XLRowIterator::pointer XLRowIterator::operator->()
|
||||
{
|
||||
return &m_currentRow;
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
* @pre
|
||||
* @post
|
||||
*/
|
||||
bool XLRowIterator::operator==(const XLRowIterator& rhs) const
|
||||
{
|
||||
return m_currentRow == rhs.m_currentRow;
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
* @pre
|
||||
* @post
|
||||
*/
|
||||
bool XLRowIterator::operator!=(const XLRowIterator& rhs) const
|
||||
{
|
||||
return !(m_currentRow == rhs.m_currentRow);
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
* @pre
|
||||
* @post
|
||||
*/
|
||||
XLRowIterator::operator bool() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace OpenXLSX
|
||||
|
||||
// ========== XLRowRange =================================================== //
|
||||
namespace OpenXLSX
|
||||
{
|
||||
/**
|
||||
* @details
|
||||
* @pre
|
||||
* @post
|
||||
*/
|
||||
XLRowRange::XLRowRange(const XMLNode& dataNode, uint32_t first, uint32_t last, const OpenXLSX::XLSharedStrings& sharedStrings)
|
||||
: m_dataNode(std::make_unique<XMLNode>(dataNode)),
|
||||
m_firstRow(first),
|
||||
m_lastRow(last),
|
||||
m_sharedStrings(sharedStrings)
|
||||
{}
|
||||
|
||||
/**
|
||||
* @details
|
||||
* @pre
|
||||
* @post
|
||||
*/
|
||||
XLRowRange::XLRowRange(const XLRowRange& other)
|
||||
: m_dataNode(std::make_unique<XMLNode>(*other.m_dataNode)),
|
||||
m_firstRow(other.m_firstRow),
|
||||
m_lastRow(other.m_lastRow),
|
||||
m_sharedStrings(other.m_sharedStrings)
|
||||
{}
|
||||
|
||||
/**
|
||||
* @details
|
||||
* @pre
|
||||
* @post
|
||||
*/
|
||||
XLRowRange::XLRowRange(XLRowRange&& other) noexcept = default;
|
||||
|
||||
/**
|
||||
* @details
|
||||
* @pre
|
||||
* @post
|
||||
*/
|
||||
XLRowRange::~XLRowRange() = default;
|
||||
|
||||
/**
|
||||
* @details
|
||||
* @pre
|
||||
* @post
|
||||
*/
|
||||
XLRowRange& XLRowRange::operator=(const XLRowRange& other)
|
||||
{
|
||||
if (&other != this) {
|
||||
auto temp = XLRowRange(other);
|
||||
std::swap(*this, temp);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
* @pre
|
||||
* @post
|
||||
*/
|
||||
XLRowRange& XLRowRange::operator=(XLRowRange&& other) noexcept = default;
|
||||
|
||||
/**
|
||||
* @details
|
||||
* @pre
|
||||
* @post
|
||||
*/
|
||||
uint32_t XLRowRange::rowCount() const
|
||||
{
|
||||
return m_lastRow - m_firstRow + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
* @pre
|
||||
* @post
|
||||
*/
|
||||
XLRowIterator XLRowRange::begin()
|
||||
{
|
||||
return XLRowIterator(*this, XLIteratorLocation::Begin);
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
* @pre
|
||||
* @post
|
||||
*/
|
||||
XLRowIterator XLRowRange::end()
|
||||
{
|
||||
return XLRowIterator(*this, XLIteratorLocation::End);
|
||||
}
|
||||
|
||||
} // namespace OpenXLSX
|
||||
Vendored
+533
@@ -0,0 +1,533 @@
|
||||
/*
|
||||
|
||||
____ ____ ___ ____ ____ ____ ___
|
||||
6MMMMb `MM( )M' `MM' 6MMMMb\`MM( )M'
|
||||
8P Y8 `MM. d' MM 6M' ` `MM. d'
|
||||
6M Mb __ ____ ____ ___ __ `MM. d' MM MM `MM. d'
|
||||
MM MM `M6MMMMb 6MMMMb `MM 6MMb `MM. d' MM YM. `MM. d'
|
||||
MM MM MM' `Mb 6M' `Mb MMM9 `Mb `MMd MM YMMMMb `MMd
|
||||
MM MM MM MM MM MM MM' MM dMM. MM `Mb dMM.
|
||||
MM MM MM MM MMMMMMMM MM MM d'`MM. MM MM d'`MM.
|
||||
YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM.
|
||||
8b d8 MM. ,M9 YM d9 MM MM d' `MM. MM / L ,M9 d' `MM.
|
||||
YMMMM9 MMYMMM9 YMMMM9 _MM_ _MM_M(_ _)MM_ _MMMMMMM MYMMMM9 _M(_ _)MM_
|
||||
MM
|
||||
MM
|
||||
_MM_
|
||||
|
||||
Copyright (c) 2018, Kenneth Troldal Balslev
|
||||
|
||||
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.
|
||||
- Neither the name of the author nor the
|
||||
names of any 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 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.
|
||||
|
||||
*/
|
||||
|
||||
// ===== External Includes ===== //
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
|
||||
// ===== OpenXLSX Includes ===== //
|
||||
#include "XLCell.hpp"
|
||||
#include "XLRow.hpp"
|
||||
#include "XLRowData.hpp"
|
||||
#include "utilities/XLUtilities.hpp"
|
||||
|
||||
// ========== XLRowDataIterator ============================================ //
|
||||
namespace OpenXLSX
|
||||
{
|
||||
/**
|
||||
* @details Constructor.
|
||||
* @pre The given range and location are both valid.
|
||||
* @post
|
||||
*/
|
||||
XLRowDataIterator::XLRowDataIterator(const XLRowDataRange& rowDataRange, XLIteratorLocation loc)
|
||||
: m_dataRange(std::make_unique<XLRowDataRange>(rowDataRange)),
|
||||
m_cellNode(std::make_unique<XMLNode>(getCellNode(*m_dataRange->m_rowNode, m_dataRange->m_firstCol))),
|
||||
m_currentCell(loc == XLIteratorLocation::End ? XLCell() : XLCell(*m_cellNode, m_dataRange->m_sharedStrings))
|
||||
{}
|
||||
|
||||
/**
|
||||
* @details Destructor. Default implementation.
|
||||
* @pre
|
||||
* @post
|
||||
*/
|
||||
XLRowDataIterator::~XLRowDataIterator() = default;
|
||||
|
||||
/**
|
||||
* @details Copy constructor. Trivial implementation with deep copy of pointer members.
|
||||
* @pre
|
||||
* @post
|
||||
*/
|
||||
XLRowDataIterator::XLRowDataIterator(const XLRowDataIterator& other)
|
||||
: m_dataRange(std::make_unique<XLRowDataRange>(*other.m_dataRange)),
|
||||
m_cellNode(std::make_unique<XMLNode>(*other.m_cellNode)),
|
||||
m_currentCell(other.m_currentCell)
|
||||
{}
|
||||
|
||||
/**
|
||||
* @details Move constructor. Default implementation.
|
||||
* @pre
|
||||
* @post
|
||||
*/
|
||||
XLRowDataIterator::XLRowDataIterator(XLRowDataIterator&& other) noexcept = default; // NOLINT
|
||||
|
||||
/**
|
||||
* @details Copy assignment operator. Implemented using copy-and-swap idiom.
|
||||
* @pre
|
||||
* @post
|
||||
*/
|
||||
XLRowDataIterator& XLRowDataIterator::operator=(const XLRowDataIterator& other)
|
||||
{
|
||||
if (&other != this) {
|
||||
XLRowDataIterator temp = other;
|
||||
std::swap(temp, *this);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @details Move assignment operator. Default implementation.
|
||||
* @pre
|
||||
* @post
|
||||
*/
|
||||
XLRowDataIterator& XLRowDataIterator::operator=(XLRowDataIterator&& other) noexcept = default;
|
||||
|
||||
/**
|
||||
* @details Pre-increment operator. Advances the iterator one element.
|
||||
* @pre
|
||||
* @post
|
||||
*/
|
||||
XLRowDataIterator& XLRowDataIterator::operator++()
|
||||
{
|
||||
// ===== Compute the column number, and move the m_cellNode to the next sibling.
|
||||
auto cellNumber = m_currentCell.cellReference().column() + 1;
|
||||
auto cellNode = m_currentCell.m_cellNode->next_sibling();
|
||||
|
||||
// ===== If the cellNumber exceeds the last column in the range has been reached, and the m_currentCell
|
||||
// ===== is set to an empty XLCell, indicating the end of the range has been reached.
|
||||
if (cellNumber > m_dataRange->m_lastCol) m_currentCell = XLCell();
|
||||
|
||||
// ====== If the m_cellNode is null (i.e. no more children in the current row node) or the column number of the cell node
|
||||
// ====== is higher than the computed column number, then insert the node.
|
||||
// TODO: When checking for > cellNumber rather than != cellNumber, m_cellNode->empty() fails. Why?
|
||||
// TODO: Apparently only fails when assigning containers with POD values, rather XLCellValues.
|
||||
// else if (m_cellNode->empty() || XLCellReference(cellNode.attribute("r").value()).column() > cellNumber) {
|
||||
else if (m_cellNode->empty() || XLCellReference(cellNode.attribute("r").value()).column() != cellNumber) {
|
||||
cellNode = m_dataRange->m_rowNode->insert_child_after("c", *m_currentCell.m_cellNode);
|
||||
cellNode.append_attribute("r").set_value(
|
||||
XLCellReference(
|
||||
static_cast<uint32_t>(m_dataRange->m_rowNode->attribute("r").as_ullong()),
|
||||
static_cast<uint16_t>(cellNumber)).address().c_str());
|
||||
m_currentCell = XLCell(cellNode, m_dataRange->m_sharedStrings);
|
||||
}
|
||||
|
||||
// ===== Otherwise, the cell node and the column number match.
|
||||
else {
|
||||
assert(XLCellReference(cellNode.attribute("r").value()).column() == cellNumber);
|
||||
m_currentCell = XLCell(cellNode, m_dataRange->m_sharedStrings);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @details Post-increment operator. Implemented in terms of the pre-increment operator.
|
||||
* @pre
|
||||
* @post
|
||||
*/
|
||||
XLRowDataIterator XLRowDataIterator::operator++(int) // NOLINT
|
||||
{
|
||||
auto oldIter(*this);
|
||||
++(*this);
|
||||
return oldIter;
|
||||
}
|
||||
|
||||
/**
|
||||
* @details Dereferencing operator.
|
||||
* @pre
|
||||
* @post
|
||||
*/
|
||||
XLCell& XLRowDataIterator::operator*()
|
||||
{
|
||||
return m_currentCell;
|
||||
}
|
||||
|
||||
/**
|
||||
* @details Arrow operator.
|
||||
* @pre
|
||||
* @post
|
||||
*/
|
||||
XLRowDataIterator::pointer XLRowDataIterator::operator->()
|
||||
{
|
||||
return &m_currentCell;
|
||||
}
|
||||
|
||||
/**
|
||||
* @details Equality comparison operator.
|
||||
* @pre
|
||||
* @post
|
||||
*/
|
||||
bool XLRowDataIterator::operator==(const XLRowDataIterator& rhs) const
|
||||
{
|
||||
if (m_currentCell && !rhs.m_currentCell)
|
||||
return false;
|
||||
if (!m_currentCell && !rhs.m_currentCell)
|
||||
return true;
|
||||
return m_currentCell == rhs.m_currentCell;
|
||||
}
|
||||
|
||||
/**
|
||||
* @details Non-equality comparison operator.
|
||||
* @pre
|
||||
* @post
|
||||
*/
|
||||
bool XLRowDataIterator::operator!=(const XLRowDataIterator& rhs) const
|
||||
{
|
||||
return !(*this == rhs);
|
||||
}
|
||||
|
||||
} // namespace OpenXLSX
|
||||
|
||||
// ========== XLRowDataRange =============================================== //
|
||||
namespace OpenXLSX
|
||||
{
|
||||
/**
|
||||
* @details Constructor. Trivial implementation.
|
||||
* @throws If firstColumn > than lastColumn, an XLOverflowError will be thrown.
|
||||
* @pre
|
||||
* @post
|
||||
*/
|
||||
XLRowDataRange::XLRowDataRange(const XMLNode& rowNode, uint16_t firstColumn, uint16_t lastColumn, const XLSharedStrings& sharedStrings)
|
||||
: m_rowNode(std::make_unique<XMLNode>(rowNode)),
|
||||
m_firstCol(firstColumn),
|
||||
m_lastCol(lastColumn),
|
||||
m_sharedStrings(sharedStrings)
|
||||
{
|
||||
if (lastColumn < firstColumn) {
|
||||
m_firstCol = 1;
|
||||
m_lastCol = 1;
|
||||
throw XLOverflowError("lastColumn is less than firstColumn.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @details Copy constructor. Trivial implementation.
|
||||
* @pre
|
||||
* @post
|
||||
*/
|
||||
XLRowDataRange::XLRowDataRange(const XLRowDataRange& other)
|
||||
: m_rowNode(std::make_unique<XMLNode>(*other.m_rowNode)),
|
||||
m_firstCol(other.m_firstCol),
|
||||
m_lastCol(other.m_lastCol),
|
||||
m_sharedStrings(other.m_sharedStrings)
|
||||
|
||||
{}
|
||||
|
||||
/**
|
||||
* @details Move constructor. Default implementation.
|
||||
* @pre
|
||||
* @post
|
||||
*/
|
||||
XLRowDataRange::XLRowDataRange(XLRowDataRange&& other) noexcept = default;
|
||||
|
||||
/**
|
||||
* @details Destructor. Default implementation.
|
||||
* @pre
|
||||
* @post
|
||||
*/
|
||||
XLRowDataRange::~XLRowDataRange() = default;
|
||||
|
||||
/**
|
||||
* @details Copy assignment operator. Implemented in terms of copy-and-swap.
|
||||
* @pre
|
||||
* @post
|
||||
*/
|
||||
XLRowDataRange& XLRowDataRange::operator=(const XLRowDataRange& other)
|
||||
{
|
||||
if (&other != this) {
|
||||
XLRowDataRange temp(other);
|
||||
std::swap(temp, *this);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @details Move assignment operator. Default implementation.
|
||||
* @pre
|
||||
* @post
|
||||
*/
|
||||
XLRowDataRange& XLRowDataRange::operator=(XLRowDataRange&& other) noexcept = default;
|
||||
|
||||
/**
|
||||
* @details Calculates the size (number of cells) in the range.
|
||||
* @pre
|
||||
* @post
|
||||
*/
|
||||
uint16_t XLRowDataRange::size() const
|
||||
{
|
||||
return m_lastCol - m_firstCol + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @details Get an iterator to the first cell in the range.
|
||||
* @pre
|
||||
* @post
|
||||
*/
|
||||
XLRowDataIterator XLRowDataRange::begin()
|
||||
{
|
||||
return XLRowDataIterator { *this, XLIteratorLocation::Begin };
|
||||
}
|
||||
|
||||
/**
|
||||
* @details Get an iterator to (one past) the last cell in the range.
|
||||
* @pre
|
||||
* @post
|
||||
*/
|
||||
XLRowDataIterator XLRowDataRange::end()
|
||||
{
|
||||
return XLRowDataIterator { *this, XLIteratorLocation::End };
|
||||
}
|
||||
|
||||
} // namespace OpenXLSX
|
||||
|
||||
// ========== XLRowDataProxy =============================================== //
|
||||
namespace OpenXLSX
|
||||
{
|
||||
/**
|
||||
* @details Destructor. Default implementation.
|
||||
* @pre
|
||||
* @post
|
||||
*/
|
||||
XLRowDataProxy::~XLRowDataProxy() = default;
|
||||
|
||||
/**
|
||||
* @details Copy constructor. This is not a 'true' copy constructor, as it is the row values that will
|
||||
* be copied, not the XLRowDataProxy member variables (pointers to the XLRow and row node objects).
|
||||
* @pre
|
||||
* @post
|
||||
*/
|
||||
XLRowDataProxy& XLRowDataProxy::operator=(const XLRowDataProxy& other)
|
||||
{
|
||||
if (&other != this) {
|
||||
*this = other.getValues();
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @details Constructor
|
||||
* @pre
|
||||
* @post
|
||||
*/
|
||||
XLRowDataProxy::XLRowDataProxy(XLRow* row, XMLNode* rowNode) : m_row(row), m_rowNode(rowNode) {}
|
||||
|
||||
/**
|
||||
* @details Copy constructor. Default implementation.
|
||||
* @pre
|
||||
* @post
|
||||
*/
|
||||
XLRowDataProxy::XLRowDataProxy(const XLRowDataProxy& other) = default;
|
||||
|
||||
/**
|
||||
* @details Move constructor. Default implementation.
|
||||
* @pre
|
||||
* @post
|
||||
*/
|
||||
XLRowDataProxy::XLRowDataProxy(XLRowDataProxy&& other) noexcept = default;
|
||||
|
||||
/**
|
||||
* @details Move assignment operator. Default implementation.
|
||||
* @pre
|
||||
* @post
|
||||
*/
|
||||
XLRowDataProxy& XLRowDataProxy::operator=(XLRowDataProxy&& other) noexcept = default;
|
||||
|
||||
/**
|
||||
* @details Assignment operator taking a std::vector of XLCellValue objects as an argument. Other container types
|
||||
* and/or value types will be handled by the templated operator=. However, because assigning a std::vector of
|
||||
* XLCellValue object is the most common case, this case is handled separately fo higher performance.
|
||||
* @pre
|
||||
* @post
|
||||
*/
|
||||
XLRowDataProxy& XLRowDataProxy::operator=(const std::vector<XLCellValue>& values)
|
||||
{
|
||||
// ===== Mark cell nodes for deletion
|
||||
std::vector<XMLNode> toBeDeleted;
|
||||
for (auto cellNode : m_rowNode->children()) {
|
||||
if (XLCellReference(cellNode.attribute("r").value()).column() <= values.size()) toBeDeleted.emplace_back(cellNode);
|
||||
}
|
||||
|
||||
// ===== Delete selected cell nodes
|
||||
for (auto cellNode : toBeDeleted) m_rowNode->remove_child(cellNode);
|
||||
|
||||
// ===== prepend new cell nodes to current row node
|
||||
auto curNode = XMLNode();
|
||||
auto colNo = values.size();
|
||||
for (auto value = values.rbegin(); value != values.rend(); ++value) { // NOLINT
|
||||
curNode = m_rowNode->prepend_child("c");
|
||||
curNode.append_attribute("r").set_value(XLCellReference(static_cast<uint32_t>(m_row->rowNumber()),
|
||||
static_cast<uint16_t>(colNo)).address().c_str());
|
||||
XLCell(curNode, m_row->m_sharedStrings).value() = *value;
|
||||
--colNo;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @details Assignment operator taking a std::vector of bool values as an argument. Under most circumstances,
|
||||
* one of the templated assignment operators should do the job. However, because std::vector<bool> is handled
|
||||
* differently than other value types, some compilers don't play well with using std::vector<bool> in a
|
||||
* template function. Therefore this edge case is handled separately.
|
||||
* @pre
|
||||
* @post
|
||||
*/
|
||||
XLRowDataProxy& XLRowDataProxy::operator=(const std::vector<bool>& values)
|
||||
{
|
||||
if (values.size() > MAX_COLS) throw XLOverflowError("Container size exceeds maximum number of columns.");
|
||||
if (values.empty()) return *this;
|
||||
|
||||
auto range = XLRowDataRange(*m_rowNode, 1, static_cast<uint16_t>(values.size()), getSharedStrings());
|
||||
auto dst = range.begin();
|
||||
auto src = values.begin();
|
||||
|
||||
while (true) {
|
||||
dst->value() = static_cast<bool>(*src);
|
||||
++src;
|
||||
if (src == values.end()) break;
|
||||
++dst;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @details This function simply calls the getValues() function, which returns a std::vector of XLCellValues as required.
|
||||
* @pre
|
||||
* @post
|
||||
*/
|
||||
XLRowDataProxy::operator std::vector<XLCellValue>() const
|
||||
{
|
||||
return getValues();
|
||||
}
|
||||
|
||||
/**
|
||||
* @details Calls the convertContainer convenience function with a std::deque of XLCellValues as an argument.
|
||||
* @pre
|
||||
* @post
|
||||
*/
|
||||
XLRowDataProxy::operator std::deque<XLCellValue>() const
|
||||
{
|
||||
return convertContainer<std::deque<XLCellValue>>();
|
||||
}
|
||||
|
||||
/**
|
||||
* @details Calls the convertContainer convenience function with a std::list of XLCellValues as an argument.
|
||||
* @pre
|
||||
* @post
|
||||
*/
|
||||
XLRowDataProxy::operator std::list<XLCellValue>() const
|
||||
{
|
||||
return convertContainer<std::list<XLCellValue>>();
|
||||
}
|
||||
|
||||
/**
|
||||
* @details Iterates through the cell values (if any) for the current row, and copies them to an output std::vector of XLCellValues.
|
||||
* @pre
|
||||
* @post
|
||||
*/
|
||||
std::vector<XLCellValue> XLRowDataProxy::getValues() const
|
||||
{
|
||||
// ===== Determine the number of cells in the current row. Create a std::vector of the same size.
|
||||
auto numCells =
|
||||
(m_rowNode->last_child() == XMLNode() ? 0 : XLCellReference(m_rowNode->last_child().attribute("r").value()).column());
|
||||
std::vector<XLCellValue> result(static_cast<uint64_t>(numCells));
|
||||
|
||||
// ===== If there are one or more cells in the current row, iterate through them and add the value to the container.
|
||||
if (numCells > 0) {
|
||||
for (auto& node : m_rowNode->children())
|
||||
result[XLCellReference(node.attribute("r").value()).column() - 1] = XLCell(node, m_row->m_sharedStrings).value();
|
||||
}
|
||||
|
||||
// ===== Return the resulting container.
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @details The function returns a pointer to an XLSharedStrings object embedded in the m_row member.
|
||||
* This is required because the XLRow class internals is not visible in the header file.
|
||||
* @pre
|
||||
* @post
|
||||
*/
|
||||
XLSharedStrings XLRowDataProxy::getSharedStrings() const
|
||||
{
|
||||
return m_row->m_sharedStrings;
|
||||
}
|
||||
|
||||
/**
|
||||
* @details The deleteCellValues is a convenience function used solely by the templated operator= function.
|
||||
* The purpose of a separate function is to keep details of xml_node out of the header file.
|
||||
* @pre
|
||||
* @post
|
||||
*/
|
||||
void XLRowDataProxy::deleteCellValues(uint16_t count)
|
||||
{
|
||||
// ===== Mark cell nodes for deletion
|
||||
std::vector<XMLNode> toBeDeleted;
|
||||
for (auto cellNode : m_rowNode->children()) {
|
||||
if (XLCellReference(cellNode.attribute("r").value()).column() <= count) toBeDeleted.emplace_back(cellNode);
|
||||
}
|
||||
|
||||
// ===== Delete selected cell nodes
|
||||
for (auto cellNode : toBeDeleted) m_rowNode->remove_child(cellNode);
|
||||
}
|
||||
|
||||
/**
|
||||
* @details The prependCellValue is a convenience function used solely by the templated operator= function.
|
||||
* The purpose of a separate function is to keep details of xml_node out of the header file.
|
||||
* Note that no checking on the column number is made.
|
||||
* @pre
|
||||
* @post
|
||||
*/
|
||||
void XLRowDataProxy::prependCellValue(const XLCellValue& value, uint16_t col)
|
||||
{
|
||||
auto curNode = m_rowNode->prepend_child("c");
|
||||
curNode.append_attribute("r").set_value(XLCellReference(static_cast<uint32_t>(m_row->rowNumber()), col).address().c_str());
|
||||
XLCell(curNode, m_row->m_sharedStrings).value() = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
* @pre
|
||||
* @post
|
||||
*/
|
||||
void XLRowDataProxy::clear()
|
||||
{
|
||||
m_rowNode->remove_children();
|
||||
}
|
||||
|
||||
} // namespace OpenXLSX
|
||||
+120
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
|
||||
____ ____ ___ ____ ____ ____ ___
|
||||
6MMMMb `MM( )M' `MM' 6MMMMb\`MM( )M'
|
||||
8P Y8 `MM. d' MM 6M' ` `MM. d'
|
||||
6M Mb __ ____ ____ ___ __ `MM. d' MM MM `MM. d'
|
||||
MM MM `M6MMMMb 6MMMMb `MM 6MMb `MM. d' MM YM. `MM. d'
|
||||
MM MM MM' `Mb 6M' `Mb MMM9 `Mb `MMd MM YMMMMb `MMd
|
||||
MM MM MM MM MM MM MM' MM dMM. MM `Mb dMM.
|
||||
MM MM MM MM MMMMMMMM MM MM d'`MM. MM MM d'`MM.
|
||||
YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM.
|
||||
8b d8 MM. ,M9 YM d9 MM MM d' `MM. MM / L ,M9 d' `MM.
|
||||
YMMMM9 MMYMMM9 YMMMM9 _MM_ _MM_M(_ _)MM_ _MMMMMMM MYMMMM9 _M(_ _)MM_
|
||||
MM
|
||||
MM
|
||||
_MM_
|
||||
|
||||
Copyright (c) 2018, Kenneth Troldal Balslev
|
||||
|
||||
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.
|
||||
- Neither the name of the author nor the
|
||||
names of any 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 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.
|
||||
|
||||
*/
|
||||
|
||||
// ===== External Includes ===== //
|
||||
#include <algorithm>
|
||||
#include <pugixml.hpp>
|
||||
|
||||
// ===== OpenXLSX Includes ===== //
|
||||
#include "XLDocument.hpp"
|
||||
#include "XLSharedStrings.hpp"
|
||||
|
||||
using namespace OpenXLSX;
|
||||
|
||||
/**
|
||||
* @details Constructs a new XLSharedStrings object. Only one (common) object is allowed per XLDocument instance.
|
||||
* A filepath to the underlying XML file must be provided.
|
||||
*/
|
||||
XLSharedStrings::XLSharedStrings(XLXmlData* xmlData, std::deque<std::string> *stringCache) : XLXmlFile(xmlData), m_stringCache(stringCache)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
XLSharedStrings::~XLSharedStrings() = default;
|
||||
|
||||
/**
|
||||
* @details Look up a string index by the string content. If the string does not exist, the returned index is -1.
|
||||
*/
|
||||
int32_t XLSharedStrings::getStringIndex(const std::string& str) const
|
||||
{
|
||||
auto iter = std::find_if(m_stringCache->begin(), m_stringCache->end(), [&](const std::string& s) { return str == s; });
|
||||
|
||||
return iter == m_stringCache->end() ? -1 : static_cast<int32_t>(std::distance(m_stringCache->begin(), iter));
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
bool XLSharedStrings::stringExists(const std::string& str) const
|
||||
{
|
||||
return getStringIndex(str) >= 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
const char* XLSharedStrings::getString(uint32_t index) const
|
||||
{
|
||||
return (*m_stringCache)[index].c_str();
|
||||
}
|
||||
|
||||
/**
|
||||
* @details Append a string by creating a new node in the XML file and adding the string to it. The index to the
|
||||
* shared string is returned
|
||||
*/
|
||||
int32_t XLSharedStrings::appendString(const std::string& str)
|
||||
{
|
||||
auto textNode = xmlDocument().document_element().append_child("si").append_child("t");
|
||||
if (str.front() == ' ' || str.back() == ' ') textNode.append_attribute("xml:space").set_value("preserve");
|
||||
|
||||
textNode.text().set(str.c_str());
|
||||
m_stringCache->emplace_back(textNode.text().get());
|
||||
|
||||
return static_cast<int32_t>(std::distance(m_stringCache->begin(), m_stringCache->end()) - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @details Clear the string at the given index. This will affect the entire spreadsheet; everywhere the shared string
|
||||
* is used, it will be erased.
|
||||
*/
|
||||
void XLSharedStrings::clearString(uint64_t index)
|
||||
{
|
||||
(*m_stringCache)[index] = "";
|
||||
auto iter = xmlDocument().document_element().children().begin();
|
||||
std::advance(iter, index);
|
||||
iter->text().set("");
|
||||
}
|
||||
Vendored
+626
@@ -0,0 +1,626 @@
|
||||
/*
|
||||
|
||||
____ ____ ___ ____ ____ ____ ___
|
||||
6MMMMb `MM( )M' `MM' 6MMMMb\`MM( )M'
|
||||
8P Y8 `MM. d' MM 6M' ` `MM. d'
|
||||
6M Mb __ ____ ____ ___ __ `MM. d' MM MM `MM. d'
|
||||
MM MM `M6MMMMb 6MMMMb `MM 6MMb `MM. d' MM YM. `MM. d'
|
||||
MM MM MM' `Mb 6M' `Mb MMM9 `Mb `MMd MM YMMMMb `MMd
|
||||
MM MM MM MM MM MM MM' MM dMM. MM `Mb dMM.
|
||||
MM MM MM MM MMMMMMMM MM MM d'`MM. MM MM d'`MM.
|
||||
YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM.
|
||||
8b d8 MM. ,M9 YM d9 MM MM d' `MM. MM / L ,M9 d' `MM.
|
||||
YMMMM9 MMYMMM9 YMMMM9 _MM_ _MM_M(_ _)MM_ _MMMMMMM MYMMMM9 _M(_ _)MM_
|
||||
MM
|
||||
MM
|
||||
_MM_
|
||||
|
||||
Copyright (c) 2018, Kenneth Troldal Balslev
|
||||
|
||||
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.
|
||||
- Neither the name of the author nor the
|
||||
names of any 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 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.
|
||||
|
||||
*/
|
||||
|
||||
// ===== External Includes ===== //
|
||||
#include <algorithm>
|
||||
#include <pugixml.hpp>
|
||||
|
||||
// ===== OpenXLSX Includes ===== //
|
||||
#include "XLCellRange.hpp"
|
||||
#include "XLDocument.hpp"
|
||||
#include "XLRelationships.hpp"
|
||||
#include "XLSheet.hpp"
|
||||
|
||||
using namespace OpenXLSX;
|
||||
|
||||
namespace OpenXLSX
|
||||
{
|
||||
// Forward declaration. Implementation is in the XLUtilities.hpp file
|
||||
XMLNode getRowNode(XMLNode sheetDataNode, uint32_t rowNumber);
|
||||
|
||||
/**
|
||||
* @brief Function for setting tab color.
|
||||
* @param xmlDocument XMLDocument object
|
||||
* @param color Thr color to set
|
||||
*/
|
||||
void setTabColor(const XMLDocument& xmlDocument, const XLColor& color) {
|
||||
|
||||
if (!xmlDocument.document_element().child("sheetPr")) xmlDocument.document_element().prepend_child("sheetPr");
|
||||
|
||||
if (!xmlDocument.document_element().child("sheetPr").child("tabColor"))
|
||||
xmlDocument.document_element().child("sheetPr").prepend_child("tabColor");
|
||||
|
||||
auto colorNode = xmlDocument.document_element().child("sheetPr").child("tabColor");
|
||||
for (auto attr : colorNode.attributes()) colorNode.remove_attribute(attr);
|
||||
|
||||
colorNode.prepend_attribute("rgb").set_value(color.hex().c_str());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Function for checking if the tab is selected.
|
||||
* @param xmlDocument
|
||||
* @param selected
|
||||
*/
|
||||
void setTabSelected(const XMLDocument& xmlDocument, bool selected) {
|
||||
unsigned int value = (selected ? 1 : 0);
|
||||
xmlDocument.first_child().child("sheetViews").first_child().attribute("tabSelected").set_value(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the tab selected property to true.
|
||||
* @param xmlDocument
|
||||
* @return
|
||||
*/
|
||||
bool tabIsSelected(const XMLDocument& xmlDocument) {
|
||||
return xmlDocument.first_child().child("sheetViews").first_child().attribute("tabSelected").value();
|
||||
}
|
||||
|
||||
} // namespace OpenXLSX
|
||||
|
||||
// ========== XLSheet Member Functions
|
||||
|
||||
/**
|
||||
* @details The constructor begins by constructing an instance of its superclass, XLAbstractXMLFile. The default
|
||||
* sheet type is WorkSheet and the default sheet state is Visible.
|
||||
*/
|
||||
XLSheet::XLSheet(XLXmlData* xmlData) : XLXmlFile(xmlData)
|
||||
{
|
||||
if (xmlData->getXmlType() == XLContentType::Worksheet)
|
||||
m_sheet = XLWorksheet(xmlData);
|
||||
else if (xmlData->getXmlType() == XLContentType::Chartsheet)
|
||||
m_sheet = XLChartsheet(xmlData);
|
||||
else
|
||||
throw XLInternalError("Invalid XML data.");
|
||||
}
|
||||
|
||||
/**
|
||||
* @details This method uses visitor pattern to return the name() member variable of the underlying
|
||||
* sheet object (XLWorksheet or XLChartsheet).
|
||||
*/
|
||||
std::string XLSheet::name() const
|
||||
{
|
||||
return std::visit([](auto&& arg) { return arg.name(); }, m_sheet);
|
||||
}
|
||||
|
||||
/**
|
||||
* @details This method sets the name of the sheet to a new name, by calling the setName()
|
||||
* member function of the underlying sheet object (XLWorksheet or XLChartsheet).
|
||||
*/
|
||||
void XLSheet::setName(const std::string& name)
|
||||
{
|
||||
std::visit([&](auto&& arg) { return arg.setName(name); }, m_sheet);
|
||||
}
|
||||
|
||||
/**
|
||||
* @details This method uses visitor pattern to return the visibility() member variable of the underlying
|
||||
* sheet object (XLWorksheet or XLChartsheet).
|
||||
*/
|
||||
XLSheetState XLSheet::visibility() const
|
||||
{
|
||||
return std::visit([](auto&& arg) { return arg.visibility(); }, m_sheet);
|
||||
}
|
||||
|
||||
/**
|
||||
* @details This method sets the visibility state of the sheet, by calling the setVisibility()
|
||||
* member function of the underlying sheet object (XLWorksheet or XLChartsheet).
|
||||
*/
|
||||
void XLSheet::setVisibility(XLSheetState state)
|
||||
{
|
||||
std::visit([&](auto&& arg) { return arg.setVisibility(state); }, m_sheet);
|
||||
}
|
||||
|
||||
/**
|
||||
* @details This method uses visitor pattern to return the color() member variable of the underlying
|
||||
* sheet object (XLWorksheet or XLChartsheet).
|
||||
*/
|
||||
XLColor XLSheet::color() const
|
||||
{
|
||||
return std::visit([](auto&& arg) { return arg.color(); }, m_sheet);
|
||||
}
|
||||
|
||||
/**
|
||||
* @details This method sets the color of the sheet, by calling the setColor()
|
||||
* member function of the underlying sheet object (XLWorksheet or XLChartsheet).
|
||||
*/
|
||||
void XLSheet::setColor(const XLColor& color)
|
||||
{
|
||||
std::visit([&](auto&& arg) { return arg.setColor(color); }, m_sheet);
|
||||
}
|
||||
|
||||
/**
|
||||
* @details This method sets the selection state of the sheet, by calling the setSelected()
|
||||
* member function of the underlying sheet object (XLWorksheet or XLChartsheet).
|
||||
*/
|
||||
void XLSheet::setSelected(bool selected)
|
||||
{
|
||||
std::visit([&](auto&& arg) { return arg.setSelected(selected); }, m_sheet);
|
||||
}
|
||||
|
||||
/**
|
||||
* @details Clones the sheet by calling the clone() method in the underlying sheet object
|
||||
* (XLWorksheet or XLChartsheet), using the visitor pattern.
|
||||
*/
|
||||
void XLSheet::clone(const std::string& newName)
|
||||
{
|
||||
std::visit([&](auto&& arg) { arg.clone(newName); }, m_sheet);
|
||||
}
|
||||
|
||||
/**
|
||||
* @details Get the index of the sheet, by calling the index() method in the underlying
|
||||
* sheet object (XLWorksheet or XLChartsheet), using the visitor pattern.
|
||||
*/
|
||||
uint16_t XLSheet::index() const
|
||||
{
|
||||
return std::visit([](auto&& arg) { return arg.index(); }, m_sheet);
|
||||
}
|
||||
|
||||
/**
|
||||
* @details This method sets the index of the sheet (i.e. move the sheet), by calling the setIndex()
|
||||
* member function of the underlying sheet object (XLWorksheet or XLChartsheet).
|
||||
*/
|
||||
void XLSheet::setIndex(uint16_t index)
|
||||
{
|
||||
std::visit([&](auto&& arg) { arg.setIndex(index); }, m_sheet);
|
||||
}
|
||||
|
||||
/**
|
||||
* @details Implicit conversion operator to XLWorksheet. Calls the get<>() member function, with XLWorksheet as
|
||||
* the template argument.
|
||||
*/
|
||||
XLSheet::operator XLWorksheet() const
|
||||
{
|
||||
return this->get<XLWorksheet>();
|
||||
}
|
||||
|
||||
/**
|
||||
* @details Implicit conversion operator to XLChartsheet. Calls the get<>() member function, with XLChartsheet as
|
||||
* the template argument.
|
||||
*/
|
||||
XLSheet::operator XLChartsheet() const
|
||||
{
|
||||
return this->get<XLChartsheet>();
|
||||
}
|
||||
|
||||
|
||||
// ========== XLWorksheet Member Functions
|
||||
|
||||
/**
|
||||
* @details The constructor does some slight reconfiguration of the XML file, in order to make parsing easier.
|
||||
* For example, columns with identical formatting are by default grouped under the same node. However, this makes it more difficult to
|
||||
* parse, so the constructor reconfigures it so each column has it's own formatting.
|
||||
*/
|
||||
XLWorksheet::XLWorksheet(XLXmlData* xmlData) : XLSheetBase(xmlData)
|
||||
{
|
||||
// ===== Read the dimensions of the Sheet and set data members accordingly.
|
||||
std::string dimensions = xmlDocument().document_element().child("dimension").attribute("ref").value();
|
||||
if (dimensions.find(':') == std::string::npos)
|
||||
xmlDocument().document_element().child("dimension").set_value("A1");
|
||||
else
|
||||
xmlDocument().document_element().child("dimension").set_value(dimensions.substr(dimensions.find(':') + 1).c_str());
|
||||
|
||||
// If Column properties are grouped, divide them into properties for individual Columns.
|
||||
if (xmlDocument().first_child().child("cols").type() != pugi::node_null) {
|
||||
auto currentNode = xmlDocument().first_child().child("cols").first_child();
|
||||
while (currentNode != nullptr) {
|
||||
int min = std::stoi(currentNode.attribute("min").value());
|
||||
int max = std::stoi(currentNode.attribute("max").value());
|
||||
if (min != max) {
|
||||
currentNode.attribute("min").set_value(max);
|
||||
for (int i = min; i < max; i++) { // NOLINT
|
||||
auto newnode = xmlDocument().first_child().child("cols").insert_child_before("col", currentNode);
|
||||
auto attr = currentNode.first_attribute();
|
||||
while (attr != nullptr) { // NOLINT
|
||||
newnode.append_attribute(attr.name()) = attr.value();
|
||||
attr = attr.next_attribute();
|
||||
}
|
||||
newnode.attribute("min") = i;
|
||||
newnode.attribute("max") = i;
|
||||
}
|
||||
}
|
||||
currentNode = currentNode.next_sibling();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @details Destructor. Default implementation.
|
||||
*/
|
||||
XLWorksheet::~XLWorksheet() = default;
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
XLColor XLWorksheet::getColor_impl() const
|
||||
{
|
||||
return XLColor(xmlDocument().document_element().child("sheetPr").child("tabColor").attribute("rgb").value());
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
void XLWorksheet::setColor_impl(const XLColor& color)
|
||||
{
|
||||
setTabColor(xmlDocument(), color);
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
bool XLWorksheet::isSelected_impl() const
|
||||
{
|
||||
return tabIsSelected(xmlDocument());
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
void XLWorksheet::setSelected_impl(bool selected)
|
||||
{
|
||||
setTabSelected(xmlDocument(), selected);
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
bool XLWorksheet::isActive_impl() const
|
||||
{
|
||||
return parentDoc().execQuery(XLQuery(XLQueryType::QuerySheetIsActive).setParam("sheetID", relationshipID())).result<bool>();
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
void XLWorksheet::setActive_impl()
|
||||
{
|
||||
parentDoc().execCommand(XLCommand(XLCommandType::SetSheetActive).setParam("sheetID", relationshipID()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
XLCell XLWorksheet::cell(const std::string& ref) const
|
||||
{
|
||||
return cell(XLCellReference(ref));
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
XLCell XLWorksheet::cell(const XLCellReference& ref) const
|
||||
{
|
||||
return cell(ref.row(), ref.column());
|
||||
}
|
||||
|
||||
/**
|
||||
* @details This function returns a pointer to an XLCell object in the worksheet. This particular overload
|
||||
* also serves as the main function, called by the other overloads.
|
||||
*/
|
||||
XLCell XLWorksheet::cell(uint32_t rowNumber, uint16_t columnNumber) const
|
||||
{
|
||||
auto cellNode = XMLNode();
|
||||
auto cellRef = XLCellReference(rowNumber, columnNumber);
|
||||
auto rowNode = getRowNode(xmlDocument().first_child().child("sheetData"), rowNumber);
|
||||
|
||||
// ===== If there are no cells in the current row, or the requested cell is beyond the last cell in the row...
|
||||
if (rowNode.last_child().empty() || XLCellReference(rowNode.last_child().attribute("r").value()).column() < columnNumber) {
|
||||
// if (rowNode.last_child().empty() ||
|
||||
// XLCellReference::CoordinatesFromAddress(rowNode.last_child().attribute("r").getValue()).second < columnNumber) {
|
||||
rowNode.append_child("c").append_attribute("r").set_value(cellRef.address().c_str());
|
||||
cellNode = rowNode.last_child();
|
||||
}
|
||||
// ===== If the requested node is closest to the end, start from the end and search backwards...
|
||||
else if (XLCellReference(rowNode.last_child().attribute("r").value()).column() - columnNumber < columnNumber) {
|
||||
cellNode = rowNode.last_child();
|
||||
while (XLCellReference(cellNode.attribute("r").value()).column() > columnNumber) cellNode = cellNode.previous_sibling();
|
||||
if (XLCellReference(cellNode.attribute("r").value()).column() < columnNumber) {
|
||||
cellNode = rowNode.insert_child_after("c", cellNode);
|
||||
cellNode.append_attribute("r").set_value(cellRef.address().c_str());
|
||||
}
|
||||
}
|
||||
// ===== Otherwise, start from the beginning
|
||||
else {
|
||||
cellNode = rowNode.first_child();
|
||||
while (XLCellReference(cellNode.attribute("r").value()).column() < columnNumber) cellNode = cellNode.next_sibling();
|
||||
if (XLCellReference(cellNode.attribute("r").value()).column() > columnNumber) {
|
||||
cellNode = rowNode.insert_child_before("c", cellNode);
|
||||
cellNode.append_attribute("r").set_value(cellRef.address().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
return XLCell{cellNode, parentDoc().execQuery(XLQuery(XLQueryType::QuerySharedStrings)).result<XLSharedStrings>()};
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
XLCellRange XLWorksheet::range() const
|
||||
{
|
||||
return range(XLCellReference("A1"), lastCell());
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
XLCellRange XLWorksheet::range(const XLCellReference& topLeft, const XLCellReference& bottomRight) const
|
||||
{
|
||||
return XLCellRange(xmlDocument().first_child().child("sheetData"),
|
||||
topLeft,
|
||||
bottomRight,
|
||||
parentDoc().execQuery(XLQuery(XLQueryType::QuerySharedStrings)).result<XLSharedStrings>());
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
* @pre
|
||||
* @post
|
||||
*/
|
||||
XLRowRange XLWorksheet::rows() const
|
||||
{
|
||||
auto sheetDataNode = xmlDocument().first_child().child("sheetData");
|
||||
return XLRowRange(sheetDataNode,
|
||||
1,
|
||||
(sheetDataNode.last_child()
|
||||
? static_cast<uint32_t>(sheetDataNode.last_child().attribute("r").as_ullong())
|
||||
: 1),
|
||||
parentDoc().execQuery(XLQuery(XLQueryType::QuerySharedStrings)).result<XLSharedStrings>());
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
* @pre
|
||||
* @post
|
||||
*/
|
||||
XLRowRange XLWorksheet::rows(uint32_t rowCount) const
|
||||
{
|
||||
return XLRowRange(xmlDocument().first_child().child("sheetData"),
|
||||
1,
|
||||
rowCount,
|
||||
parentDoc().execQuery(XLQuery(XLQueryType::QuerySharedStrings)).result<XLSharedStrings>());
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
* @pre
|
||||
* @post
|
||||
*/
|
||||
XLRowRange XLWorksheet::rows(uint32_t firstRow, uint32_t lastRow) const
|
||||
{
|
||||
return XLRowRange(xmlDocument().first_child().child("sheetData"),
|
||||
firstRow,
|
||||
lastRow,
|
||||
parentDoc().execQuery(XLQuery(XLQueryType::QuerySharedStrings)).result<XLSharedStrings>());
|
||||
}
|
||||
|
||||
/**
|
||||
* @details Get the XLRow object corresponding to the given row number. In the XML file, all cell data are stored under
|
||||
* the corresponding row, and all rows have to be ordered in ascending order. If a row have no data, there may not be a
|
||||
* node for that row.
|
||||
*/
|
||||
XLRow XLWorksheet::row(uint32_t rowNumber) const
|
||||
{
|
||||
return XLRow{getRowNode(xmlDocument().first_child().child("sheetData"), rowNumber),
|
||||
parentDoc().execQuery(XLQuery(XLQueryType::QuerySharedStrings)).result<XLSharedStrings>()};
|
||||
}
|
||||
|
||||
/**
|
||||
* @details Get the XLColumn object corresponding to the given column number. In the underlying XML data structure,
|
||||
* column nodes do not hold any cell data. Columns are used solely to hold data regarding column formatting.
|
||||
* @todo Consider simplifying this function. Can any standard algorithms be used?
|
||||
*/
|
||||
XLColumn XLWorksheet::column(uint16_t columnNumber) const
|
||||
{
|
||||
// If no columns exists, create the <cols> node in the XML document.
|
||||
if (!xmlDocument().first_child().child("cols"))
|
||||
xmlDocument().first_child().insert_child_before("cols", xmlDocument().first_child().child("sheetData"));
|
||||
|
||||
// ===== Find the column node, if it exists
|
||||
auto columnNode =
|
||||
xmlDocument().first_child().child("cols").find_child([&](XMLNode node) {
|
||||
return (columnNumber >= node.attribute("min").as_int() && columnNumber <= node.attribute("max").as_int()) || node.attribute("min").as_int() > columnNumber; });
|
||||
|
||||
// ===== If the node exists for the column, and only spans that column, then continue...
|
||||
if (columnNode && columnNode.attribute("min").as_int() == columnNumber && columnNode.attribute("max").as_int() == columnNumber) {}
|
||||
|
||||
// ===== If the node exists for the column, but spans several columns, split it into individual nodes, and set columnNode to the right one...
|
||||
else if (columnNode && columnNode.attribute("min").as_int() != columnNode.attribute("max").as_int()) {
|
||||
// ===== Split the node in individual columns...
|
||||
for (int i = columnNode.attribute("min").as_int(); i < columnNode.attribute("max").as_int(); ++i) {
|
||||
auto node = xmlDocument().first_child().child("cols").insert_copy_before(columnNode, columnNode);
|
||||
node.attribute("min").set_value(i);
|
||||
node.attribute("max").set_value(i);
|
||||
}
|
||||
// ===== Delete the original node
|
||||
columnNode = columnNode.previous_sibling();
|
||||
xmlDocument().first_child().child("cols").remove_child(columnNode.next_sibling());
|
||||
// ===== Find the node corresponding to the column number
|
||||
while (true) {
|
||||
if (columnNode.attribute("min").as_int() == columnNumber) break;
|
||||
columnNode = columnNode.previous_sibling();
|
||||
}
|
||||
}
|
||||
|
||||
// ===== If a node for the column does NOT exist, but a node for a higher column exist...
|
||||
else if (columnNode && columnNode.attribute("min").as_int() > columnNumber) {
|
||||
columnNode = xmlDocument().first_child().child("cols").insert_child_before("col", columnNode);
|
||||
columnNode.append_attribute("min") = columnNumber;
|
||||
columnNode.append_attribute("max") = columnNumber;
|
||||
columnNode.append_attribute("width") = 9.8; // NOLINT
|
||||
columnNode.append_attribute("customWidth") = 0;
|
||||
}
|
||||
|
||||
// ===== Otherwise, the end of the list is reached, and a new node is appended
|
||||
else if (!columnNode) {
|
||||
columnNode = xmlDocument().first_child().child("cols").append_child("col");
|
||||
columnNode.append_attribute("min") = columnNumber;
|
||||
columnNode.append_attribute("max") = columnNumber;
|
||||
columnNode.append_attribute("width") = 9.8; // NOLINT
|
||||
columnNode.append_attribute("customWidth") = 0;
|
||||
}
|
||||
|
||||
|
||||
// if (!columnNode || columnNode.attribute("min").as_int() > columnNumber) {
|
||||
// if (columnNode.attribute("min").as_int() > columnNumber) {
|
||||
// columnNode = xmlDocument().first_child().child("cols").insert_child_before("col", columnNode);
|
||||
// }
|
||||
// else {
|
||||
// columnNode = xmlDocument().first_child().child("cols").append_child("col");
|
||||
// }
|
||||
//
|
||||
// columnNode.append_attribute("min") = columnNumber;
|
||||
// columnNode.append_attribute("max") = columnNumber;
|
||||
// columnNode.append_attribute("width") = 10; // NOLINT
|
||||
// columnNode.append_attribute("customWidth") = 1;
|
||||
// }
|
||||
|
||||
return XLColumn(columnNode);
|
||||
}
|
||||
|
||||
/**
|
||||
* @details Returns an XLCellReference to the last cell using rowCount() and columnCount() methods.
|
||||
*/
|
||||
XLCellReference XLWorksheet::lastCell() const noexcept
|
||||
{
|
||||
return {rowCount(), columnCount()};
|
||||
}
|
||||
|
||||
/**
|
||||
* @details Iterates through the rows and finds the maximum number of cells.
|
||||
*/
|
||||
uint16_t XLWorksheet::columnCount() const noexcept
|
||||
{
|
||||
std::vector<int16_t> counts;
|
||||
for (const auto& row : rows()) {
|
||||
counts.emplace_back(row.cellCount());
|
||||
}
|
||||
|
||||
return std::max(static_cast<uint16_t>(1), static_cast<uint16_t>(*std::max_element(counts.begin(), counts.end())));
|
||||
}
|
||||
|
||||
/**
|
||||
* @details Finds the last row (node) and returns the row number.
|
||||
*/
|
||||
uint32_t XLWorksheet::rowCount() const noexcept
|
||||
{
|
||||
return static_cast<uint32_t>(xmlDocument().document_element().child("sheetData").last_child().attribute("r").as_ullong());
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
void XLWorksheet::updateSheetName(const std::string& oldName, const std::string& newName)
|
||||
{
|
||||
// ===== Set up temporary variables
|
||||
std::string oldNameTemp = oldName;
|
||||
std::string newNameTemp = newName;
|
||||
std::string formula;
|
||||
|
||||
// ===== If the sheet name contains spaces, it should be enclosed in single quotes (')
|
||||
if (oldName.find(' ') != std::string::npos) oldNameTemp = "\'" + oldName + "\'";
|
||||
if (newName.find(' ') != std::string::npos) newNameTemp = "\'" + newName + "\'";
|
||||
|
||||
// ===== Ensure only sheet names are replaced (references to sheets always ends with a '!')
|
||||
oldNameTemp += '!';
|
||||
newNameTemp += '!';
|
||||
|
||||
// ===== Iterate through all defined names
|
||||
for (auto& row : xmlDocument().document_element().child("sheetData")) {
|
||||
for (auto& cell : row.children()) {
|
||||
if (!XLCell(cell, XLSharedStrings()).hasFormula()) continue;
|
||||
|
||||
formula = XLCell(cell, XLSharedStrings()).formula().get();
|
||||
|
||||
// ===== Skip if formula contains a '[' and ']' (means that the defined refers to external workbook)
|
||||
if (formula.find('[') == std::string::npos && formula.find(']') == std::string::npos) {
|
||||
// ===== For all instances of the old sheet name in the formula, replace with the new name.
|
||||
while (formula.find(oldNameTemp) != std::string::npos) { // NOLINT
|
||||
formula.replace(formula.find(oldNameTemp), oldNameTemp.length(), newNameTemp);
|
||||
}
|
||||
XLCell(cell, XLSharedStrings()).formula() = formula;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @details Constructor
|
||||
*/
|
||||
XLChartsheet::XLChartsheet(XLXmlData* xmlData) : XLSheetBase(xmlData) {}
|
||||
|
||||
/**
|
||||
* @details Destructor. Default implementation used.
|
||||
*/
|
||||
XLChartsheet::~XLChartsheet() = default;
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
XLColor XLChartsheet::getColor_impl() const
|
||||
{
|
||||
return XLColor(xmlDocument().document_element().child("sheetPr").child("tabColor").attribute("rgb").value());
|
||||
}
|
||||
|
||||
/**
|
||||
* @details Calls the setTabColor() free function.
|
||||
*/
|
||||
void XLChartsheet::setColor_impl(const XLColor& color)
|
||||
{
|
||||
setTabColor(xmlDocument(), color);
|
||||
}
|
||||
|
||||
/**
|
||||
* @details Calls the tabIsSelected() free function.
|
||||
*/
|
||||
bool XLChartsheet::isSelected_impl() const
|
||||
{
|
||||
return tabIsSelected(xmlDocument());
|
||||
}
|
||||
|
||||
/**
|
||||
* @details Calls the setTabSelected() free function.
|
||||
*/
|
||||
void XLChartsheet::setSelected_impl(bool selected)
|
||||
{
|
||||
setTabSelected(xmlDocument(), selected);
|
||||
}
|
||||
+628
@@ -0,0 +1,628 @@
|
||||
/*
|
||||
|
||||
____ ____ ___ ____ ____ ____ ___
|
||||
6MMMMb `MM( )M' `MM' 6MMMMb\`MM( )M'
|
||||
8P Y8 `MM. d' MM 6M' ` `MM. d'
|
||||
6M Mb __ ____ ____ ___ __ `MM. d' MM MM `MM. d'
|
||||
MM MM `M6MMMMb 6MMMMb `MM 6MMb `MM. d' MM YM. `MM. d'
|
||||
MM MM MM' `Mb 6M' `Mb MMM9 `Mb `MMd MM YMMMMb `MMd
|
||||
MM MM MM MM MM MM MM' MM dMM. MM `Mb dMM.
|
||||
MM MM MM MM MMMMMMMM MM MM d'`MM. MM MM d'`MM.
|
||||
YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM.
|
||||
8b d8 MM. ,M9 YM d9 MM MM d' `MM. MM / L ,M9 d' `MM.
|
||||
YMMMM9 MMYMMM9 YMMMM9 _MM_ _MM_M(_ _)MM_ _MMMMMMM MYMMMM9 _M(_ _)MM_
|
||||
MM
|
||||
MM
|
||||
_MM_
|
||||
|
||||
Copyright (c) 2018, Kenneth Troldal Balslev
|
||||
|
||||
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.
|
||||
- Neither the name of the author nor the
|
||||
names of any 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 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.
|
||||
|
||||
*/
|
||||
|
||||
// ===== External Includes ===== //
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
#include <pugixml.hpp>
|
||||
#include <vector>
|
||||
|
||||
// ===== OpenXLSX Includes ===== //
|
||||
#include "XLDocument.hpp"
|
||||
#include "XLSheet.hpp"
|
||||
#include "XLWorkbook.hpp"
|
||||
|
||||
using namespace OpenXLSX;
|
||||
|
||||
namespace
|
||||
{
|
||||
/**
|
||||
* @brief
|
||||
* @param doc
|
||||
* @return
|
||||
*/
|
||||
XMLNode sheetsNode(const XMLDocument& doc)
|
||||
{
|
||||
return doc.document_element().child("sheets");
|
||||
}
|
||||
} // namespace
|
||||
|
||||
/**
|
||||
* @details The constructor initializes the member variables and calls the loadXMLData from the
|
||||
* XLAbstractXMLFile base class.
|
||||
*/
|
||||
XLWorkbook::XLWorkbook(XLXmlData* xmlData) : XLXmlFile(xmlData) {}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
XLWorkbook::~XLWorkbook() = default;
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
XLSheet XLWorkbook::sheet(const std::string& sheetName)
|
||||
{
|
||||
// ===== First determine if the sheet exists.
|
||||
if (xmlDocument().document_element().child("sheets").find_child_by_attribute("name", sheetName.c_str()) == nullptr)
|
||||
throw XLInputError("Sheet \"" + sheetName + "\" does not exist");
|
||||
|
||||
// ===== Find the sheet data corresponding to the sheet with the requested name
|
||||
std::string xmlID =
|
||||
xmlDocument().document_element().child("sheets").find_child_by_attribute("name", sheetName.c_str()).attribute("r:id").value();
|
||||
|
||||
XLQuery pathQuery(XLQueryType::QuerySheetRelsTarget);
|
||||
pathQuery.setParam("sheetID", xmlID);
|
||||
auto xmlPath = parentDoc().execQuery(pathQuery).result<std::string>();
|
||||
|
||||
// Some spreadsheets use absolute rather than relative paths in relationship items.
|
||||
if (xmlPath.substr(0,4) == "/xl/") xmlPath = xmlPath.substr(4);
|
||||
|
||||
XLQuery xmlQuery(XLQueryType::QueryXmlData);
|
||||
xmlQuery.setParam("xmlPath", "xl/" + xmlPath);
|
||||
return XLSheet(parentDoc().execQuery(xmlQuery).result<XLXmlData*>());
|
||||
}
|
||||
|
||||
/**
|
||||
* @details Create a vector with sheet nodes, retrieve the node at the requested index, get sheet name and return the
|
||||
* corresponding sheet object.
|
||||
*/
|
||||
XLSheet XLWorkbook::sheet(uint16_t index)
|
||||
{
|
||||
if (index < 1 || index > sheetCount()) throw XLInputError("Sheet index is out of bounds");
|
||||
return sheet(
|
||||
std::vector<XMLNode>(sheetsNode(xmlDocument()).begin(), sheetsNode(xmlDocument()).end())[index - 1].attribute("name").as_string());
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
XLWorksheet XLWorkbook::worksheet(const std::string& sheetName)
|
||||
{
|
||||
return sheet(sheetName).get<XLWorksheet>();
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
XLChartsheet XLWorkbook::chartsheet(const std::string& sheetName)
|
||||
{
|
||||
return sheet(sheetName).get<XLChartsheet>();
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
bool XLWorkbook::hasSharedStrings() const
|
||||
{
|
||||
return true;//parentDoc().executeQuery(XLQuerySharedStrings()).sharedStrings() != nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
XLSharedStrings XLWorkbook::sharedStrings()
|
||||
{
|
||||
XLQuery query(XLQueryType::QuerySharedStrings);
|
||||
return parentDoc().execQuery(query).result<XLSharedStrings>();
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
void XLWorkbook::deleteNamedRanges()
|
||||
{
|
||||
for (auto& child : xmlDocument().document_element().child("definedNames").children()) child.parent().remove_child(child);
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
void XLWorkbook::deleteSheet(const std::string& sheetName)
|
||||
{
|
||||
// ===== Determine ID and type of sheet, as well as current worksheet count.
|
||||
auto sheetID = sheetsNode(xmlDocument()).find_child_by_attribute("name", sheetName.c_str()).attribute("r:id").value(); // NOLINT
|
||||
|
||||
XLQuery sheetTypeQuery(XLQueryType::QuerySheetType);
|
||||
sheetTypeQuery.setParam("sheetID", relationshipID());
|
||||
auto sheetType = parentDoc().execQuery(sheetTypeQuery).result<XLContentType>();
|
||||
|
||||
auto worksheetCount =
|
||||
std::count_if(sheetsNode(xmlDocument()).children().begin(), sheetsNode(xmlDocument()).children().end(), [&](const XMLNode& item) {
|
||||
XLQuery query(XLQueryType::QuerySheetType);
|
||||
query.setParam("sheetID", std::string(item.attribute("r:id").value()));
|
||||
return parentDoc().execQuery(query).result<XLContentType>() == XLContentType::Worksheet;
|
||||
});
|
||||
|
||||
// ===== If this is the last worksheet in the workbook, throw an exception.
|
||||
if (worksheetCount == 1 && sheetType == XLContentType::Worksheet)
|
||||
throw XLInputError("Invalid operation. There must be at least one worksheet in the workbook.");
|
||||
|
||||
// ===== Delete the sheet data as well as the sheet node from Workbook.xml
|
||||
parentDoc().execCommand(XLCommand(XLCommandType::DeleteSheet)
|
||||
.setParam("sheetID", std::string(sheetID))
|
||||
.setParam("sheetName", sheetName));
|
||||
sheetsNode(xmlDocument()).remove_child(sheetsNode(xmlDocument()).find_child_by_attribute("name", sheetName.c_str()));
|
||||
|
||||
if (sheetIsActive(sheetID))
|
||||
xmlDocument().document_element().child("bookViews").first_child().remove_attribute("activeTab");
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
void XLWorkbook::addWorksheet(const std::string& sheetName)
|
||||
{
|
||||
// ===== If a sheet with the given name already exists, throw an exception.
|
||||
if (xmlDocument().document_element().child("sheets").find_child_by_attribute("name", sheetName.c_str()))
|
||||
throw XLInputError("Sheet named \"" + sheetName + "\" already exists.");
|
||||
|
||||
// ===== Create new internal (workbook) ID for the sheet
|
||||
auto internalID = createInternalSheetID();
|
||||
|
||||
// ===== Create xml file for new worksheet and add metadata to the workbook file.
|
||||
parentDoc().execCommand(XLCommand(XLCommandType::AddWorksheet)
|
||||
.setParam("sheetName", sheetName)
|
||||
.setParam("sheetPath", "/xl/worksheets/sheet" + std::to_string(internalID) + ".xml"));
|
||||
prepareSheetMetadata(sheetName, internalID);
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
* @todo If the original sheet's tabSelected attribute is set, ensure it is un-set in the clone.
|
||||
*/
|
||||
void XLWorkbook::cloneSheet(const std::string& existingName, const std::string& newName)
|
||||
{
|
||||
parentDoc().execCommand(XLCommand(XLCommandType::CloneSheet)
|
||||
.setParam("sheetID", sheetID(existingName))
|
||||
.setParam("cloneName", newName));
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
uint16_t XLWorkbook::createInternalSheetID()
|
||||
{
|
||||
return static_cast<uint16_t>(std::max_element(xmlDocument().document_element().child("sheets").children().begin(),
|
||||
xmlDocument().document_element().child("sheets").children().end(),
|
||||
[](const XMLNode& a, const XMLNode& b) {
|
||||
return a.attribute("sheetId").as_uint() < b.attribute("sheetId").as_uint();
|
||||
})
|
||||
->attribute("sheetId")
|
||||
.as_uint() +
|
||||
1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
std::string XLWorkbook::sheetID(const std::string& sheetName)
|
||||
{
|
||||
return xmlDocument().document_element().child("sheets").find_child_by_attribute("name", sheetName.c_str()).attribute("r:id").value();
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
std::string XLWorkbook::sheetName(const std::string& sheetID) const
|
||||
{
|
||||
return xmlDocument().document_element().child("sheets").find_child_by_attribute("r:id", sheetID.c_str()).attribute("name").value();
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
std::string XLWorkbook::sheetVisibility(const std::string& sheetID) const
|
||||
{
|
||||
return xmlDocument().document_element().child("sheets").find_child_by_attribute("r:id", sheetID.c_str()).attribute("state").value();
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
void XLWorkbook::prepareSheetMetadata(const std::string& sheetName, uint16_t internalID)
|
||||
{
|
||||
// ===== Add new child node to the "sheets" node.
|
||||
auto node = sheetsNode(xmlDocument()).append_child("sheet");
|
||||
|
||||
// ===== append the required attributes to the newly created sheet node.
|
||||
std::string sheetPath = "/xl/worksheets/sheet" + std::to_string(internalID) + ".xml";
|
||||
node.append_attribute("name") = sheetName.c_str();
|
||||
node.append_attribute("sheetId") = std::to_string(internalID).c_str();
|
||||
|
||||
XLQuery query(XLQueryType::QuerySheetRelsID);
|
||||
query.setParam("sheetPath", sheetPath);
|
||||
node.append_attribute("r:id") = parentDoc().execQuery(query).result<std::string>().c_str();
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
void XLWorkbook::setSheetName(const std::string& sheetRID, const std::string& newName)
|
||||
{
|
||||
auto sheetName = xmlDocument().document_element().child("sheets").find_child_by_attribute("r:id", sheetRID.c_str()).attribute("name");
|
||||
|
||||
updateSheetReferences(sheetName.value(), newName);
|
||||
sheetName.set_value(newName.c_str());
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
void XLWorkbook::setSheetVisibility(const std::string& sheetRID, const std::string& state)
|
||||
{
|
||||
// ===== First, determine if there are other sheets that are visible
|
||||
int visibleSheets = 0;
|
||||
for (const auto& item : xmlDocument().document_element().child("sheets").children()) {
|
||||
if (std::string(item.attribute("r:id").value()) != sheetRID) {
|
||||
if (!item.attribute("state") || !(std::string(item.attribute("state").value()) == "hidden" || std::string(item.attribute("state").value()) == "veryHidden"))
|
||||
++visibleSheets;
|
||||
}
|
||||
}
|
||||
|
||||
// ===== If there are no other visible sheets, and the current sheet is to be made hidden, throw an exception.
|
||||
if ((state == "hidden" || state == "veryHidden") && visibleSheets == 0)
|
||||
throw XLSheetError("At least one sheet must be visible.");
|
||||
|
||||
// ===== Then, retrieve or create the visibility ("state") attribute for the sheet, and set it to the "state" value
|
||||
auto stateAttribute =
|
||||
xmlDocument().document_element().child("sheets").find_child_by_attribute("r:id", sheetRID.c_str()).attribute("state");
|
||||
if (!stateAttribute) {
|
||||
stateAttribute =
|
||||
xmlDocument().document_element().child("sheets").find_child_by_attribute("r:id", sheetRID.c_str()).prepend_attribute("state");
|
||||
}
|
||||
stateAttribute.set_value(state.c_str());
|
||||
|
||||
// Next, find the index of the sheet...
|
||||
std::string name = xmlDocument().document_element().child("sheets").find_child_by_attribute("r:id", sheetRID.c_str()).attribute("name").value();
|
||||
auto index = indexOfSheet(name) - 1;
|
||||
|
||||
// ...and determine the index of the active sheet
|
||||
auto activeTabAttribute = xmlDocument().document_element().child("bookViews").first_child().attribute("activeTab");
|
||||
if (!activeTabAttribute) {
|
||||
activeTabAttribute = xmlDocument().document_element().child("bookViews").first_child().append_attribute("activeTab");
|
||||
activeTabAttribute.set_value(0);
|
||||
}
|
||||
auto activeTabIndex = activeTabAttribute.as_uint();
|
||||
|
||||
// Finally, if the current sheet is the active one, set the "activeTab" attribute to the first visible sheet in the workbook
|
||||
if (activeTabIndex == index) {
|
||||
for (auto& item : xmlDocument().document_element().child("sheets").children()) {
|
||||
if (!item.attribute("state") || std::string(item.attribute("state").value()) != "hidden" || std::string(item.attribute("state").value()) != "veryHidden")
|
||||
activeTabAttribute.set_value(indexOfSheet(item.attribute("name").value()) - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
* @todo In some cases (eg. if a sheet is moved to the position before the selected sheet), multiple sheets are selected when opened in Excel.
|
||||
*/
|
||||
void XLWorkbook::setSheetIndex(const std::string& sheetName, unsigned int index)
|
||||
{
|
||||
// ===== Check that the input is valid
|
||||
// if (index < 1 || index > std::distance(xmlDocument().document_element().child("sheets").children().begin(),
|
||||
// xmlDocument().document_element().child("sheets").children().end()))
|
||||
// throw XLException("Invalid sheet index");
|
||||
|
||||
// ===== If the new index is equal to the current, don't do anything
|
||||
if (index-1 == std::distance(xmlDocument().document_element().child("sheets").children().begin(),
|
||||
std::find_if(xmlDocument().document_element().child("sheets").children().begin(),
|
||||
xmlDocument().document_element().child("sheets").children().end(),
|
||||
[&](const XMLNode& item) { return sheetName == item.attribute("name").value(); })))
|
||||
return;
|
||||
|
||||
// ===== Modify the node in the XML file
|
||||
if (index <= 1)
|
||||
sheetsNode(xmlDocument()).prepend_move(sheetsNode(xmlDocument()).find_child_by_attribute("name", sheetName.c_str()));
|
||||
else if (index >= sheetCount())
|
||||
sheetsNode(xmlDocument()).append_move(sheetsNode(xmlDocument()).find_child_by_attribute("name", sheetName.c_str()));
|
||||
else {
|
||||
auto vec = std::vector<XMLNode>(sheetsNode(xmlDocument()).children().begin(), sheetsNode(xmlDocument()).children().end());
|
||||
auto existingSheet = vec[index - 1];
|
||||
if (indexOfSheet(sheetName) < index) {
|
||||
sheetsNode(xmlDocument())
|
||||
.insert_move_after(sheetsNode(xmlDocument()).find_child_by_attribute("name", sheetName.c_str()), existingSheet);
|
||||
}
|
||||
else if (indexOfSheet(sheetName) > index) {
|
||||
sheetsNode(xmlDocument())
|
||||
.insert_move_before(sheetsNode(xmlDocument()).find_child_by_attribute("name", sheetName.c_str()), existingSheet);
|
||||
}
|
||||
}
|
||||
|
||||
// ===== Updated defined names with worksheet scopes.
|
||||
for (auto& definedName : xmlDocument().document_element().child("definedNames").children()) {
|
||||
definedName.attribute("localSheetId").set_value(indexOfSheet(sheetName) - 1);
|
||||
}
|
||||
|
||||
// ===== Update the activeTab attribute.
|
||||
// unsigned int index = 0;
|
||||
// for (auto& item : getSheetsNode().children()) {
|
||||
// if (m_activeSheet == item) {
|
||||
// XmlDocument().first_child().child("bookViews").first_child().attribute("activeTab").set_value(index);
|
||||
// break;
|
||||
// }
|
||||
// index++;
|
||||
// }
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
unsigned int XLWorkbook::indexOfSheet(const std::string& sheetName) const
|
||||
{
|
||||
// ===== Iterate through sheet nodes. When a match is found, return the index;
|
||||
unsigned int index = 1;
|
||||
for (auto& sheet : sheetsNode(xmlDocument()).children()) {
|
||||
if (sheetName == sheet.attribute("name").value()) return index;
|
||||
index++;
|
||||
}
|
||||
|
||||
// ===== If a match is not found, throw an exception.
|
||||
throw XLInputError("Sheet does not exist");
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
XLSheetType XLWorkbook::typeOfSheet(const std::string& sheetName) const
|
||||
{
|
||||
if (!sheetExists(sheetName)) throw XLInputError("Sheet with name \"" + sheetName + "\" doesn't exist.");
|
||||
|
||||
if (worksheetExists(sheetName))
|
||||
return XLSheetType::Worksheet;
|
||||
return XLSheetType::Chartsheet;
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
XLSheetType XLWorkbook::typeOfSheet(unsigned int index) const
|
||||
{
|
||||
std::string name =
|
||||
std::vector<XMLNode>(sheetsNode(xmlDocument()).begin(), sheetsNode(xmlDocument()).end())[index - 1].attribute("name").as_string();
|
||||
return typeOfSheet(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
unsigned int XLWorkbook::sheetCount() const
|
||||
{
|
||||
return static_cast<unsigned int>(
|
||||
std::distance(sheetsNode(xmlDocument()).children().begin(), sheetsNode(xmlDocument()).children().end()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
unsigned int XLWorkbook::worksheetCount() const
|
||||
{
|
||||
return static_cast<unsigned int>(worksheetNames().size());
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
unsigned int XLWorkbook::chartsheetCount() const
|
||||
{
|
||||
return static_cast<unsigned int>(chartsheetNames().size());
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
std::vector<std::string> XLWorkbook::sheetNames() const
|
||||
{
|
||||
std::vector<std::string> results;
|
||||
|
||||
for (const auto& item : sheetsNode(xmlDocument()).children()) results.emplace_back(item.attribute("name").value());
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
std::vector<std::string> XLWorkbook::worksheetNames() const
|
||||
{
|
||||
std::vector<std::string> results;
|
||||
|
||||
for (const auto& item : sheetsNode(xmlDocument()).children()) {
|
||||
XLQuery query(XLQueryType::QuerySheetType);
|
||||
query.setParam("sheetID", std::string(item.attribute("r:id").value()));
|
||||
if (parentDoc().execQuery(query).result<XLContentType>() == XLContentType::Worksheet)
|
||||
results.emplace_back(item.attribute("name").value());
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
std::vector<std::string> XLWorkbook::chartsheetNames() const
|
||||
{
|
||||
std::vector<std::string> results;
|
||||
|
||||
for (const auto& item : sheetsNode(xmlDocument()).children()) {
|
||||
XLQuery query(XLQueryType::QuerySheetType);
|
||||
query.setParam("sheetID", std::string(item.attribute("r:id").value()));
|
||||
if (parentDoc().execQuery(query).result<XLContentType>() == XLContentType::Chartsheet)
|
||||
results.emplace_back(item.attribute("name").value());
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
bool XLWorkbook::sheetExists(const std::string& sheetName) const
|
||||
{
|
||||
return chartsheetExists(sheetName) || worksheetExists(sheetName);
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
bool XLWorkbook::worksheetExists(const std::string& sheetName) const
|
||||
{
|
||||
auto wksNames = worksheetNames();
|
||||
return std::find(wksNames.begin(), wksNames.end(), sheetName) != wksNames.end();
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
bool XLWorkbook::chartsheetExists(const std::string& sheetName) const
|
||||
{
|
||||
auto chsNames = chartsheetNames();
|
||||
return std::find(chsNames.begin(), chsNames.end(), sheetName) != chsNames.end();
|
||||
}
|
||||
|
||||
/**
|
||||
* @details The UpdateSheetName member function searches throug the usages of the old name and replaces with the
|
||||
* new sheet name.
|
||||
* @todo Currently, this function only searches through defined names. Consider using this function to update the
|
||||
* actual sheet name as well.
|
||||
*/
|
||||
void XLWorkbook::updateSheetReferences(const std::string& oldName, const std::string& newName)
|
||||
{
|
||||
// for (auto& sheet : m_sheets) {
|
||||
// if (sheet.sheetType == XLSheetType::WorkSheet)
|
||||
// Worksheet(sheet.sheetNode.attribute("name").getValue())->UpdateSheetName(oldName, newName);
|
||||
// }
|
||||
|
||||
// ===== Set up temporary variables
|
||||
std::string oldNameTemp = oldName;
|
||||
std::string newNameTemp = newName;
|
||||
std::string formula;
|
||||
|
||||
// ===== If the sheet name contains spaces, it should be enclosed in single quotes (')
|
||||
if (oldName.find(' ') != std::string::npos) oldNameTemp = "\'" + oldName + "\'";
|
||||
if (newName.find(' ') != std::string::npos) newNameTemp = "\'" + newName + "\'";
|
||||
|
||||
// ===== Ensure only sheet names are replaced (references to sheets always ends with a '!')
|
||||
oldNameTemp += '!';
|
||||
newNameTemp += '!';
|
||||
|
||||
// ===== Iterate through all defined names
|
||||
for (auto& definedName : xmlDocument().document_element().child("definedNames").children()) {
|
||||
formula = definedName.text().get();
|
||||
|
||||
// ===== Skip if formula contains a '[' and ']' (means that the defined refers to external workbook)
|
||||
if (formula.find('[') == std::string::npos && formula.find(']') == std::string::npos) {
|
||||
// ===== For all instances of the old sheet name in the formula, replace with the new name.
|
||||
while (formula.find(oldNameTemp) != std::string::npos) { // NOLINT
|
||||
formula.replace(formula.find(oldNameTemp), oldNameTemp.length(), newNameTemp);
|
||||
}
|
||||
definedName.text().set(formula.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
void XLWorkbook::setFullCalculationOnLoad()
|
||||
{
|
||||
auto calcPr = xmlDocument().document_element().child("calcPr");
|
||||
|
||||
auto getOrCreateAttribute = [&calcPr](const char * attributeName)
|
||||
{
|
||||
auto attr = calcPr.attribute(attributeName);
|
||||
if (!attr)
|
||||
attr = calcPr.append_attribute(attributeName);
|
||||
return attr;
|
||||
};
|
||||
|
||||
getOrCreateAttribute("forceFullCalc").set_value(true);
|
||||
getOrCreateAttribute("fullCalcOnLoad").set_value(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
bool XLWorkbook::sheetIsActive(const std::string& sheetRID) const
|
||||
{
|
||||
|
||||
auto activeTabAttribute = xmlDocument().document_element().child("bookViews").first_child().attribute("activeTab");
|
||||
auto activeTabIndex = (activeTabAttribute ? activeTabAttribute.as_uint() : 0);
|
||||
|
||||
unsigned int index = 0;
|
||||
for (const auto& item : sheetsNode(xmlDocument()).children()){
|
||||
if (std::string(item.attribute("r:id").value()) == sheetRID) break;
|
||||
++index;
|
||||
}
|
||||
|
||||
return index == activeTabIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
void XLWorkbook::setSheetActive(const std::string& sheetRID) {
|
||||
|
||||
unsigned int index = 0;
|
||||
for (const auto& item : sheetsNode(xmlDocument()).children()){
|
||||
if (std::string(item.attribute("r:id").value()) == sheetRID && std::string(item.attribute("state").value()) != "hidden") break;
|
||||
if (item == sheetsNode(xmlDocument()).last_child()) {
|
||||
index = 0;
|
||||
break;
|
||||
}
|
||||
++index;
|
||||
}
|
||||
|
||||
if (index == 0) {
|
||||
xmlDocument().document_element().child("bookViews").first_child().remove_attribute("activeTab");
|
||||
}
|
||||
else {
|
||||
if (xmlDocument().document_element().child("bookViews").first_child().attribute("activeTab") == XMLAttribute())
|
||||
xmlDocument().document_element().child("bookViews").first_child().append_attribute("activeTab");
|
||||
|
||||
xmlDocument().document_element().child("bookViews").first_child().attribute("activeTab").set_value(index);
|
||||
}
|
||||
}
|
||||
Vendored
+151
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
|
||||
____ ____ ___ ____ ____ ____ ___
|
||||
6MMMMb `MM( )M' `MM' 6MMMMb\`MM( )M'
|
||||
8P Y8 `MM. d' MM 6M' ` `MM. d'
|
||||
6M Mb __ ____ ____ ___ __ `MM. d' MM MM `MM. d'
|
||||
MM MM `M6MMMMb 6MMMMb `MM 6MMb `MM. d' MM YM. `MM. d'
|
||||
MM MM MM' `Mb 6M' `Mb MMM9 `Mb `MMd MM YMMMMb `MMd
|
||||
MM MM MM MM MM MM MM' MM dMM. MM `Mb dMM.
|
||||
MM MM MM MM MMMMMMMM MM MM d'`MM. MM MM d'`MM.
|
||||
YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM.
|
||||
8b d8 MM. ,M9 YM d9 MM MM d' `MM. MM / L ,M9 d' `MM.
|
||||
YMMMM9 MMYMMM9 YMMMM9 _MM_ _MM_M(_ _)MM_ _MMMMMMM MYMMMM9 _M(_ _)MM_
|
||||
MM
|
||||
MM
|
||||
_MM_
|
||||
|
||||
Copyright (c) 2018, Kenneth Troldal Balslev
|
||||
|
||||
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.
|
||||
- Neither the name of the author nor the
|
||||
names of any 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 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.
|
||||
|
||||
*/
|
||||
|
||||
// ===== External Includes ===== //
|
||||
#include <pugixml.hpp>
|
||||
|
||||
// ===== OpenXLSX Includes ===== //
|
||||
#include "XLDocument.hpp"
|
||||
#include "XLXmlData.hpp"
|
||||
|
||||
using namespace OpenXLSX;
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
XLXmlData::XLXmlData(OpenXLSX::XLDocument* parentDoc, const std::string& xmlPath, const std::string& xmlId, OpenXLSX::XLContentType xmlType)
|
||||
: m_parentDoc(parentDoc),
|
||||
m_xmlPath(xmlPath),
|
||||
m_xmlID(xmlId),
|
||||
m_xmlType(xmlType),
|
||||
m_xmlDoc(std::make_unique<XMLDocument>())
|
||||
{
|
||||
m_xmlDoc->reset();
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
XLXmlData::~XLXmlData() = default;
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
void XLXmlData::setRawData(const std::string& data)
|
||||
{
|
||||
m_xmlDoc->load_string(data.c_str(), pugi::parse_default | pugi::parse_ws_pcdata);
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
std::string XLXmlData::getRawData() const
|
||||
{
|
||||
std::ostringstream ostr;
|
||||
getXmlDocument()->save(ostr, "", pugi::format_raw);
|
||||
return ostr.str();
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
XLDocument* XLXmlData::getParentDoc()
|
||||
{
|
||||
return m_parentDoc;
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
const XLDocument* XLXmlData::getParentDoc() const
|
||||
{
|
||||
return m_parentDoc;
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
std::string XLXmlData::getXmlPath() const
|
||||
{
|
||||
return m_xmlPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
std::string XLXmlData::getXmlID() const
|
||||
{
|
||||
return m_xmlID;
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
XLContentType XLXmlData::getXmlType() const
|
||||
{
|
||||
return m_xmlType;
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
XMLDocument* XLXmlData::getXmlDocument()
|
||||
{
|
||||
if (!m_xmlDoc->document_element())
|
||||
m_xmlDoc->load_string(m_parentDoc->extractXmlFromArchive(m_xmlPath).c_str(), pugi::parse_default | pugi::parse_ws_pcdata);
|
||||
|
||||
return m_xmlDoc.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
const XMLDocument* XLXmlData::getXmlDocument() const
|
||||
{
|
||||
if (!m_xmlDoc->document_element())
|
||||
m_xmlDoc->load_string(m_parentDoc->extractXmlFromArchive(m_xmlPath).c_str(), pugi::parse_default | pugi::parse_ws_pcdata);
|
||||
|
||||
return m_xmlDoc.get();
|
||||
}
|
||||
Vendored
+123
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
|
||||
____ ____ ___ ____ ____ ____ ___
|
||||
6MMMMb `MM( )M' `MM' 6MMMMb\`MM( )M'
|
||||
8P Y8 `MM. d' MM 6M' ` `MM. d'
|
||||
6M Mb __ ____ ____ ___ __ `MM. d' MM MM `MM. d'
|
||||
MM MM `M6MMMMb 6MMMMb `MM 6MMb `MM. d' MM YM. `MM. d'
|
||||
MM MM MM' `Mb 6M' `Mb MMM9 `Mb `MMd MM YMMMMb `MMd
|
||||
MM MM MM MM MM MM MM' MM dMM. MM `Mb dMM.
|
||||
MM MM MM MM MMMMMMMM MM MM d'`MM. MM MM d'`MM.
|
||||
YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM.
|
||||
8b d8 MM. ,M9 YM d9 MM MM d' `MM. MM / L ,M9 d' `MM.
|
||||
YMMMM9 MMYMMM9 YMMMM9 _MM_ _MM_M(_ _)MM_ _MMMMMMM MYMMMM9 _M(_ _)MM_
|
||||
MM
|
||||
MM
|
||||
_MM_
|
||||
|
||||
Copyright (c) 2018, Kenneth Troldal Balslev
|
||||
|
||||
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.
|
||||
- Neither the name of the author nor the
|
||||
names of any 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 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.
|
||||
|
||||
*/
|
||||
|
||||
// ===== External Includes ===== //
|
||||
#include <pugixml.hpp>
|
||||
|
||||
// ===== OpenXLSX Includes ===== //
|
||||
#include "XLDocument.hpp"
|
||||
#include "XLXmlFile.hpp"
|
||||
|
||||
using namespace OpenXLSX;
|
||||
|
||||
/**
|
||||
* @details The constructor creates a new object with the parent XLDocument and the file path as input, with
|
||||
* an optional input being a std::string with the XML data. If the XML data is provided by a string, any file with
|
||||
* the same path in the .zip file will be overwritten upon saving of the document. If no xmlData is provided,
|
||||
* the data will be read from the .zip file, using the given path.
|
||||
*/
|
||||
XLXmlFile::XLXmlFile(XLXmlData* xmlData) : m_xmlData(xmlData) {}
|
||||
|
||||
XLXmlFile::~XLXmlFile() = default;
|
||||
|
||||
/**
|
||||
* @details This method sets the XML data with a std::string as input. The underlying XMLDocument reads the data.
|
||||
* When envoking the load_string method in PugiXML, the flag 'parse_ws_pcdata' is passed along with the default flags.
|
||||
* This will enable parsing of whitespace characters. If not set, Excel cells with only spaces will be returned as
|
||||
* empty strings, which is not what we want. The downside is that whitespace characters such as \\n and \\t in the
|
||||
* input xml file may mess up the parsing.
|
||||
*/
|
||||
void XLXmlFile::setXmlData(const std::string& xmlData)
|
||||
{
|
||||
m_xmlData->setRawData(xmlData);
|
||||
}
|
||||
|
||||
/**
|
||||
* @details This method retrieves the underlying XML data as a std::string.
|
||||
*/
|
||||
std::string XLXmlFile::xmlData() const
|
||||
{
|
||||
return m_xmlData->getRawData();
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
const XLDocument& XLXmlFile::parentDoc() const
|
||||
{
|
||||
return *m_xmlData->getParentDoc();
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
XLDocument& XLXmlFile::parentDoc()
|
||||
{
|
||||
return *m_xmlData->getParentDoc();
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
std::string XLXmlFile::relationshipID() const
|
||||
{
|
||||
return m_xmlData->getXmlID();
|
||||
}
|
||||
|
||||
/**
|
||||
* @details This method returns a pointer to the underlying XMLDocument resource.
|
||||
*/
|
||||
XMLDocument& XLXmlFile::xmlDocument()
|
||||
{
|
||||
return const_cast<XMLDocument&>(static_cast<const XLXmlFile*>(this)->xmlDocument()); // NOLINT
|
||||
}
|
||||
|
||||
/**
|
||||
* @details This method returns a pointer to the underlying XMLDocument resource as const.
|
||||
*/
|
||||
const XMLDocument& XLXmlFile::xmlDocument() const
|
||||
{
|
||||
return *m_xmlData->getXmlDocument();
|
||||
}
|
||||
+138
@@ -0,0 +1,138 @@
|
||||
/*
|
||||
|
||||
____ ____ ___ ____ ____ ____ ___
|
||||
6MMMMb `MM( )M' `MM' 6MMMMb\`MM( )M'
|
||||
8P Y8 `MM. d' MM 6M' ` `MM. d'
|
||||
6M Mb __ ____ ____ ___ __ `MM. d' MM MM `MM. d'
|
||||
MM MM `M6MMMMb 6MMMMb `MM 6MMb `MM. d' MM YM. `MM. d'
|
||||
MM MM MM' `Mb 6M' `Mb MMM9 `Mb `MMd MM YMMMMb `MMd
|
||||
MM MM MM MM MM MM MM' MM dMM. MM `Mb dMM.
|
||||
MM MM MM MM MMMMMMMM MM MM d'`MM. MM MM d'`MM.
|
||||
YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM.
|
||||
8b d8 MM. ,M9 YM d9 MM MM d' `MM. MM / L ,M9 d' `MM.
|
||||
YMMMM9 MMYMMM9 YMMMM9 _MM_ _MM_M(_ _)MM_ _MMMMMMM MYMMMM9 _M(_ _)MM_
|
||||
MM
|
||||
MM
|
||||
_MM_
|
||||
|
||||
Copyright (c) 2018, Kenneth Troldal Balslev
|
||||
|
||||
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.
|
||||
- Neither the name of the author nor the
|
||||
names of any 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 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.
|
||||
|
||||
*/
|
||||
|
||||
// ===== External Includes ===== //
|
||||
#include <zippy.hpp>
|
||||
|
||||
// ===== OpenXLSX Includes ===== //
|
||||
#include "XLZipArchive.hpp"
|
||||
|
||||
using namespace OpenXLSX;
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
OpenXLSX::XLZipArchive::XLZipArchive() : m_archive(nullptr) {}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
XLZipArchive::~XLZipArchive() = default;
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
XLZipArchive::operator bool() const
|
||||
{
|
||||
return isValid();
|
||||
}
|
||||
|
||||
bool XLZipArchive::isValid() const { return m_archive != nullptr; }
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
bool OpenXLSX::XLZipArchive::isOpen() const
|
||||
{
|
||||
return m_archive && m_archive->IsOpen();
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
void OpenXLSX::XLZipArchive::open(const std::string& fileName)
|
||||
{
|
||||
m_archive = std::make_shared<Zippy::ZipArchive>();
|
||||
m_archive->Open(fileName);
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
void OpenXLSX::XLZipArchive::close()
|
||||
{
|
||||
m_archive->Close();
|
||||
m_archive = nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
void OpenXLSX::XLZipArchive::save(const std::string& path)
|
||||
{
|
||||
m_archive->Save(path);
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
void OpenXLSX::XLZipArchive::addEntry(const std::string& name, const std::string& data)
|
||||
{
|
||||
m_archive->AddEntry(name, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
void OpenXLSX::XLZipArchive::deleteEntry(const std::string& entryName)
|
||||
{
|
||||
m_archive->DeleteEntry(entryName);
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
std::string OpenXLSX::XLZipArchive::getEntry(const std::string& name)
|
||||
{
|
||||
return m_archive->GetEntry(name).GetDataAsString();
|
||||
}
|
||||
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
bool OpenXLSX::XLZipArchive::hasEntry(const std::string& entryName)
|
||||
{
|
||||
return m_archive->HasEntry(entryName);
|
||||
}
|
||||
+100
@@ -0,0 +1,100 @@
|
||||
//
|
||||
// Created by Kenneth Balslev on 24/08/2020.
|
||||
//
|
||||
|
||||
#ifndef OPENXLSX_XLUTILITIES_HPP
|
||||
#define OPENXLSX_XLUTILITIES_HPP
|
||||
|
||||
#include <fstream>
|
||||
#include <pugixml.hpp>
|
||||
|
||||
#include "XLCellReference.hpp"
|
||||
#include "XLXmlParser.hpp"
|
||||
|
||||
namespace OpenXLSX
|
||||
{
|
||||
/**
|
||||
* @details
|
||||
*/
|
||||
inline XMLNode getRowNode(XMLNode sheetDataNode, uint32_t rowNumber)
|
||||
{
|
||||
// ===== If the requested node is beyond the current max node, append a new node to the end.
|
||||
auto result = XMLNode();
|
||||
if (!sheetDataNode.last_child() || rowNumber > sheetDataNode.last_child().attribute("r").as_ullong()) {
|
||||
result = sheetDataNode.append_child("row");
|
||||
|
||||
result.append_attribute("r") = rowNumber;
|
||||
// result.append_attribute("x14ac:dyDescent") = "0.2";
|
||||
// result.append_attribute("spans") = "1:1";
|
||||
}
|
||||
|
||||
// ===== If the requested node is closest to the end, start from the end and search backwards
|
||||
else if (sheetDataNode.last_child().attribute("r").as_ullong() - rowNumber < rowNumber) {
|
||||
result = sheetDataNode.last_child();
|
||||
while (result.attribute("r").as_ullong() > rowNumber) result = result.previous_sibling();
|
||||
if (result.attribute("r").as_ullong() < rowNumber) {
|
||||
result = sheetDataNode.insert_child_after("row", result);
|
||||
|
||||
result.append_attribute("r") = rowNumber;
|
||||
// result.append_attribute("x14ac:dyDescent") = "0.2";
|
||||
// result.append_attribute("spans") = "1:1";
|
||||
}
|
||||
}
|
||||
|
||||
// ===== Otherwise, start from the beginning
|
||||
else {
|
||||
result = sheetDataNode.first_child();
|
||||
while (result.attribute("r").as_ullong() < rowNumber) result = result.next_sibling();
|
||||
if (result.attribute("r").as_ullong() > rowNumber) {
|
||||
result = sheetDataNode.insert_child_before("row", result);
|
||||
|
||||
result.append_attribute("r") = rowNumber;
|
||||
// result.append_attribute("x14ac:dyDescent") = "0.2";
|
||||
// result.append_attribute("spans") = "1:1";
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Retrieve the xml node representing the cell at the given row and column. If the node doesn't
|
||||
* exist, it will be created.
|
||||
* @param rowNode The row node under which to find the cell.
|
||||
* @param columnNumber The column at which to find the cell.
|
||||
* @return The xml node representing the requested cell.
|
||||
*/
|
||||
inline XMLNode getCellNode(XMLNode rowNode, uint16_t columnNumber)
|
||||
{
|
||||
auto cellNode = XMLNode();
|
||||
auto cellRef = XLCellReference(rowNode.attribute("r").as_uint(), columnNumber);
|
||||
|
||||
// ===== If there are no cells in the current row, or the requested cell is beyond the last cell in the row...
|
||||
if (rowNode.last_child().empty() || XLCellReference(rowNode.last_child().attribute("r").value()).column() < columnNumber) {
|
||||
rowNode.append_child("c").append_attribute("r").set_value(cellRef.address().c_str());
|
||||
cellNode = rowNode.last_child();
|
||||
}
|
||||
// ===== If the requested node is closest to the end, start from the end and search backwards...
|
||||
else if (XLCellReference(rowNode.last_child().attribute("r").value()).column() - columnNumber < columnNumber) {
|
||||
cellNode = rowNode.last_child();
|
||||
while (XLCellReference(cellNode.attribute("r").value()).column() > columnNumber) cellNode = cellNode.previous_sibling();
|
||||
if (XLCellReference(cellNode.attribute("r").value()).column() < columnNumber) {
|
||||
cellNode = rowNode.insert_child_after("c", cellNode);
|
||||
cellNode.append_attribute("r").set_value(cellRef.address().c_str());
|
||||
}
|
||||
}
|
||||
// ===== Otherwise, start from the beginning
|
||||
else {
|
||||
cellNode = rowNode.first_child();
|
||||
while (XLCellReference(cellNode.attribute("r").value()).column() < columnNumber) cellNode = cellNode.next_sibling();
|
||||
if (XLCellReference(cellNode.attribute("r").value()).column() > columnNumber) {
|
||||
cellNode = rowNode.insert_child_before("c", cellNode);
|
||||
cellNode.append_attribute("r").set_value(cellRef.address().c_str());
|
||||
}
|
||||
}
|
||||
return cellNode;
|
||||
}
|
||||
|
||||
} // namespace OpenXLSX
|
||||
|
||||
#endif // OPENXLSX_XLUTILITIES_HPP
|
||||
Reference in New Issue
Block a user