初始化内容

This commit is contained in:
2026-09-16 14:07:40 +08:00
parent 6934b390bf
commit 4f643c1e7c
18350 changed files with 6088489 additions and 305 deletions
+322
View File
@@ -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}
)
+63
View File
@@ -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
+1
View File
@@ -0,0 +1 @@
include("${CMAKE_CURRENT_LIST_DIR}/OpenXLSXTargets.cmake")
+162
View File
@@ -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
View File
@@ -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
+35
View File
@@ -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
View File
@@ -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
+99
View File
@@ -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
+16
View File
@@ -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
+76
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
+88
View File
@@ -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
+143
View File
@@ -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
+44
View File
@@ -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
View File
@@ -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
+475
View File
@@ -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
+36
View File
@@ -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
View File
@@ -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.
*/
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+345
View File
@@ -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
+231
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
+230
View File
@@ -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
+139
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
+365
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
+496
View File
@@ -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
+427
View File
@@ -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
View File
@@ -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
+737
View File
@@ -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
View File
@@ -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
+202
View File
@@ -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
+163
View File
@@ -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
View File
@@ -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
View File
@@ -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
+215
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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("");
}
}
+216
View File
@@ -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());
}
+125
View File
@@ -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
View File
@@ -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
View File
@@ -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
File diff suppressed because it is too large Load Diff
+190
View File
@@ -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
View File
@@ -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
View File
@@ -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;
}
+558
View File
@@ -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
+533
View File
@@ -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
View File
@@ -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("");
}
+626
View File
@@ -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
View File
@@ -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);
}
}
+151
View File
@@ -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();
}
+123
View File
@@ -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
View File
@@ -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
View File
@@ -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