mirror of
https://github.com/tfussell/xlnt.git
synced 2024-03-22 13:11:17 +08:00
restructure project
This commit is contained in:
parent
b30bfabe49
commit
3e78b7e49b
|
@ -2,11 +2,6 @@ solution "xlnt"
|
||||||
configurations { "Debug", "Release" }
|
configurations { "Debug", "Release" }
|
||||||
platforms { "x64" }
|
platforms { "x64" }
|
||||||
location ("./" .. _ACTION)
|
location ("./" .. _ACTION)
|
||||||
configuration "not windows"
|
|
||||||
buildoptions {
|
|
||||||
"-std=c++11",
|
|
||||||
"-Wno-unknown-pragmas"
|
|
||||||
}
|
|
||||||
configuration "Debug"
|
configuration "Debug"
|
||||||
flags { "Symbols" }
|
flags { "Symbols" }
|
||||||
optimize "Off"
|
optimize "Off"
|
||||||
|
@ -24,7 +19,6 @@ project "xlnt.test"
|
||||||
"../third-party/zlib",
|
"../third-party/zlib",
|
||||||
"../third-party/zlib/contrib/minizip"
|
"../third-party/zlib/contrib/minizip"
|
||||||
}
|
}
|
||||||
defines { "WIN32" }
|
|
||||||
files {
|
files {
|
||||||
"../source/tests/**.h",
|
"../source/tests/**.h",
|
||||||
"../source/tests/runner-autogen.cpp"
|
"../source/tests/runner-autogen.cpp"
|
||||||
|
@ -45,32 +39,30 @@ project "xlnt.test"
|
||||||
configuration "windows"
|
configuration "windows"
|
||||||
defines { "WIN32" }
|
defines { "WIN32" }
|
||||||
links { "Shlwapi" }
|
links { "Shlwapi" }
|
||||||
|
configuration "not windows"
|
||||||
|
buildoptions {
|
||||||
|
"-std=c++11",
|
||||||
|
"-Wno-unknown-pragmas"
|
||||||
|
}
|
||||||
|
|
||||||
project "xlnt"
|
project "xlnt"
|
||||||
kind "StaticLib"
|
kind "StaticLib"
|
||||||
language "C++"
|
language "C++"
|
||||||
warnings "Extra"
|
warnings "Extra"
|
||||||
targetdir "../lib/"
|
targetdir "../lib/"
|
||||||
|
links {
|
||||||
|
"zlib",
|
||||||
|
"pugixml"
|
||||||
|
}
|
||||||
includedirs {
|
includedirs {
|
||||||
"../include/xlnt",
|
|
||||||
"../third-party/pugixml/src",
|
|
||||||
"../source/",
|
"../source/",
|
||||||
|
"../third-party/pugixml/src",
|
||||||
"../third-party/zlib/",
|
"../third-party/zlib/",
|
||||||
"../third-party/zlib/contrib/minizip"
|
"../third-party/zlib/contrib/minizip"
|
||||||
}
|
}
|
||||||
files {
|
files {
|
||||||
"../source/**.cpp",
|
"../source/*.cpp",
|
||||||
"../source/**.h",
|
"../source/*.h"
|
||||||
"../include/**.h",
|
|
||||||
"../third-party/pugixml/src/pugixml.cpp",
|
|
||||||
"../third-party/zlib/*.c",
|
|
||||||
"../third-party/zlib/contrib/minizip/*.c"
|
|
||||||
}
|
|
||||||
excludes {
|
|
||||||
"../source/tests/**.cpp",
|
|
||||||
"../source/tests/**.h",
|
|
||||||
"../third-party/zlib/contrib/minizip/miniunz.c",
|
|
||||||
"../third-party/zlib/contrib/minizip/minizip.c"
|
|
||||||
}
|
}
|
||||||
flags {
|
flags {
|
||||||
"Unicode",
|
"Unicode",
|
||||||
|
@ -82,5 +74,56 @@ project "xlnt"
|
||||||
flags { "FatalWarnings" }
|
flags { "FatalWarnings" }
|
||||||
configuration "windows"
|
configuration "windows"
|
||||||
defines { "WIN32" }
|
defines { "WIN32" }
|
||||||
configuration "../third-party/zlib/*.c"
|
configuration "not windows"
|
||||||
|
buildoptions {
|
||||||
|
"-std=c++11",
|
||||||
|
"-Wno-unknown-pragmas"
|
||||||
|
}
|
||||||
|
|
||||||
|
project "pugixml"
|
||||||
|
kind "StaticLib"
|
||||||
|
language "C++"
|
||||||
warnings "Off"
|
warnings "Off"
|
||||||
|
targetdir "../lib/"
|
||||||
|
includedirs {
|
||||||
|
"../third-party/pugixml/src"
|
||||||
|
}
|
||||||
|
files {
|
||||||
|
"../third-party/pugixml/src/pugixml.cpp"
|
||||||
|
}
|
||||||
|
flags {
|
||||||
|
"Unicode",
|
||||||
|
"NoEditAndContinue",
|
||||||
|
"NoManifest",
|
||||||
|
"NoPCH"
|
||||||
|
}
|
||||||
|
configuration "windows"
|
||||||
|
defines { "WIN32" }
|
||||||
|
|
||||||
|
project "zlib"
|
||||||
|
kind "StaticLib"
|
||||||
|
language "C"
|
||||||
|
warnings "Off"
|
||||||
|
targetdir "../lib/"
|
||||||
|
includedirs {
|
||||||
|
"../third-party/zlib/",
|
||||||
|
"../third-party/zlib/contrib/minizip"
|
||||||
|
}
|
||||||
|
files {
|
||||||
|
"../third-party/zlib/*.c",
|
||||||
|
"../third-party/zlib/contrib/minizip/*.c"
|
||||||
|
}
|
||||||
|
excludes {
|
||||||
|
"../third-party/zlib/contrib/minizip/miniunz.c",
|
||||||
|
"../third-party/zlib/contrib/minizip/minizip.c",
|
||||||
|
"../third-party/zlib/contrib/minizip/iowin32.c",
|
||||||
|
"../third-party/zlib/gz*.c"
|
||||||
|
}
|
||||||
|
flags {
|
||||||
|
"Unicode",
|
||||||
|
"NoEditAndContinue",
|
||||||
|
"NoManifest",
|
||||||
|
"NoPCH"
|
||||||
|
}
|
||||||
|
configuration "windows"
|
||||||
|
defines { "WIN32" }
|
||||||
|
|
474
source/cell.cpp
Normal file
474
source/cell.cpp
Normal file
|
@ -0,0 +1,474 @@
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
#include "cell.h"
|
||||||
|
|
||||||
|
#include "reference.h"
|
||||||
|
#include "relationship.h"
|
||||||
|
#include "worksheet.h"
|
||||||
|
|
||||||
|
namespace xlnt {
|
||||||
|
|
||||||
|
struct worksheet_struct;
|
||||||
|
|
||||||
|
const xlnt::color xlnt::color::black(0);
|
||||||
|
const xlnt::color xlnt::color::white(1);
|
||||||
|
|
||||||
|
struct cell_struct
|
||||||
|
{
|
||||||
|
cell_struct(worksheet_struct *ws, int column, int row)
|
||||||
|
: type(cell::type::null), parent_worksheet(ws),
|
||||||
|
column(column), row(row),
|
||||||
|
hyperlink_rel("invalid", "")
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string to_string() const;
|
||||||
|
|
||||||
|
cell::type type;
|
||||||
|
|
||||||
|
union
|
||||||
|
{
|
||||||
|
long double numeric_value;
|
||||||
|
bool bool_value;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
std::string error_value;
|
||||||
|
tm date_value;
|
||||||
|
std::string string_value;
|
||||||
|
std::string formula_value;
|
||||||
|
worksheet_struct *parent_worksheet;
|
||||||
|
int column;
|
||||||
|
int row;
|
||||||
|
style style;
|
||||||
|
relationship hyperlink_rel;
|
||||||
|
bool merged;
|
||||||
|
};
|
||||||
|
|
||||||
|
const std::unordered_map<std::string, int> cell::ErrorCodes =
|
||||||
|
{
|
||||||
|
{"#NULL!", 0},
|
||||||
|
{"#DIV/0!", 1},
|
||||||
|
{"#VALUE!", 2},
|
||||||
|
{"#REF!", 3},
|
||||||
|
{"#NAME?", 4},
|
||||||
|
{"#NUM!", 5},
|
||||||
|
{"#N/A!", 6}
|
||||||
|
};
|
||||||
|
|
||||||
|
cell::cell() : root_(nullptr)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
cell::cell(worksheet &worksheet, const std::string &column, int row) : root_(nullptr)
|
||||||
|
{
|
||||||
|
cell self = worksheet.get_cell(column + std::to_string(row));
|
||||||
|
root_ = self.root_;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
cell::cell(worksheet &worksheet, const std::string &column, int row, const std::string &initial_value) : root_(nullptr)
|
||||||
|
{
|
||||||
|
cell self = worksheet.get_cell(column + std::to_string(row));
|
||||||
|
root_ = self.root_;
|
||||||
|
*this = initial_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
cell::cell(cell_struct *root) : root_(root)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string cell::get_value() const
|
||||||
|
{
|
||||||
|
switch(root_->type)
|
||||||
|
{
|
||||||
|
case type::string:
|
||||||
|
return root_->string_value;
|
||||||
|
case type::numeric:
|
||||||
|
return std::to_string(root_->numeric_value);
|
||||||
|
case type::formula:
|
||||||
|
return root_->formula_value;
|
||||||
|
case type::error:
|
||||||
|
return root_->error_value;
|
||||||
|
case type::null:
|
||||||
|
return "";
|
||||||
|
case type::date:
|
||||||
|
return "00:00:00";
|
||||||
|
case type::boolean:
|
||||||
|
return root_->bool_value ? "TRUE" : "FALSE";
|
||||||
|
default:
|
||||||
|
throw std::runtime_error("bad enum");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int cell::get_row() const
|
||||||
|
{
|
||||||
|
return root_->row + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string cell::get_column() const
|
||||||
|
{
|
||||||
|
return cell_reference::column_string_from_index(root_->column + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> split_string(const std::string &string, char delim = ' ')
|
||||||
|
{
|
||||||
|
std::stringstream ss(string);
|
||||||
|
std::string part;
|
||||||
|
std::vector<std::string> parts;
|
||||||
|
while(std::getline(ss, part, delim))
|
||||||
|
{
|
||||||
|
parts.push_back(part);
|
||||||
|
}
|
||||||
|
return parts;
|
||||||
|
}
|
||||||
|
|
||||||
|
cell::type cell::data_type_for_value(const std::string &value)
|
||||||
|
{
|
||||||
|
if(value.empty())
|
||||||
|
{
|
||||||
|
return type::null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(value[0] == '=')
|
||||||
|
{
|
||||||
|
return type::formula;
|
||||||
|
}
|
||||||
|
else if(value[0] == '0')
|
||||||
|
{
|
||||||
|
if(value.length() > 1)
|
||||||
|
{
|
||||||
|
if(value[1] == '.' || (value.length() > 2 && (value[1] == 'e' || value[1] == 'E')))
|
||||||
|
{
|
||||||
|
auto first_non_number = std::find_if(value.begin() + 2, value.end(),
|
||||||
|
[](char c) { return !std::isdigit(c, std::locale::classic()); });
|
||||||
|
if(first_non_number == value.end())
|
||||||
|
{
|
||||||
|
return type::numeric;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
auto split = split_string(value, ':');
|
||||||
|
if(split.size() == 2 || split.size() == 3)
|
||||||
|
{
|
||||||
|
for(auto part : split)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
std::stoi(part);
|
||||||
|
}
|
||||||
|
catch(std::invalid_argument)
|
||||||
|
{
|
||||||
|
return type::string;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return type::date;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return type::string;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return type::numeric;
|
||||||
|
}
|
||||||
|
else if(value[0] == '#')
|
||||||
|
{
|
||||||
|
return type::error;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
char *p;
|
||||||
|
strtod(value.c_str(), &p);
|
||||||
|
if(*p != 0)
|
||||||
|
{
|
||||||
|
static const std::vector<std::string> possible_booleans = {"TRUE", "true", "FALSE", "false"};
|
||||||
|
if(std::find(possible_booleans.begin(), possible_booleans.end(), value) != possible_booleans.end())
|
||||||
|
{
|
||||||
|
return type::boolean;
|
||||||
|
}
|
||||||
|
return type::string;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return type::numeric;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void cell::set_explicit_value(const std::string &value, type data_type)
|
||||||
|
{
|
||||||
|
root_->type = data_type;
|
||||||
|
switch(data_type)
|
||||||
|
{
|
||||||
|
case type::formula: root_->formula_value = value; return;
|
||||||
|
case type::date: root_->date_value.tm_hour = std::stoi(value); return;
|
||||||
|
case type::error: root_->error_value = value; return;
|
||||||
|
case type::boolean: root_->bool_value = value == "true"; return;
|
||||||
|
case type::null: return;
|
||||||
|
case type::numeric: root_->numeric_value = std::stod(value); return;
|
||||||
|
case type::string: root_->string_value = value; return;
|
||||||
|
default: throw std::runtime_error("bad enum");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void cell::set_hyperlink(const std::string &url)
|
||||||
|
{
|
||||||
|
root_->type = type::hyperlink;
|
||||||
|
root_->hyperlink_rel = worksheet(root_->parent_worksheet).create_relationship("hyperlink", url);
|
||||||
|
}
|
||||||
|
|
||||||
|
void cell::set_merged(bool merged)
|
||||||
|
{
|
||||||
|
root_->merged = merged;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cell::get_merged() const
|
||||||
|
{
|
||||||
|
return root_->merged;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cell::bind_value()
|
||||||
|
{
|
||||||
|
root_->type = type::null;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cell::bind_value(int value)
|
||||||
|
{
|
||||||
|
root_->type = type::numeric;
|
||||||
|
root_->numeric_value = value;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cell::bind_value(double value)
|
||||||
|
{
|
||||||
|
root_->type = type::numeric;
|
||||||
|
root_->numeric_value = value;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cell::bind_value(const std::string &value)
|
||||||
|
{
|
||||||
|
//Given a value, infer type and display options.
|
||||||
|
root_->type = data_type_for_value(value);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cell::bind_value(const char *value)
|
||||||
|
{
|
||||||
|
return bind_value(std::string(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cell::bind_value(bool value)
|
||||||
|
{
|
||||||
|
root_->type = type::boolean;
|
||||||
|
root_->bool_value = value;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cell::bind_value(const tm &value)
|
||||||
|
{
|
||||||
|
root_->type = type::date;
|
||||||
|
root_->date_value = value;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cell::is_date() const
|
||||||
|
{
|
||||||
|
return root_->type == type::date;
|
||||||
|
}
|
||||||
|
|
||||||
|
cell_reference cell::get_reference() const
|
||||||
|
{
|
||||||
|
return {root_->column, root_->row};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string cell::get_hyperlink_rel_id() const
|
||||||
|
{
|
||||||
|
return root_->hyperlink_rel.get_id();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cell::operator==(std::nullptr_t) const
|
||||||
|
{
|
||||||
|
return root_ == nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cell::operator==(int comparand) const
|
||||||
|
{
|
||||||
|
return root_->type == type::numeric && root_->numeric_value == comparand;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cell::operator==(double comparand) const
|
||||||
|
{
|
||||||
|
return root_->type == type::numeric && root_->numeric_value == comparand;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cell::operator==(const std::string &comparand) const
|
||||||
|
{
|
||||||
|
if(root_->type == type::hyperlink)
|
||||||
|
{
|
||||||
|
return root_->hyperlink_rel.get_target_uri() == comparand;
|
||||||
|
}
|
||||||
|
if(root_->type == type::string)
|
||||||
|
{
|
||||||
|
return root_->string_value == comparand;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cell::operator==(const char *comparand) const
|
||||||
|
{
|
||||||
|
return *this == std::string(comparand);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cell::operator==(const tm &comparand) const
|
||||||
|
{
|
||||||
|
return root_->type == cell::type::date && root_->date_value.tm_hour == comparand.tm_hour;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(int comparand, const xlnt::cell &cell)
|
||||||
|
{
|
||||||
|
return cell == comparand;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(const char *comparand, const xlnt::cell &cell)
|
||||||
|
{
|
||||||
|
return cell == comparand;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(const std::string &comparand, const xlnt::cell &cell)
|
||||||
|
{
|
||||||
|
return cell == comparand;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(const tm &comparand, const xlnt::cell &cell)
|
||||||
|
{
|
||||||
|
return cell == comparand;
|
||||||
|
}
|
||||||
|
|
||||||
|
style &cell::get_style()
|
||||||
|
{
|
||||||
|
return root_->style;
|
||||||
|
}
|
||||||
|
|
||||||
|
const style &cell::get_style() const
|
||||||
|
{
|
||||||
|
return root_->style;
|
||||||
|
}
|
||||||
|
|
||||||
|
xlnt::cell::type cell::get_data_type() const
|
||||||
|
{
|
||||||
|
return root_->type;
|
||||||
|
}
|
||||||
|
|
||||||
|
xlnt::cell cell::get_offset(int row_offset, int column_offset)
|
||||||
|
{
|
||||||
|
worksheet parent_wrapper(root_->parent_worksheet);
|
||||||
|
cell_reference ref(root_->column + column_offset, root_->row + row_offset);
|
||||||
|
return parent_wrapper[ref];
|
||||||
|
}
|
||||||
|
|
||||||
|
cell &cell::operator=(const cell &rhs)
|
||||||
|
{
|
||||||
|
root_ = rhs.root_;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
cell &cell::operator=(int value)
|
||||||
|
{
|
||||||
|
root_->type = type::numeric;
|
||||||
|
root_->numeric_value = value;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
cell &cell::operator=(double value)
|
||||||
|
{
|
||||||
|
root_->type = type::numeric;
|
||||||
|
root_->numeric_value = value;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
cell &cell::operator=(bool value)
|
||||||
|
{
|
||||||
|
root_->type = type::boolean;
|
||||||
|
root_->bool_value = value;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
cell &cell::operator=(const std::string &value)
|
||||||
|
{
|
||||||
|
root_->type = data_type_for_value(value);
|
||||||
|
|
||||||
|
switch(root_->type)
|
||||||
|
{
|
||||||
|
case type::date:
|
||||||
|
{
|
||||||
|
root_->date_value = std::tm();
|
||||||
|
auto split = split_string(value, ':');
|
||||||
|
root_->date_value.tm_hour = std::stoi(split[0]);
|
||||||
|
root_->date_value.tm_min = std::stoi(split[1]);
|
||||||
|
if(split.size() > 2)
|
||||||
|
{
|
||||||
|
root_->date_value.tm_sec = std::stoi(split[2]);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case type::formula:
|
||||||
|
root_->formula_value = value;
|
||||||
|
break;
|
||||||
|
case type::numeric:
|
||||||
|
root_->numeric_value = std::stod(value);
|
||||||
|
break;
|
||||||
|
case type::boolean:
|
||||||
|
root_->bool_value = value == "TRUE" || value == "true";
|
||||||
|
break;
|
||||||
|
case type::error:
|
||||||
|
root_->error_value = value;
|
||||||
|
break;
|
||||||
|
case type::string:
|
||||||
|
root_->string_value = value;
|
||||||
|
break;
|
||||||
|
case type::null:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw std::runtime_error("bad enum");
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
cell &cell::operator=(const char *value)
|
||||||
|
{
|
||||||
|
return *this = std::string(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
cell &cell::operator=(const tm &value)
|
||||||
|
{
|
||||||
|
root_->type = type::date;
|
||||||
|
root_->date_value = value;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string cell::to_string() const
|
||||||
|
{
|
||||||
|
return root_->to_string();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string cell_struct::to_string() const
|
||||||
|
{
|
||||||
|
return "<Cell " + worksheet(parent_worksheet).get_title() + "." + cell_reference(column, row).to_string() + ">";
|
||||||
|
}
|
||||||
|
|
||||||
|
cell cell::allocate(xlnt::worksheet owner, int column_index, int row_index)
|
||||||
|
{
|
||||||
|
return new cell_struct(owner.root_, column_index, row_index);
|
||||||
|
}
|
||||||
|
|
||||||
|
void cell::deallocate(xlnt::cell cell)
|
||||||
|
{
|
||||||
|
delete cell.root_;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace xlnt
|
||||||
|
|
402
source/cell.h
Normal file
402
source/cell.h
Normal file
|
@ -0,0 +1,402 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
|
namespace xlnt {
|
||||||
|
|
||||||
|
class cell_reference;
|
||||||
|
class worksheet;
|
||||||
|
|
||||||
|
struct cell_struct;
|
||||||
|
|
||||||
|
typedef std::string comment;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Alignment options for use in styles.
|
||||||
|
/// </summary>
|
||||||
|
struct alignment
|
||||||
|
{
|
||||||
|
enum class horizontal_alignment
|
||||||
|
{
|
||||||
|
general,
|
||||||
|
left,
|
||||||
|
right,
|
||||||
|
center,
|
||||||
|
center_continuous,
|
||||||
|
justify
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class vertical_alignment
|
||||||
|
{
|
||||||
|
bottom,
|
||||||
|
top,
|
||||||
|
center,
|
||||||
|
justify
|
||||||
|
};
|
||||||
|
|
||||||
|
horizontal_alignment horizontal = horizontal_alignment::general;
|
||||||
|
vertical_alignment vertical = vertical_alignment::bottom;
|
||||||
|
int text_rotation = 0;
|
||||||
|
bool wrap_text = false;
|
||||||
|
bool shrink_to_fit = false;
|
||||||
|
int indent = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class number_format
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum class format
|
||||||
|
{
|
||||||
|
general,
|
||||||
|
text,
|
||||||
|
number,
|
||||||
|
number00,
|
||||||
|
number_comma_separated1,
|
||||||
|
number_comma_separated2,
|
||||||
|
percentage,
|
||||||
|
percentage00,
|
||||||
|
date_yyyymmdd2,
|
||||||
|
date_yyyymmdd,
|
||||||
|
date_ddmmyyyy,
|
||||||
|
date_dmyslash,
|
||||||
|
date_dmyminus,
|
||||||
|
date_dmminus,
|
||||||
|
date_myminus,
|
||||||
|
date_xlsx14,
|
||||||
|
date_xlsx15,
|
||||||
|
date_xlsx16,
|
||||||
|
date_xlsx17,
|
||||||
|
date_xlsx22,
|
||||||
|
date_datetime,
|
||||||
|
date_time1,
|
||||||
|
date_time2,
|
||||||
|
date_time3,
|
||||||
|
date_time4,
|
||||||
|
date_time5,
|
||||||
|
date_time6,
|
||||||
|
date_time7,
|
||||||
|
date_time8,
|
||||||
|
date_timedelta,
|
||||||
|
date_yyyymmddslash,
|
||||||
|
currency_usd_simple,
|
||||||
|
currency_usd,
|
||||||
|
currency_eur_simple
|
||||||
|
};
|
||||||
|
|
||||||
|
static const std::unordered_map<int, std::string> builtin_formats;
|
||||||
|
|
||||||
|
static std::string builtin_format_code(int index);
|
||||||
|
|
||||||
|
static bool is_date_format(const std::string &format);
|
||||||
|
static bool is_builtin(const std::string &format);
|
||||||
|
|
||||||
|
format get_format_code() const { return format_code_; }
|
||||||
|
void set_format_code(format format_code) { format_code_ = format_code; }
|
||||||
|
void set_format_code(const std::string &format_code) { custom_format_code_ = format_code; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string custom_format_code_ = "";
|
||||||
|
format format_code_ = format::general;
|
||||||
|
int format_index_ = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct color
|
||||||
|
{
|
||||||
|
static const color black;
|
||||||
|
static const color white;
|
||||||
|
static const color red;
|
||||||
|
static const color darkred;
|
||||||
|
static const color blue;
|
||||||
|
static const color darkblue;
|
||||||
|
static const color green;
|
||||||
|
static const color darkgreen;
|
||||||
|
static const color yellow;
|
||||||
|
static const color darkyellow;
|
||||||
|
|
||||||
|
color(int index)
|
||||||
|
{
|
||||||
|
this->index = index;
|
||||||
|
}
|
||||||
|
|
||||||
|
int index;
|
||||||
|
};
|
||||||
|
|
||||||
|
class font
|
||||||
|
{
|
||||||
|
enum class underline
|
||||||
|
{
|
||||||
|
none,
|
||||||
|
double_,
|
||||||
|
double_accounting,
|
||||||
|
single,
|
||||||
|
single_accounting
|
||||||
|
};
|
||||||
|
|
||||||
|
/* std::string name = "Calibri";
|
||||||
|
int size = 11;
|
||||||
|
bool bold = false;
|
||||||
|
bool italic = false;
|
||||||
|
bool superscript = false;
|
||||||
|
bool subscript = false;
|
||||||
|
underline underline = underline::none;
|
||||||
|
bool strikethrough = false;
|
||||||
|
color color = color::black;*/
|
||||||
|
};
|
||||||
|
|
||||||
|
class fill
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum class type
|
||||||
|
{
|
||||||
|
none,
|
||||||
|
solid,
|
||||||
|
gradient_linear,
|
||||||
|
gradient_path,
|
||||||
|
pattern_darkdown,
|
||||||
|
pattern_darkgray,
|
||||||
|
pattern_darkgrid,
|
||||||
|
pattern_darkhorizontal,
|
||||||
|
pattern_darktrellis,
|
||||||
|
pattern_darkup,
|
||||||
|
pattern_darkvertical,
|
||||||
|
pattern_gray0625,
|
||||||
|
pattern_gray125,
|
||||||
|
pattern_lightdown,
|
||||||
|
pattern_lightgray,
|
||||||
|
pattern_lightgrid,
|
||||||
|
pattern_lighthorizontal,
|
||||||
|
pattern_lighttrellis,
|
||||||
|
pattern_lightup,
|
||||||
|
pattern_lightvertical,
|
||||||
|
pattern_mediumgray,
|
||||||
|
};
|
||||||
|
|
||||||
|
type type = type::none;
|
||||||
|
int rotation = 0;
|
||||||
|
color start_color = color::white;
|
||||||
|
color end_color = color::black;
|
||||||
|
};
|
||||||
|
|
||||||
|
class borders
|
||||||
|
{
|
||||||
|
struct border
|
||||||
|
{
|
||||||
|
enum class style
|
||||||
|
{
|
||||||
|
none,
|
||||||
|
dashdot,
|
||||||
|
dashdotdot,
|
||||||
|
dashed,
|
||||||
|
dotted,
|
||||||
|
double_,
|
||||||
|
hair,
|
||||||
|
medium,
|
||||||
|
mediumdashdot,
|
||||||
|
mediumdashdotdot,
|
||||||
|
mediumdashed,
|
||||||
|
slantdashdot,
|
||||||
|
thick,
|
||||||
|
thin
|
||||||
|
};
|
||||||
|
|
||||||
|
style style = style::none;
|
||||||
|
color color = color::black;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class diagonal_direction
|
||||||
|
{
|
||||||
|
none,
|
||||||
|
up,
|
||||||
|
down,
|
||||||
|
both
|
||||||
|
};
|
||||||
|
|
||||||
|
border left;
|
||||||
|
border right;
|
||||||
|
border top;
|
||||||
|
border bottom;
|
||||||
|
border diagonal;
|
||||||
|
// diagonal_direction diagonal_direction = diagonal_direction::none;
|
||||||
|
border all_borders;
|
||||||
|
border outline;
|
||||||
|
border inside;
|
||||||
|
border vertical;
|
||||||
|
border horizontal;
|
||||||
|
};
|
||||||
|
|
||||||
|
class protection
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum class type
|
||||||
|
{
|
||||||
|
inherit,
|
||||||
|
protected_,
|
||||||
|
unprotected
|
||||||
|
};
|
||||||
|
|
||||||
|
type locked;
|
||||||
|
type hidden;
|
||||||
|
};
|
||||||
|
|
||||||
|
class style
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
style(bool static_ = false) : static_(static_) {}
|
||||||
|
|
||||||
|
style copy() const;
|
||||||
|
|
||||||
|
font get_font() const;
|
||||||
|
void set_font(font font);
|
||||||
|
|
||||||
|
fill get_fill() const;
|
||||||
|
void set_fill(fill fill);
|
||||||
|
|
||||||
|
borders get_borders() const;
|
||||||
|
void set_borders(borders borders);
|
||||||
|
|
||||||
|
alignment get_alignment() const;
|
||||||
|
void set_alignment(alignment alignment);
|
||||||
|
|
||||||
|
number_format &get_number_format() { return number_format_; }
|
||||||
|
const number_format &get_number_format() const { return number_format_; }
|
||||||
|
void set_number_format(number_format number_format);
|
||||||
|
|
||||||
|
protection get_protection() const;
|
||||||
|
void set_protection(protection protection);
|
||||||
|
|
||||||
|
private:
|
||||||
|
style(const style &rhs);
|
||||||
|
|
||||||
|
bool static_ = false;
|
||||||
|
font font_;
|
||||||
|
fill fill_;
|
||||||
|
borders borders_;
|
||||||
|
alignment alignment_;
|
||||||
|
number_format number_format_;
|
||||||
|
protection protection_;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Describes cell associated properties.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Properties of interest include style, type, value, and address.
|
||||||
|
/// The Cell class is required to know its value and type, display options,
|
||||||
|
/// and any other features of an Excel cell.Utilities for referencing
|
||||||
|
/// cells using Excel's 'A1' column/row nomenclature are also provided.
|
||||||
|
/// </remarks>
|
||||||
|
class cell
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum class type
|
||||||
|
{
|
||||||
|
null,
|
||||||
|
numeric,
|
||||||
|
string,
|
||||||
|
date,
|
||||||
|
formula,
|
||||||
|
boolean,
|
||||||
|
error,
|
||||||
|
hyperlink
|
||||||
|
};
|
||||||
|
|
||||||
|
static const std::unordered_map<std::string, int> ErrorCodes;
|
||||||
|
|
||||||
|
static std::string check_string(const std::string &value);
|
||||||
|
static std::string check_numeric(const std::string &value);
|
||||||
|
static std::string check_error(const std::string &value);
|
||||||
|
|
||||||
|
cell();
|
||||||
|
cell(worksheet &ws, const std::string &column, int row);
|
||||||
|
cell(worksheet &ws, const std::string &column, int row, const std::string &initial_value);
|
||||||
|
|
||||||
|
std::string get_value() const;
|
||||||
|
|
||||||
|
std::string get_column() const;
|
||||||
|
int get_row() const;
|
||||||
|
|
||||||
|
std::string to_string() const;
|
||||||
|
|
||||||
|
void set_explicit_value(const std::string &value, type data_type);
|
||||||
|
type data_type_for_value(const std::string &value);
|
||||||
|
|
||||||
|
bool bind_value();
|
||||||
|
bool bind_value(int value);
|
||||||
|
bool bind_value(double value);
|
||||||
|
bool bind_value(const std::string &value);
|
||||||
|
bool bind_value(const char *value);
|
||||||
|
bool bind_value(bool value);
|
||||||
|
bool bind_value(const tm &value);
|
||||||
|
|
||||||
|
bool get_merged() const;
|
||||||
|
void set_merged(bool);
|
||||||
|
|
||||||
|
std::string get_hyperlink() const;
|
||||||
|
void set_hyperlink(const std::string &value);
|
||||||
|
|
||||||
|
std::string get_hyperlink_rel_id() const;
|
||||||
|
|
||||||
|
void set_number_format(const std::string &format_code);
|
||||||
|
|
||||||
|
bool has_style() const;
|
||||||
|
|
||||||
|
style &get_style();
|
||||||
|
const style &get_style() const;
|
||||||
|
|
||||||
|
type get_data_type() const;
|
||||||
|
|
||||||
|
cell_reference get_reference() const;
|
||||||
|
|
||||||
|
cell get_offset(int row, int column);
|
||||||
|
|
||||||
|
bool is_date() const;
|
||||||
|
|
||||||
|
std::pair<int, int> get_anchor() const;
|
||||||
|
|
||||||
|
comment get_comment() const;
|
||||||
|
void set_comment(comment comment);
|
||||||
|
|
||||||
|
cell &operator=(const cell &rhs);
|
||||||
|
cell &operator=(bool value);
|
||||||
|
cell &operator=(int value);
|
||||||
|
cell &operator=(double value);
|
||||||
|
cell &operator=(const std::string &value);
|
||||||
|
cell &operator=(const char *value);
|
||||||
|
cell &operator=(const tm &value);
|
||||||
|
|
||||||
|
bool operator==(std::nullptr_t) const;
|
||||||
|
bool operator==(bool comparand) const;
|
||||||
|
bool operator==(int comparand) const;
|
||||||
|
bool operator==(double comparand) const;
|
||||||
|
bool operator==(const std::string &comparand) const;
|
||||||
|
bool operator==(const char *comparand) const;
|
||||||
|
bool operator==(const tm &comparand) const;
|
||||||
|
bool operator==(const cell &comparand) const { return root_ == comparand.root_; }
|
||||||
|
|
||||||
|
friend bool operator==(std::nullptr_t, const cell &cell);
|
||||||
|
friend bool operator==(bool comparand, const cell &cell);
|
||||||
|
friend bool operator==(int comparand, const cell &cell);
|
||||||
|
friend bool operator==(double comparand, const cell &cell);
|
||||||
|
friend bool operator==(const std::string &comparand, const cell &cell);
|
||||||
|
friend bool operator==(const char *comparand, const cell &cell);
|
||||||
|
friend bool operator==(const tm &comparand, const cell &cell);
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend struct worksheet_struct;
|
||||||
|
|
||||||
|
static cell allocate(worksheet owner, int column_index, int row_index);
|
||||||
|
static void deallocate(cell cell);
|
||||||
|
|
||||||
|
cell(cell_struct *root);
|
||||||
|
|
||||||
|
cell_struct *root_;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline std::ostream &operator<<(std::ostream &stream, const xlnt::cell &cell)
|
||||||
|
{
|
||||||
|
return stream << cell.to_string();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace xlnt
|
||||||
|
|
40
source/constants.cpp
Normal file
40
source/constants.cpp
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
#include "constants.h"
|
||||||
|
|
||||||
|
namespace xlnt {
|
||||||
|
|
||||||
|
const int constants::MinRow = 0;
|
||||||
|
const int constants::MinColumn = 0;
|
||||||
|
const int constants::MaxColumn = 16384;
|
||||||
|
const int constants::MaxRow = 1048576;
|
||||||
|
|
||||||
|
// constants
|
||||||
|
const std::string constants::PackageProps = "docProps";
|
||||||
|
const std::string constants::PackageXl = "xl";
|
||||||
|
const std::string constants::PackageRels = "_rels";
|
||||||
|
const std::string constants::PackageTheme = PackageXl + "/" + "theme";
|
||||||
|
const std::string constants::PackageWorksheets = PackageXl + "/" + "worksheets";
|
||||||
|
const std::string constants::PackageDrawings = PackageXl + "/" + "drawings";
|
||||||
|
const std::string constants::PackageCharts = PackageXl + "/" + "charts";
|
||||||
|
|
||||||
|
const std::string constants::ArcContentTypes = "[Content_Types].xml";
|
||||||
|
const std::string constants::ArcRootRels = PackageRels + "/.rels";
|
||||||
|
const std::string constants::ArcWorkbookRels = PackageXl + "/" + PackageRels + "/workbook.xml.rels";
|
||||||
|
const std::string constants::ArcCore = PackageProps + "/core.xml";
|
||||||
|
const std::string constants::ArcApp = PackageProps + "/app.xml";
|
||||||
|
const std::string constants::ArcWorkbook = PackageXl + "/workbook.xml";
|
||||||
|
const std::string constants::ArcStyles = PackageXl + "/styles.xml";
|
||||||
|
const std::string constants::ArcTheme = PackageTheme + "/theme1.xml";
|
||||||
|
const std::string constants::ArcSharedString = PackageXl + "/sharedStrings.xml";
|
||||||
|
|
||||||
|
const std::unordered_map<std::string, std::string> constants::Namespaces =
|
||||||
|
{
|
||||||
|
{"cp", "http://schemas.openxmlformats.org/package/2006/metadata/core-properties"},
|
||||||
|
{"dc", "http://purl.org/dc/elements/1.1/"},
|
||||||
|
{"dcterms", "http://purl.org/dc/terms/"},
|
||||||
|
{"dcmitype", "http://purl.org/dc/dcmitype/"},
|
||||||
|
{"xsi", "http://www.w3.org/2001/XMLSchema-instance"},
|
||||||
|
{"vt", "http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes"},
|
||||||
|
{"xml", "http://www.w3.org/XML/1998/namespace"}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
37
source/constants.h
Normal file
37
source/constants.h
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
|
namespace xlnt {
|
||||||
|
|
||||||
|
struct constants
|
||||||
|
{
|
||||||
|
static const int MinRow;
|
||||||
|
static const int MinColumn;
|
||||||
|
static const int MaxColumn;
|
||||||
|
static const int MaxRow;
|
||||||
|
|
||||||
|
// constants
|
||||||
|
static const std::string PackageProps;
|
||||||
|
static const std::string PackageXl;
|
||||||
|
static const std::string PackageRels;
|
||||||
|
static const std::string PackageTheme;
|
||||||
|
static const std::string PackageWorksheets;
|
||||||
|
static const std::string PackageDrawings;
|
||||||
|
static const std::string PackageCharts;
|
||||||
|
|
||||||
|
static const std::string ArcContentTypes;
|
||||||
|
static const std::string ArcRootRels;
|
||||||
|
static const std::string ArcWorkbookRels;
|
||||||
|
static const std::string ArcCore;
|
||||||
|
static const std::string ArcApp;
|
||||||
|
static const std::string ArcWorkbook;
|
||||||
|
static const std::string ArcStyles;
|
||||||
|
static const std::string ArcTheme;
|
||||||
|
static const std::string ArcSharedString;
|
||||||
|
|
||||||
|
static const std::unordered_map<std::string, std::string> Namespaces;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace xlnt
|
1
source/custom_exceptions.cpp
Normal file
1
source/custom_exceptions.cpp
Normal file
|
@ -0,0 +1 @@
|
||||||
|
#include "custom_exceptions.h"
|
34
source/custom_exceptions.h
Normal file
34
source/custom_exceptions.h
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <exception>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace xlnt {
|
||||||
|
|
||||||
|
class bad_sheet_title : public std::runtime_error
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
bad_sheet_title(const std::string &title)
|
||||||
|
: std::runtime_error(std::string("bad worksheet title: ") + title)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class bad_cell_coordinates : public std::runtime_error
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
bad_cell_coordinates(int row, int column)
|
||||||
|
: std::runtime_error(std::string("bad cell coordinates: (") + std::to_string(row) + "," + std::to_string(column) + ")")
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bad_cell_coordinates(const std::string &coord_string)
|
||||||
|
: std::runtime_error(std::string("bad cell coordinates: (") + coord_string + ")")
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace xlnt
|
1
source/drawing.cpp
Normal file
1
source/drawing.cpp
Normal file
|
@ -0,0 +1 @@
|
||||||
|
#include "drawing.h"
|
19
source/drawing.h
Normal file
19
source/drawing.h
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace xlnt {
|
||||||
|
|
||||||
|
class worksheet;
|
||||||
|
struct drawing_struct;
|
||||||
|
|
||||||
|
class drawing
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
drawing();
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class worksheet;
|
||||||
|
drawing(drawing_struct *root);
|
||||||
|
drawing_struct *root_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace xlnt
|
62
source/named_range.cpp
Normal file
62
source/named_range.cpp
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
#include "named_range.h"
|
||||||
|
#include "reference.h"
|
||||||
|
#include "worksheet.h"
|
||||||
|
|
||||||
|
namespace xlnt {
|
||||||
|
|
||||||
|
struct named_range_struct
|
||||||
|
{
|
||||||
|
named_range_struct(const std::string &name, worksheet parent, const range_reference &reference)
|
||||||
|
: name_(name),
|
||||||
|
parent_worksheet_(parent),
|
||||||
|
target_range_(reference)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string name_;
|
||||||
|
worksheet parent_worksheet_;
|
||||||
|
range_reference target_range_;
|
||||||
|
};
|
||||||
|
|
||||||
|
void named_range::set_scope(worksheet scope)
|
||||||
|
{
|
||||||
|
root_->parent_worksheet_ = scope;
|
||||||
|
}
|
||||||
|
|
||||||
|
named_range::named_range(named_range_struct *root) : root_(root)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool named_range::operator==(const xlnt::named_range &comparand) const
|
||||||
|
{
|
||||||
|
return comparand.root_->parent_worksheet_ == root_->parent_worksheet_
|
||||||
|
&& comparand.root_->target_range_ == root_->target_range_;
|
||||||
|
}
|
||||||
|
|
||||||
|
named_range::named_range() : root_(nullptr)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
named_range::named_range(const std::string &name, worksheet ws, const range_reference &target)
|
||||||
|
{
|
||||||
|
root_ = ws.create_named_range(name, target).root_;
|
||||||
|
}
|
||||||
|
|
||||||
|
range_reference named_range::get_target_range() const
|
||||||
|
{
|
||||||
|
return root_->target_range_;
|
||||||
|
}
|
||||||
|
|
||||||
|
worksheet named_range::get_scope() const
|
||||||
|
{
|
||||||
|
return root_->parent_worksheet_;
|
||||||
|
}
|
||||||
|
|
||||||
|
named_range named_range::allocate(const std::string &name, xlnt::worksheet ws, const xlnt::range_reference &target)
|
||||||
|
{
|
||||||
|
return new named_range_struct(name, ws, target);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace xlnt
|
31
source/named_range.h
Normal file
31
source/named_range.h
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace xlnt {
|
||||||
|
|
||||||
|
class range_reference;
|
||||||
|
class worksheet;
|
||||||
|
|
||||||
|
struct named_range_struct;
|
||||||
|
|
||||||
|
class named_range
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
named_range();
|
||||||
|
named_range(const std::string &name, worksheet ws, const range_reference &target);
|
||||||
|
range_reference get_target_range() const;
|
||||||
|
worksheet get_scope() const;
|
||||||
|
void set_scope(worksheet scope);
|
||||||
|
bool operator==(const named_range &comparand) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class worksheet;
|
||||||
|
|
||||||
|
static named_range allocate(const std::string &name, worksheet ws, const range_reference &target);
|
||||||
|
|
||||||
|
named_range(named_range_struct *);
|
||||||
|
named_range_struct *root_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace xlnt
|
42
source/protection.cpp
Normal file
42
source/protection.cpp
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
#include "protection.h"
|
||||||
|
|
||||||
|
namespace xlnt {
|
||||||
|
|
||||||
|
void sheet_protection::set_password(const std::string &password)
|
||||||
|
{
|
||||||
|
hashed_password_ = hash_password(password);
|
||||||
|
}
|
||||||
|
|
||||||
|
template< typename T >
|
||||||
|
std::string int_to_hex(T i)
|
||||||
|
{
|
||||||
|
std::stringstream stream;
|
||||||
|
stream << std::hex << i;
|
||||||
|
return stream.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string sheet_protection::hash_password(const std::string &plaintext_password)
|
||||||
|
{
|
||||||
|
int password = 0x0000;
|
||||||
|
int i = 1;
|
||||||
|
|
||||||
|
for(auto character : plaintext_password)
|
||||||
|
{
|
||||||
|
int value = character << i;
|
||||||
|
int rotated_bits = value >> 15;
|
||||||
|
value &= 0x7fff;
|
||||||
|
password ^= (value | rotated_bits);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
password ^= plaintext_password.size();
|
||||||
|
password ^= 0xCE4B;
|
||||||
|
|
||||||
|
std::string hashed = int_to_hex(password);
|
||||||
|
std::transform(hashed.begin(), hashed.end(), hashed.begin(), [](char c){ return std::toupper(c, std::locale::classic()); });
|
||||||
|
return hashed;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
19
source/protection.h
Normal file
19
source/protection.h
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace xlnt {
|
||||||
|
|
||||||
|
class sheet_protection
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static std::string hash_password(const std::string &password);
|
||||||
|
|
||||||
|
void set_password(const std::string &password);
|
||||||
|
std::string get_hashed_password() const { return hashed_password_; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string hashed_password_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace xlnt
|
1
source/range.cpp
Normal file
1
source/range.cpp
Normal file
|
@ -0,0 +1 @@
|
||||||
|
#include "range.h"
|
12
source/range.h
Normal file
12
source/range.h
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace xlnt {
|
||||||
|
|
||||||
|
class cell;
|
||||||
|
|
||||||
|
typedef std::vector<std::vector<cell>> range;
|
||||||
|
|
||||||
|
} // namespace xlnt
|
240
source/reader.cpp
Normal file
240
source/reader.cpp
Normal file
|
@ -0,0 +1,240 @@
|
||||||
|
#include <pugixml.hpp>
|
||||||
|
|
||||||
|
#include "reader.h"
|
||||||
|
#include "cell.h"
|
||||||
|
#include "reference.h"
|
||||||
|
#include "workbook.h"
|
||||||
|
#include "worksheet.h"
|
||||||
|
|
||||||
|
namespace xlnt {
|
||||||
|
|
||||||
|
std::unordered_map<std::string, std::pair<std::string, std::string>> reader::read_relationships(const std::string &content)
|
||||||
|
{
|
||||||
|
pugi::xml_document doc;
|
||||||
|
doc.load(content.c_str());
|
||||||
|
|
||||||
|
auto root_node = doc.child("Relationships");
|
||||||
|
|
||||||
|
std::unordered_map<std::string, std::pair<std::string, std::string>> relationships;
|
||||||
|
|
||||||
|
for(auto relationship : root_node.children("Relationship"))
|
||||||
|
{
|
||||||
|
std::string id = relationship.attribute("Id").as_string();
|
||||||
|
std::string type = relationship.attribute("Type").as_string();
|
||||||
|
std::string target = relationship.attribute("Target").as_string();
|
||||||
|
relationships[id] = std::make_pair(type, target);
|
||||||
|
}
|
||||||
|
|
||||||
|
return relationships;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::pair<std::unordered_map<std::string, std::string>, std::unordered_map<std::string, std::string>> reader::read_content_types(const std::string &content)
|
||||||
|
{
|
||||||
|
pugi::xml_document doc;
|
||||||
|
doc.load(content.c_str());
|
||||||
|
|
||||||
|
auto root_node = doc.child("Types");
|
||||||
|
|
||||||
|
std::unordered_map<std::string, std::string> default_types;
|
||||||
|
|
||||||
|
for(auto child : root_node.children("Default"))
|
||||||
|
{
|
||||||
|
default_types[child.attribute("Extension").as_string()] = child.attribute("ContentType").as_string();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unordered_map<std::string, std::string> override_types;
|
||||||
|
|
||||||
|
for(auto child : root_node.children("Override"))
|
||||||
|
{
|
||||||
|
override_types[child.attribute("PartName").as_string()] = child.attribute("ContentType").as_string();
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::make_pair(default_types, override_types);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string reader::determine_document_type(const std::unordered_map<std::string, std::pair<std::string, std::string>> &root_relationships,
|
||||||
|
const std::unordered_map<std::string, std::string> &override_types)
|
||||||
|
{
|
||||||
|
auto relationship_match = std::find_if(root_relationships.begin(), root_relationships.end(),
|
||||||
|
[](const std::pair<std::string, std::pair<std::string, std::string>> &v)
|
||||||
|
{ return v.second.first == "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument"; });
|
||||||
|
std::string type;
|
||||||
|
|
||||||
|
if(relationship_match != root_relationships.end())
|
||||||
|
{
|
||||||
|
std::string office_document_relationship = relationship_match->second.second;
|
||||||
|
|
||||||
|
if(office_document_relationship[0] != '/')
|
||||||
|
{
|
||||||
|
office_document_relationship = std::string("/") + office_document_relationship;
|
||||||
|
}
|
||||||
|
|
||||||
|
type = override_types.at(office_document_relationship);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(type == "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml")
|
||||||
|
{
|
||||||
|
return "excel";
|
||||||
|
}
|
||||||
|
else if(type == "application/vnd.openxmlformats-officedocument.presentationml.presentation.main+xml")
|
||||||
|
{
|
||||||
|
return "powerpoint";
|
||||||
|
}
|
||||||
|
else if(type == "application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml")
|
||||||
|
{
|
||||||
|
return "word";
|
||||||
|
}
|
||||||
|
|
||||||
|
return "unsupported";
|
||||||
|
}
|
||||||
|
|
||||||
|
void read_worksheet_common(worksheet ws, const pugi::xml_node &root_node, const std::vector<std::string> &string_table)
|
||||||
|
{
|
||||||
|
auto dimension_node = root_node.child("dimension");
|
||||||
|
std::string dimension = dimension_node.attribute("ref").as_string();
|
||||||
|
auto sheet_data_node = root_node.child("sheetData");
|
||||||
|
auto merge_cells_node = root_node.child("mergeCells");
|
||||||
|
|
||||||
|
if(merge_cells_node != nullptr)
|
||||||
|
{
|
||||||
|
int count = merge_cells_node.attribute("count").as_int();
|
||||||
|
|
||||||
|
for(auto merge_cell_node : merge_cells_node.children("mergeCell"))
|
||||||
|
{
|
||||||
|
ws.merge_cells(merge_cell_node.attribute("ref").as_string());
|
||||||
|
count--;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(count != 0)
|
||||||
|
{
|
||||||
|
throw std::runtime_error("mismatch between count and actual number of merged cells");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for(auto row_node : sheet_data_node.children("row"))
|
||||||
|
{
|
||||||
|
int row_index = row_node.attribute("r").as_int();
|
||||||
|
std::string span_string = row_node.attribute("spans").as_string();
|
||||||
|
auto colon_index = span_string.find(':');
|
||||||
|
int min_column = std::stoi(span_string.substr(0, colon_index));
|
||||||
|
int max_column = std::stoi(span_string.substr(colon_index + 1));
|
||||||
|
|
||||||
|
for(int i = min_column; i < max_column + 1; i++)
|
||||||
|
{
|
||||||
|
std::string address = xlnt::cell_reference::column_string_from_index(i) + std::to_string(row_index);
|
||||||
|
auto cell_node = row_node.find_child_by_attribute("c", "r", address.c_str());
|
||||||
|
|
||||||
|
if(cell_node != nullptr)
|
||||||
|
{
|
||||||
|
if(cell_node.attribute("t") != nullptr && std::string(cell_node.attribute("t").as_string()) == "inlineStr") // inline string
|
||||||
|
{
|
||||||
|
ws.get_cell(address) = cell_node.child("is").child("t").text().as_string();
|
||||||
|
}
|
||||||
|
else if(cell_node.attribute("t") != nullptr && std::string(cell_node.attribute("t").as_string()) == "s") // shared string
|
||||||
|
{
|
||||||
|
ws.get_cell(address) = string_table.at(cell_node.child("v").text().as_int());
|
||||||
|
}
|
||||||
|
else if(cell_node.attribute("s") != nullptr && std::string(cell_node.attribute("s").as_string()) == "2") // date
|
||||||
|
{
|
||||||
|
tm date;
|
||||||
|
date.tm_year = 1900;
|
||||||
|
int days = cell_node.child("v").text().as_int();
|
||||||
|
while(days > 365)
|
||||||
|
{
|
||||||
|
date.tm_year += 1;
|
||||||
|
days -= 365;
|
||||||
|
}
|
||||||
|
date.tm_yday = days;
|
||||||
|
while(days > 30)
|
||||||
|
{
|
||||||
|
date.tm_mon += 1;
|
||||||
|
days -= 30;
|
||||||
|
}
|
||||||
|
date.tm_mday = days;
|
||||||
|
ws.get_cell(address) = date;
|
||||||
|
}
|
||||||
|
else if(cell_node.attribute("s") != nullptr && std::string(cell_node.attribute("s").as_string()) == "3") // time
|
||||||
|
{
|
||||||
|
tm date;
|
||||||
|
double remaining = cell_node.child("v").text().as_double() * 24;
|
||||||
|
date.tm_hour = (int)(remaining);
|
||||||
|
remaining -= date.tm_hour;
|
||||||
|
remaining *= 60;
|
||||||
|
date.tm_min = (int)(remaining);
|
||||||
|
remaining -= date.tm_min;
|
||||||
|
remaining *= 60;
|
||||||
|
date.tm_sec = (int)(remaining);
|
||||||
|
remaining -= date.tm_sec;
|
||||||
|
if(remaining > 0.5)
|
||||||
|
{
|
||||||
|
date.tm_sec++;
|
||||||
|
if(date.tm_sec > 59)
|
||||||
|
{
|
||||||
|
date.tm_sec = 0;
|
||||||
|
date.tm_min++;
|
||||||
|
if(date.tm_min > 59)
|
||||||
|
{
|
||||||
|
date.tm_min = 0;
|
||||||
|
date.tm_hour++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ws.get_cell(address) = date;
|
||||||
|
}
|
||||||
|
else if(cell_node.attribute("s") != nullptr && std::string(cell_node.attribute("s").as_string()) == "4") // decimal
|
||||||
|
{
|
||||||
|
ws.get_cell(address) = cell_node.child("v").text().as_double();
|
||||||
|
}
|
||||||
|
else if(cell_node.attribute("s") != nullptr && std::string(cell_node.attribute("s").as_string()) == "1") // percent
|
||||||
|
{
|
||||||
|
ws.get_cell(address) = cell_node.child("v").text().as_double();
|
||||||
|
}
|
||||||
|
else if(cell_node.child("v") != nullptr)
|
||||||
|
{
|
||||||
|
ws.get_cell(address) = cell_node.child("v").text().as_string();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void reader::read_worksheet(worksheet ws, const std::string &xml_string, const std::vector<std::string> &string_table)
|
||||||
|
{
|
||||||
|
pugi::xml_document doc;
|
||||||
|
doc.load(xml_string.c_str());
|
||||||
|
read_worksheet_common(ws, doc.child("worksheet"), string_table);
|
||||||
|
}
|
||||||
|
|
||||||
|
worksheet xlnt::reader::read_worksheet(std::istream &handle, xlnt::workbook &wb, const std::string &title, const std::vector<std::string> &string_table)
|
||||||
|
{
|
||||||
|
auto ws = wb.create_sheet();
|
||||||
|
ws.set_title(title);
|
||||||
|
pugi::xml_document doc;
|
||||||
|
doc.load(handle);
|
||||||
|
read_worksheet_common(ws, doc.child("worksheet"), string_table);
|
||||||
|
return ws;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> reader::read_shared_string(const std::string &xml_string)
|
||||||
|
{
|
||||||
|
std::vector<std::string> shared_strings;
|
||||||
|
pugi::xml_document doc;
|
||||||
|
doc.load(xml_string.c_str());
|
||||||
|
auto root_node = doc.child("sst");
|
||||||
|
//int count = root_node.attribute("count").as_int();
|
||||||
|
int unique_count = root_node.attribute("uniqueCount").as_int();
|
||||||
|
|
||||||
|
for(auto si_node : root_node)
|
||||||
|
{
|
||||||
|
shared_strings.push_back(si_node.child("t").text().as_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
if(unique_count != (int)shared_strings.size())
|
||||||
|
{
|
||||||
|
throw std::runtime_error("counts don't match");
|
||||||
|
}
|
||||||
|
|
||||||
|
return shared_strings;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace xlnt
|
25
source/reader.h
Normal file
25
source/reader.h
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <string>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace xlnt {
|
||||||
|
|
||||||
|
class workbook;
|
||||||
|
class worksheet;
|
||||||
|
|
||||||
|
class reader
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static std::unordered_map<std::string, std::pair<std::string, std::string>> read_relationships(const std::string &content);
|
||||||
|
static std::pair<std::unordered_map<std::string, std::string>, std::unordered_map<std::string, std::string>> read_content_types(const std::string &content);
|
||||||
|
static std::string determine_document_type(const std::unordered_map<std::string, std::pair<std::string, std::string>> &root_relationships,
|
||||||
|
const std::unordered_map<std::string, std::string> &override_types);
|
||||||
|
static worksheet read_worksheet(std::istream &handle, workbook &wb, const std::string &title, const std::vector<std::string> &string_table);
|
||||||
|
static void read_worksheet(worksheet ws, const std::string &xml_string, const std::vector<std::string> &string_table);
|
||||||
|
static std::vector<std::string> read_shared_string(const std::string &xml_string);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace xlnt
|
273
source/reference.cpp
Normal file
273
source/reference.cpp
Normal file
|
@ -0,0 +1,273 @@
|
||||||
|
#include <locale>
|
||||||
|
|
||||||
|
#include "reference.h"
|
||||||
|
#include "custom_exceptions.h"
|
||||||
|
|
||||||
|
namespace xlnt {
|
||||||
|
|
||||||
|
std::size_t cell_reference_hash::operator()(const cell_reference &k) const
|
||||||
|
{
|
||||||
|
return std::hash<std::string>()(k.to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
cell_reference cell_reference::make_absolute(const cell_reference &relative_reference)
|
||||||
|
{
|
||||||
|
cell_reference copy = relative_reference;
|
||||||
|
copy.absolute_ = true;
|
||||||
|
return copy;
|
||||||
|
}
|
||||||
|
|
||||||
|
cell_reference::cell_reference(const std::string &string)
|
||||||
|
{
|
||||||
|
bool absolute = false;
|
||||||
|
auto split = split_reference(string, absolute, absolute);
|
||||||
|
*this = cell_reference(split.first, split.second, absolute);
|
||||||
|
}
|
||||||
|
|
||||||
|
cell_reference::cell_reference(const char *reference_string) : cell_reference(std::string(reference_string))
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
cell_reference::cell_reference(const std::string &column, int row, bool absolute)
|
||||||
|
: column_index_(column_index_from_string(column) - 1),
|
||||||
|
row_index_(row - 1),
|
||||||
|
absolute_(absolute)
|
||||||
|
{
|
||||||
|
if(row_index_ < 0 || column_index_ < 0 || row_index_ >= 1048576 || column_index_ >= 16384)
|
||||||
|
{
|
||||||
|
throw bad_cell_coordinates(column_index_, row_index_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cell_reference::cell_reference(int column_index, int row_index, bool absolute)
|
||||||
|
: column_index_(column_index),
|
||||||
|
row_index_(row_index),
|
||||||
|
absolute_(absolute)
|
||||||
|
{
|
||||||
|
if(row_index_ < 0 || column_index_ < 0 || row_index_ >= 1048576 || column_index_ >= 16384)
|
||||||
|
{
|
||||||
|
throw bad_cell_coordinates(column_index_, row_index_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string cell_reference::to_string() const
|
||||||
|
{
|
||||||
|
if(absolute_)
|
||||||
|
{
|
||||||
|
return std::string("$") + column_string_from_index(column_index_ + 1) + "$" + std::to_string(row_index_ + 1);
|
||||||
|
}
|
||||||
|
return column_string_from_index(column_index_ + 1) + std::to_string(row_index_ + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::pair<std::string, int> cell_reference::split_reference(const std::string &reference_string, bool &absolute_column, bool &absolute_row)
|
||||||
|
{
|
||||||
|
absolute_column = false;
|
||||||
|
absolute_row = false;
|
||||||
|
|
||||||
|
// Convert a coordinate string like 'B12' to a tuple ('B', 12)
|
||||||
|
bool column_part = true;
|
||||||
|
|
||||||
|
std::string column_string;
|
||||||
|
|
||||||
|
for(auto character : reference_string)
|
||||||
|
{
|
||||||
|
char upper = std::toupper(character, std::locale::classic());
|
||||||
|
|
||||||
|
if(std::isalpha(character, std::locale::classic()))
|
||||||
|
{
|
||||||
|
if(column_part)
|
||||||
|
{
|
||||||
|
column_string.append(1, upper);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw bad_cell_coordinates(reference_string);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(column_part)
|
||||||
|
{
|
||||||
|
column_part = false;
|
||||||
|
}
|
||||||
|
else if(!(std::isdigit(character, std::locale::classic()) || character == '$'))
|
||||||
|
{
|
||||||
|
throw bad_cell_coordinates(reference_string);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string row_string = reference_string.substr(column_string.length());
|
||||||
|
|
||||||
|
if(column_string[0] == '$')
|
||||||
|
{
|
||||||
|
absolute_row = true;
|
||||||
|
column_string = column_string.substr(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(row_string[0] == '$')
|
||||||
|
{
|
||||||
|
absolute_column = true;
|
||||||
|
row_string = row_string.substr(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {column_string, std::stoi(row_string)};
|
||||||
|
}
|
||||||
|
|
||||||
|
cell_reference cell_reference::make_offset(int column_offset, int row_offset) const
|
||||||
|
{
|
||||||
|
return cell_reference(column_index_ + column_offset, row_index_ + row_offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cell_reference::operator==(const cell_reference &comparand) const
|
||||||
|
{
|
||||||
|
return comparand.column_index_ == column_index_
|
||||||
|
&& comparand.row_index_ == row_index_
|
||||||
|
&& absolute_ == comparand.absolute_;
|
||||||
|
}
|
||||||
|
|
||||||
|
int cell_reference::column_index_from_string(const std::string &column_string)
|
||||||
|
{
|
||||||
|
if(column_string.length() > 3 || column_string.empty())
|
||||||
|
{
|
||||||
|
throw std::runtime_error("column must be one to three characters");
|
||||||
|
}
|
||||||
|
|
||||||
|
int column_index = 0;
|
||||||
|
int place = 1;
|
||||||
|
|
||||||
|
for(int i = static_cast<int>(column_string.length()) - 1; i >= 0; i--)
|
||||||
|
{
|
||||||
|
if(!std::isalpha(column_string[i], std::locale::classic()))
|
||||||
|
{
|
||||||
|
throw std::runtime_error("column must contain only letters in the range A-Z");
|
||||||
|
}
|
||||||
|
|
||||||
|
column_index += (std::toupper(column_string[i], std::locale::classic()) - 'A' + 1) * place;
|
||||||
|
place *= 26;
|
||||||
|
}
|
||||||
|
|
||||||
|
return column_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert a column number into a column letter (3 -> 'C')
|
||||||
|
// Right shift the column col_idx by 26 to find column letters in reverse
|
||||||
|
// order.These numbers are 1 - based, and can be converted to ASCII
|
||||||
|
// ordinals by adding 64.
|
||||||
|
std::string cell_reference::column_string_from_index(int column_index)
|
||||||
|
{
|
||||||
|
// these indicies corrospond to A->ZZZ and include all allowed
|
||||||
|
// columns
|
||||||
|
if(column_index < 1 || column_index > 18278)
|
||||||
|
{
|
||||||
|
auto msg = "Column index out of bounds: " + std::to_string(column_index);
|
||||||
|
throw std::runtime_error(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto temp = column_index;
|
||||||
|
std::string column_letter = "";
|
||||||
|
|
||||||
|
while(temp > 0)
|
||||||
|
{
|
||||||
|
int quotient = temp / 26, remainder = temp % 26;
|
||||||
|
|
||||||
|
// check for exact division and borrow if needed
|
||||||
|
if(remainder == 0)
|
||||||
|
{
|
||||||
|
quotient -= 1;
|
||||||
|
remainder = 26;
|
||||||
|
}
|
||||||
|
|
||||||
|
column_letter = std::string(1, char(remainder + 64)) + column_letter;
|
||||||
|
temp = quotient;
|
||||||
|
}
|
||||||
|
|
||||||
|
return column_letter;
|
||||||
|
}
|
||||||
|
|
||||||
|
range_reference range_reference::make_absolute(const xlnt::range_reference &relative_reference)
|
||||||
|
{
|
||||||
|
range_reference copy = relative_reference;
|
||||||
|
copy.top_left_.set_absolute(true);
|
||||||
|
copy.bottom_right_.set_absolute(true);
|
||||||
|
return copy;
|
||||||
|
}
|
||||||
|
|
||||||
|
range_reference::range_reference() : range_reference("A1")
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
range_reference::range_reference(const char *range_string) : range_reference(std::string(range_string))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
range_reference::range_reference(const std::string &range_string)
|
||||||
|
: top_left_("A1"),
|
||||||
|
bottom_right_("A1")
|
||||||
|
{
|
||||||
|
auto colon_index = range_string.find(':');
|
||||||
|
|
||||||
|
if(colon_index != std::string::npos)
|
||||||
|
{
|
||||||
|
top_left_ = cell_reference(range_string.substr(0, colon_index));
|
||||||
|
bottom_right_ = cell_reference(range_string.substr(colon_index + 1));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
top_left_ = cell_reference(range_string);
|
||||||
|
bottom_right_ = cell_reference(range_string);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
range_reference::range_reference(const cell_reference &top_left, const cell_reference &bottom_right)
|
||||||
|
: top_left_(top_left),
|
||||||
|
bottom_right_(bottom_right)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
range_reference::range_reference(int column_index_start, int row_index_start, int column_index_end, int row_index_end)
|
||||||
|
: top_left_(column_index_start, row_index_start),
|
||||||
|
bottom_right_(column_index_end, row_index_end)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
range_reference range_reference::make_offset(int column_offset, int row_offset) const
|
||||||
|
{
|
||||||
|
return range_reference(top_left_.make_offset(column_offset, row_offset), bottom_right_.make_offset(column_offset, row_offset));
|
||||||
|
}
|
||||||
|
|
||||||
|
int range_reference::get_height() const
|
||||||
|
{
|
||||||
|
return bottom_right_.get_row_index() - top_left_.get_row_index();
|
||||||
|
}
|
||||||
|
|
||||||
|
int range_reference::get_width() const
|
||||||
|
{
|
||||||
|
return bottom_right_.get_column_index() - top_left_.get_column_index();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool range_reference::is_single_cell() const
|
||||||
|
{
|
||||||
|
return get_width() == 0 && get_height() == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string range_reference::to_string() const
|
||||||
|
{
|
||||||
|
if(is_single_cell())
|
||||||
|
{
|
||||||
|
return top_left_.to_string();
|
||||||
|
}
|
||||||
|
return top_left_.to_string() + ":" + bottom_right_.to_string();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool range_reference::operator==(const range_reference &comparand) const
|
||||||
|
{
|
||||||
|
return comparand.top_left_ == top_left_
|
||||||
|
&& comparand.bottom_right_ == bottom_right_;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
116
source/reference.h
Normal file
116
source/reference.h
Normal file
|
@ -0,0 +1,116 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
namespace xlnt {
|
||||||
|
|
||||||
|
class cell_reference;
|
||||||
|
|
||||||
|
struct cell_reference_hash
|
||||||
|
{
|
||||||
|
std::size_t operator()(const cell_reference &k) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
class cell_reference
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/// <summary>
|
||||||
|
/// Convert a coordinate to an absolute coordinate string (B12 -> $B$12)
|
||||||
|
/// </summary>
|
||||||
|
static cell_reference make_absolute(const cell_reference &relative_reference);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Convert a column letter into a column number (e.g. B -> 2)
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Excel only supports 1 - 3 letter column names from A->ZZZ, so we
|
||||||
|
/// restrict our column names to 1 - 3 characters, each in the range A - Z.
|
||||||
|
/// </remarks>
|
||||||
|
static int column_index_from_string(const std::string &column_string);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Convert a column number into a column letter (3 -> 'C')
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Right shift the column col_idx by 26 to find column letters in reverse
|
||||||
|
/// order.These numbers are 1 - based, and can be converted to ASCII
|
||||||
|
/// ordinals by adding 64.
|
||||||
|
/// </remarks>
|
||||||
|
static std::string column_string_from_index(int column_index);
|
||||||
|
|
||||||
|
static std::pair<std::string, int> split_reference(const std::string &reference_string,
|
||||||
|
bool &absolute_column, bool &absolute_row);
|
||||||
|
|
||||||
|
cell_reference(const char *reference_string);
|
||||||
|
cell_reference(const std::string &reference_string);
|
||||||
|
cell_reference(const std::string &column, int row, bool absolute = false);
|
||||||
|
cell_reference(int column, int row, bool absolute = false);
|
||||||
|
|
||||||
|
bool is_absolute() const { return absolute_; }
|
||||||
|
void set_absolute(bool absolute) { absolute_ = absolute; }
|
||||||
|
|
||||||
|
std::string get_column() const { return column_string_from_index(column_index_ + 1); }
|
||||||
|
void set_column(const std::string &column) { column_index_ = column_index_from_string(column) - 1; }
|
||||||
|
|
||||||
|
int get_column_index() const { return column_index_; }
|
||||||
|
void set_column_index(int column_index) { column_index_ = column_index; }
|
||||||
|
|
||||||
|
int get_row() const { return row_index_ + 1; }
|
||||||
|
void set_row(int row) { row_index_ = row - 1; }
|
||||||
|
|
||||||
|
int get_row_index() const { return row_index_; }
|
||||||
|
void set_row_index(int row_index) { row_index_ = row_index; }
|
||||||
|
|
||||||
|
cell_reference make_offset(int column_offset, int row_offset) const;
|
||||||
|
|
||||||
|
std::string to_string() const;
|
||||||
|
|
||||||
|
bool operator==(const cell_reference &comparand) const;
|
||||||
|
bool operator==(const std::string &reference_string) const { return *this == cell_reference(reference_string); }
|
||||||
|
bool operator==(const char *reference_string) const { return *this == std::string(reference_string); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
int column_index_;
|
||||||
|
int row_index_;
|
||||||
|
bool absolute_;
|
||||||
|
};
|
||||||
|
|
||||||
|
class range_reference
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/// <summary>
|
||||||
|
/// Convert a coordinate to an absolute coordinate string (B12 -> $B$12)
|
||||||
|
/// </summary>
|
||||||
|
static range_reference make_absolute(const range_reference &relative_reference);
|
||||||
|
|
||||||
|
range_reference();
|
||||||
|
range_reference(const std::string &range_string);
|
||||||
|
range_reference(const char *range_string);
|
||||||
|
range_reference(const std::pair<cell_reference, cell_reference> &reference_pair);
|
||||||
|
range_reference(const cell_reference &start, const cell_reference &end);
|
||||||
|
range_reference(const std::string &column_start, int row_start, const std::string &column_end, int row_end);
|
||||||
|
range_reference(int column_start, int row_start, int column_end, int row_end);
|
||||||
|
|
||||||
|
bool is_single_cell() const;
|
||||||
|
int get_width() const;
|
||||||
|
int get_height() const;
|
||||||
|
cell_reference get_top_left() const { return top_left_; }
|
||||||
|
cell_reference get_bottom_right() const { return bottom_right_; }
|
||||||
|
cell_reference &get_top_left() { return top_left_; }
|
||||||
|
cell_reference &get_bottom_right() { return bottom_right_; }
|
||||||
|
|
||||||
|
range_reference make_offset(int column_offset, int row_offset) const;
|
||||||
|
|
||||||
|
std::string to_string() const;
|
||||||
|
|
||||||
|
bool operator==(const range_reference &comparand) const;
|
||||||
|
bool operator==(const std::string &reference_string) const { return *this == range_reference(reference_string); }
|
||||||
|
bool operator==(const char *reference_string) const { return *this == std::string(reference_string); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
cell_reference top_left_;
|
||||||
|
cell_reference bottom_right_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace xlnt
|
1
source/relationship.cpp
Normal file
1
source/relationship.cpp
Normal file
|
@ -0,0 +1 @@
|
||||||
|
#include "relationship.h"
|
78
source/relationship.h
Normal file
78
source/relationship.h
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace xlnt {
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Specifies whether the target of a relationship is inside or outside the Package.
|
||||||
|
/// </summary>
|
||||||
|
enum class target_mode
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The relationship references a part that is inside the package.
|
||||||
|
/// </summary>
|
||||||
|
external,
|
||||||
|
/// <summary>
|
||||||
|
/// The relationship references a resource that is external to the package.
|
||||||
|
/// </summary>
|
||||||
|
internal
|
||||||
|
};
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents an association between a source Package or part, and a target object which can be a part or external resource.
|
||||||
|
/// </summary>
|
||||||
|
class relationship
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum class type
|
||||||
|
{
|
||||||
|
hyperlink,
|
||||||
|
drawing,
|
||||||
|
worksheet,
|
||||||
|
sharedStrings,
|
||||||
|
styles,
|
||||||
|
theme
|
||||||
|
};
|
||||||
|
|
||||||
|
relationship(const std::string &type, const std::string &r_id = "", const std::string &target_uri = "") : id_(r_id), source_uri_(""), target_uri_(target_uri)
|
||||||
|
{
|
||||||
|
if(type == "hyperlink")
|
||||||
|
{
|
||||||
|
type_ = type::hyperlink;
|
||||||
|
target_mode_ = target_mode::external;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// gets a string that identifies the relationship.
|
||||||
|
/// </summary>
|
||||||
|
std::string get_id() const { return id_; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// gets the URI of the package or part that owns the relationship.
|
||||||
|
/// </summary>
|
||||||
|
std::string get_source_uri() const { return source_uri_; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// gets a value that indicates whether the target of the relationship is or External to the Package.
|
||||||
|
/// </summary>
|
||||||
|
target_mode get_target_mode() const { return target_mode_; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// gets the URI of the target resource of the relationship.
|
||||||
|
/// </summary>
|
||||||
|
std::string get_target_uri() const { return target_uri_; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
relationship(const std::string &id, const std::string &relationship_type_, const std::string &source_uri, target_mode target_mode, const std::string &target_uri);
|
||||||
|
//relationship &operator=(const relationship &rhs) = delete;
|
||||||
|
|
||||||
|
type type_;
|
||||||
|
std::string id_;
|
||||||
|
std::string source_uri_;
|
||||||
|
std::string target_uri_;
|
||||||
|
target_mode target_mode_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace xlnt
|
29
source/string_table.cpp
Normal file
29
source/string_table.cpp
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
#include "string_table.h"
|
||||||
|
|
||||||
|
namespace xlnt {
|
||||||
|
|
||||||
|
int string_table::operator[](const std::string &key) const
|
||||||
|
{
|
||||||
|
for(std::size_t i = 0; i < strings_.size(); i++)
|
||||||
|
{
|
||||||
|
if(key == strings_[i])
|
||||||
|
{
|
||||||
|
return (int)i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw std::runtime_error("bad string");
|
||||||
|
}
|
||||||
|
|
||||||
|
void string_table_builder::add(const std::string &string)
|
||||||
|
{
|
||||||
|
for(std::size_t i = 0; i < table_.strings_.size(); i++)
|
||||||
|
{
|
||||||
|
if(string == table_.strings_[i])
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
table_.strings_.push_back(string);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace xlnt
|
29
source/string_table.h
Normal file
29
source/string_table.h
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace xlnt {
|
||||||
|
|
||||||
|
class string_table_builder;
|
||||||
|
|
||||||
|
class string_table
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
int operator[](const std::string &key) const;
|
||||||
|
private:
|
||||||
|
friend class string_table_builder;
|
||||||
|
std::vector<std::string> strings_;
|
||||||
|
};
|
||||||
|
|
||||||
|
class string_table_builder
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void add(const std::string &string);
|
||||||
|
string_table &get_table() { return table_; }
|
||||||
|
const string_table &get_table() const { return table_; }
|
||||||
|
private:
|
||||||
|
string_table table_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace xlnt
|
|
@ -16,74 +16,74 @@ public:
|
||||||
|
|
||||||
void test_coordinates()
|
void test_coordinates()
|
||||||
{
|
{
|
||||||
auto coord = xlnt::cell::coordinate_from_string("ZF46");
|
xlnt::cell_reference coord("ZF46");
|
||||||
TS_ASSERT_EQUALS("ZF", coord.column);
|
TS_ASSERT_EQUALS("ZF", coord.get_column());
|
||||||
TS_ASSERT_EQUALS(46, coord.row);
|
TS_ASSERT_EQUALS(46, coord.get_row());
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_invalid_coordinate()
|
void test_invalid_coordinate()
|
||||||
{
|
{
|
||||||
TS_ASSERT_THROWS_ANYTHING(xlnt::cell::coordinate_from_string("AAA"));
|
TS_ASSERT_THROWS_ANYTHING(xlnt::cell_reference("AAA"));
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_zero_row()
|
void test_zero_row()
|
||||||
{
|
{
|
||||||
TS_ASSERT_THROWS_ANYTHING(xlnt::cell::coordinate_from_string("AQ0"));
|
TS_ASSERT_THROWS_ANYTHING(xlnt::cell_reference("AQ0"));
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_absolute()
|
void test_absolute()
|
||||||
{
|
{
|
||||||
TS_ASSERT_EQUALS("$ZF$51", xlnt::cell::absolute_coordinate("ZF51"));
|
TS_ASSERT_EQUALS("$ZF$51", xlnt::cell_reference::make_absolute("ZF51").to_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_absolute_multiple()
|
void test_absolute_multiple()
|
||||||
{
|
{
|
||||||
TS_ASSERT_EQUALS("$ZF$51:$ZF$53", xlnt::cell::absolute_coordinate("ZF51:ZF$53"));
|
TS_ASSERT_EQUALS("$ZF$51:$ZF$53", xlnt::range_reference::make_absolute("ZF51:ZF$53").to_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_column_index()
|
void test_column_index()
|
||||||
{
|
{
|
||||||
TS_ASSERT_EQUALS(10, xlnt::cell::column_index_from_string("J"));
|
TS_ASSERT_EQUALS(10, xlnt::cell_reference::column_index_from_string("J"));
|
||||||
TS_ASSERT_EQUALS(270, xlnt::cell::column_index_from_string("jJ"));
|
TS_ASSERT_EQUALS(270, xlnt::cell_reference::column_index_from_string("jJ"));
|
||||||
TS_ASSERT_EQUALS(7030, xlnt::cell::column_index_from_string("jjj"));
|
TS_ASSERT_EQUALS(7030, xlnt::cell_reference::column_index_from_string("jjj"));
|
||||||
TS_ASSERT_EQUALS(1, xlnt::cell::column_index_from_string("A"));
|
TS_ASSERT_EQUALS(1, xlnt::cell_reference::column_index_from_string("A"));
|
||||||
TS_ASSERT_EQUALS(26, xlnt::cell::column_index_from_string("Z"));
|
TS_ASSERT_EQUALS(26, xlnt::cell_reference::column_index_from_string("Z"));
|
||||||
TS_ASSERT_EQUALS(27, xlnt::cell::column_index_from_string("AA"));
|
TS_ASSERT_EQUALS(27, xlnt::cell_reference::column_index_from_string("AA"));
|
||||||
TS_ASSERT_EQUALS(52, xlnt::cell::column_index_from_string("AZ"));
|
TS_ASSERT_EQUALS(52, xlnt::cell_reference::column_index_from_string("AZ"));
|
||||||
TS_ASSERT_EQUALS(53, xlnt::cell::column_index_from_string("BA"));
|
TS_ASSERT_EQUALS(53, xlnt::cell_reference::column_index_from_string("BA"));
|
||||||
TS_ASSERT_EQUALS(78, xlnt::cell::column_index_from_string("BZ"));
|
TS_ASSERT_EQUALS(78, xlnt::cell_reference::column_index_from_string("BZ"));
|
||||||
TS_ASSERT_EQUALS(677, xlnt::cell::column_index_from_string("ZA"));
|
TS_ASSERT_EQUALS(677, xlnt::cell_reference::column_index_from_string("ZA"));
|
||||||
TS_ASSERT_EQUALS(702, xlnt::cell::column_index_from_string("ZZ"));
|
TS_ASSERT_EQUALS(702, xlnt::cell_reference::column_index_from_string("ZZ"));
|
||||||
TS_ASSERT_EQUALS(703, xlnt::cell::column_index_from_string("AAA"));
|
TS_ASSERT_EQUALS(703, xlnt::cell_reference::column_index_from_string("AAA"));
|
||||||
TS_ASSERT_EQUALS(728, xlnt::cell::column_index_from_string("AAZ"));
|
TS_ASSERT_EQUALS(728, xlnt::cell_reference::column_index_from_string("AAZ"));
|
||||||
TS_ASSERT_EQUALS(731, xlnt::cell::column_index_from_string("ABC"));
|
TS_ASSERT_EQUALS(731, xlnt::cell_reference::column_index_from_string("ABC"));
|
||||||
TS_ASSERT_EQUALS(1353, xlnt::cell::column_index_from_string("AZA"));
|
TS_ASSERT_EQUALS(1353, xlnt::cell_reference::column_index_from_string("AZA"));
|
||||||
TS_ASSERT_EQUALS(18253, xlnt::cell::column_index_from_string("ZZA"));
|
TS_ASSERT_EQUALS(18253, xlnt::cell_reference::column_index_from_string("ZZA"));
|
||||||
TS_ASSERT_EQUALS(18278, xlnt::cell::column_index_from_string("ZZZ"));
|
TS_ASSERT_EQUALS(18278, xlnt::cell_reference::column_index_from_string("ZZZ"));
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_bad_column_index()
|
void test_bad_column_index()
|
||||||
{
|
{
|
||||||
for(auto bad_string : {"JJJJ", "", "$", "1"})
|
for(auto bad_string : {"JJJJ", "", "$", "1"})
|
||||||
{
|
{
|
||||||
TS_ASSERT_THROWS_ANYTHING(xlnt::cell::column_index_from_string(bad_string));
|
TS_ASSERT_THROWS_ANYTHING(xlnt::cell_reference::column_index_from_string(bad_string));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_column_letter_boundries()
|
void test_column_letter_boundries()
|
||||||
{
|
{
|
||||||
TS_ASSERT_THROWS_ANYTHING(xlnt::cell::get_column_letter(0));
|
TS_ASSERT_THROWS_ANYTHING(xlnt::cell_reference::column_string_from_index(0));
|
||||||
TS_ASSERT_THROWS_ANYTHING(xlnt::cell::get_column_letter(18279));
|
TS_ASSERT_THROWS_ANYTHING(xlnt::cell_reference::column_string_from_index(18279));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void test_column_letter()
|
void test_column_letter()
|
||||||
{
|
{
|
||||||
TS_ASSERT_EQUALS("ZZZ", xlnt::cell::get_column_letter(18278));
|
TS_ASSERT_EQUALS("ZZZ", xlnt::cell_reference::column_string_from_index(18278));
|
||||||
TS_ASSERT_EQUALS("JJJ", xlnt::cell::get_column_letter(7030));
|
TS_ASSERT_EQUALS("JJJ", xlnt::cell_reference::column_string_from_index(7030));
|
||||||
TS_ASSERT_EQUALS("AB", xlnt::cell::get_column_letter(28));
|
TS_ASSERT_EQUALS("AB", xlnt::cell_reference::column_string_from_index(28));
|
||||||
TS_ASSERT_EQUALS("AA", xlnt::cell::get_column_letter(27));
|
TS_ASSERT_EQUALS("AA", xlnt::cell_reference::column_string_from_index(27));
|
||||||
TS_ASSERT_EQUALS("Z", xlnt::cell::get_column_letter(26));
|
TS_ASSERT_EQUALS("Z", xlnt::cell_reference::column_string_from_index(26));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,7 @@ public:
|
||||||
|
|
||||||
void test_dump_sheet_title()
|
void test_dump_sheet_title()
|
||||||
{
|
{
|
||||||
xlnt::workbook wb(xlnt::optimized::write);
|
xlnt::workbook wb(xlnt::optimization::write);
|
||||||
auto ws = wb.create_sheet("Test1");
|
auto ws = wb.create_sheet("Test1");
|
||||||
wb.save(temp_file.GetFilename());
|
wb.save(temp_file.GetFilename());
|
||||||
xlnt::workbook wb2;
|
xlnt::workbook wb2;
|
||||||
|
@ -32,14 +32,14 @@ public:
|
||||||
{
|
{
|
||||||
auto test_filename = temp_file.GetFilename();
|
auto test_filename = temp_file.GetFilename();
|
||||||
|
|
||||||
xlnt::workbook wb(xlnt::optimized::write);
|
xlnt::workbook wb(xlnt::optimization::write);
|
||||||
auto ws = wb.create_sheet();
|
auto ws = wb.create_sheet();
|
||||||
|
|
||||||
std::vector<std::string> letters;
|
std::vector<std::string> letters;
|
||||||
|
|
||||||
for(int i = 0; i < 20; i++)
|
for(int i = 0; i < 20; i++)
|
||||||
{
|
{
|
||||||
letters.push_back(xlnt::cell::get_column_letter(i + 1));
|
letters.push_back(xlnt::cell_reference::column_string_from_index(i + 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::vector<std::string>> expected_rows;
|
std::vector<std::vector<std::string>> expected_rows;
|
||||||
|
@ -121,7 +121,7 @@ public:
|
||||||
{
|
{
|
||||||
auto test_filename = temp_file.GetFilename();
|
auto test_filename = temp_file.GetFilename();
|
||||||
|
|
||||||
xlnt::workbook wb(xlnt::optimized::write);
|
xlnt::workbook wb(xlnt::optimization::write);
|
||||||
|
|
||||||
for(int i = 0; i < 2; i++) // over 200 worksheets should raise an OSError("too many open files")
|
for(int i = 0; i < 2; i++) // over 200 worksheets should raise an OSError("too many open files")
|
||||||
{
|
{
|
||||||
|
@ -135,7 +135,7 @@ public:
|
||||||
{
|
{
|
||||||
auto test_filename = temp_file.GetFilename();
|
auto test_filename = temp_file.GetFilename();
|
||||||
|
|
||||||
xlnt::workbook wb(xlnt::optimized::write);
|
xlnt::workbook wb(xlnt::optimization::write);
|
||||||
auto ws = wb.create_sheet();
|
auto ws = wb.create_sheet();
|
||||||
|
|
||||||
std::vector<std::string> to_append = {"hello"};
|
std::vector<std::string> to_append = {"hello"};
|
||||||
|
@ -148,7 +148,7 @@ public:
|
||||||
|
|
||||||
void test_append_after_save()
|
void test_append_after_save()
|
||||||
{
|
{
|
||||||
xlnt::workbook wb(xlnt::optimized::write);
|
xlnt::workbook wb(xlnt::optimization::write);
|
||||||
auto ws = wb.create_sheet();
|
auto ws = wb.create_sheet();
|
||||||
|
|
||||||
std::vector<std::string> to_append = {"hello"};
|
std::vector<std::string> to_append = {"hello"};
|
||||||
|
|
|
@ -1,58 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
#include <cxxtest/TestSuite.h>
|
|
||||||
|
|
||||||
#include "../xlnt.h"
|
|
||||||
|
|
||||||
class NullableTestSuite : public CxxTest::TestSuite
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
NullableTestSuite() : integer_non_null_5(5), double_non_null_5(5.0), double_non_null_6(6.0)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void test_has_value()
|
|
||||||
{
|
|
||||||
TS_ASSERT(!integer_null.has_value())
|
|
||||||
TS_ASSERT(integer_non_null_5.has_value())
|
|
||||||
}
|
|
||||||
|
|
||||||
void test_get_value()
|
|
||||||
{
|
|
||||||
TS_ASSERT_THROWS_ANYTHING(integer_null.get_value())
|
|
||||||
TS_ASSERT_THROWS_NOTHING(integer_non_null_5.get_value())
|
|
||||||
TS_ASSERT_EQUALS(integer_non_null_5.get_value(), 5)
|
|
||||||
}
|
|
||||||
|
|
||||||
void test_equality()
|
|
||||||
{
|
|
||||||
TS_ASSERT_EQUALS(integer_null, integer_null_2)
|
|
||||||
TS_ASSERT_DIFFERS(integer_null, integer_non_null_5)
|
|
||||||
TS_ASSERT_DIFFERS(double_non_null_5, double_non_null_6)
|
|
||||||
}
|
|
||||||
|
|
||||||
void test_assignment()
|
|
||||||
{
|
|
||||||
xlnt::nullable<double> double_non_null_6_assigned;
|
|
||||||
double_non_null_6_assigned = double_non_null_6;
|
|
||||||
TS_ASSERT(double_non_null_6_assigned.has_value())
|
|
||||||
TS_ASSERT_EQUALS(double_non_null_6_assigned.get_value(), 6.0)
|
|
||||||
}
|
|
||||||
|
|
||||||
void test_copy_constructor()
|
|
||||||
{
|
|
||||||
xlnt::nullable<int> integer_non_null_5_copy(integer_non_null_5);
|
|
||||||
TS_ASSERT(integer_non_null_5_copy.has_value())
|
|
||||||
TS_ASSERT_EQUALS(integer_non_null_5_copy.get_value(), 5)
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
xlnt::nullable<int> integer_null;
|
|
||||||
xlnt::nullable<int> integer_null_2;
|
|
||||||
xlnt::nullable<int> integer_non_null_5;
|
|
||||||
xlnt::nullable<double> double_null;
|
|
||||||
xlnt::nullable<double> double_non_null_5;
|
|
||||||
xlnt::nullable<double> double_non_null_6;
|
|
||||||
};
|
|
|
@ -1,10 +1,13 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
|
#include <fstream>
|
||||||
|
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
#include <mach-o/dyld.h>
|
#include <mach-o/dyld.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
#elif defined(_WIN32)
|
#elif defined(_WIN32)
|
||||||
|
#include <Shlwapi.h>
|
||||||
#include <Windows.h>
|
#include <Windows.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -16,6 +19,7 @@ public:
|
||||||
std::string fixed;
|
std::string fixed;
|
||||||
std::stringstream ss(windows_path);
|
std::stringstream ss(windows_path);
|
||||||
std::string part;
|
std::string part;
|
||||||
|
|
||||||
while(std::getline(ss, part, '\\'))
|
while(std::getline(ss, part, '\\'))
|
||||||
{
|
{
|
||||||
if(fixed == "")
|
if(fixed == "")
|
||||||
|
@ -27,34 +31,82 @@ public:
|
||||||
fixed += "/" + part;
|
fixed += "/" + part;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return fixed;
|
return fixed;
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string GetExecutableDirectory()
|
static std::string GetExecutableDirectory()
|
||||||
{
|
{
|
||||||
|
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
|
|
||||||
std::array<char, 1024> path;
|
std::array<char, 1024> path;
|
||||||
uint32_t size = static_cast<uint32_t>(path.size());
|
uint32_t size = static_cast<uint32_t>(path.size());
|
||||||
|
|
||||||
if (_NSGetExecutablePath(path.data(), &size) == 0)
|
if (_NSGetExecutablePath(path.data(), &size) == 0)
|
||||||
{
|
{
|
||||||
return std::string(path.begin(), std::find(path.begin(), path.end(), '\0') - 9);
|
return std::string(path.begin(), std::find(path.begin(), path.end(), '\0') - 9);
|
||||||
}
|
}
|
||||||
|
|
||||||
throw std::runtime_error("buffer too small, " + std::to_string(path.size()) + ", should be: " + std::to_string(size));
|
throw std::runtime_error("buffer too small, " + std::to_string(path.size()) + ", should be: " + std::to_string(size));
|
||||||
|
|
||||||
#elif defined(_WIN32)
|
#elif defined(_WIN32)
|
||||||
|
|
||||||
std::array<TCHAR, MAX_PATH> buffer;
|
std::array<TCHAR, MAX_PATH> buffer;
|
||||||
DWORD result = GetModuleFileName(nullptr, buffer.data(), buffer.size());
|
DWORD result = GetModuleFileName(nullptr, buffer.data(), buffer.size());
|
||||||
|
|
||||||
if(result == 0 || result == buffer.size())
|
if(result == 0 || result == buffer.size())
|
||||||
{
|
{
|
||||||
throw std::runtime_error("GetModuleFileName failed or buffer was too small");
|
throw std::runtime_error("GetModuleFileName failed or buffer was too small");
|
||||||
}
|
}
|
||||||
return WindowsToUniversalPath(std::string(buffer.begin(), buffer.begin() + result - 13)) + "/";
|
return WindowsToUniversalPath(std::string(buffer.begin(), buffer.begin() + result - 13)) + "/";
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
throw std::runtime_error("not implmented");
|
throw std::runtime_error("not implmented");
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string GetDataDirectory()
|
static std::string GetDataDirectory()
|
||||||
{
|
{
|
||||||
return GetExecutableDirectory() + "../source/tests/test_data";
|
return GetExecutableDirectory() + "../source/tests/test_data";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void CopyFile(const std::string &source, const std::string &destination, bool overwrite)
|
||||||
|
{
|
||||||
|
if(!overwrite && FileExists(destination))
|
||||||
|
{
|
||||||
|
throw std::runtime_error("destination file already exists and overwrite==false");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ifstream src(source, std::ios::binary);
|
||||||
|
std::ofstream dst(destination, std::ios::binary);
|
||||||
|
|
||||||
|
dst << src.rdbuf();
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool FileExists(const std::string &path)
|
||||||
|
{
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
|
||||||
|
std::wstring path_wide(path.begin(), path.end());
|
||||||
|
return PathFileExists(path_wide.c_str()) && !PathIsDirectory(path_wide.c_str());
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
struct stat fileAtt;
|
||||||
|
|
||||||
|
if (stat(path.c_str(), &fileAtt) != 0)
|
||||||
|
{
|
||||||
|
throw std::runtime_error("stat failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
return S_ISREG(fileAtt.st_mode);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
}
|
||||||
};
|
};
|
|
@ -37,9 +37,9 @@ public:
|
||||||
TS_ASSERT_DIFFERS(ws, nullptr);
|
TS_ASSERT_DIFFERS(ws, nullptr);
|
||||||
if(!(ws == nullptr))
|
if(!(ws == nullptr))
|
||||||
{
|
{
|
||||||
TS_ASSERT_EQUALS(ws.cell("G5"), "hello");
|
TS_ASSERT_EQUALS(ws.get_cell("G5"), "hello");
|
||||||
TS_ASSERT_EQUALS(ws.cell("D30"), 30);
|
TS_ASSERT_EQUALS(ws.get_cell("D30"), 30);
|
||||||
TS_ASSERT_EQUALS(ws.cell("K9"), 0.09);
|
TS_ASSERT_EQUALS(ws.get_cell("K9"), 0.09);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,8 +67,8 @@ public:
|
||||||
wb.load(path);
|
wb.load(path);
|
||||||
auto sheet2 = wb.get_sheet_by_name("Sheet2 - Numbers");
|
auto sheet2 = wb.get_sheet_by_name("Sheet2 - Numbers");
|
||||||
TS_ASSERT_DIFFERS(sheet2, nullptr);
|
TS_ASSERT_DIFFERS(sheet2, nullptr);
|
||||||
TS_ASSERT_EQUALS("This is cell G5", sheet2.cell("G5"));
|
TS_ASSERT_EQUALS("This is cell G5", sheet2.get_cell("G5"));
|
||||||
TS_ASSERT_EQUALS(18, sheet2.cell("D18"));
|
TS_ASSERT_EQUALS(18, sheet2.get_cell("D18"));
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_read_nostring_workbook()
|
void test_read_nostring_workbook()
|
||||||
|
@ -110,7 +110,7 @@ public:
|
||||||
wb.load(path);
|
wb.load(path);
|
||||||
auto sheet2 = wb.get_sheet_by_name("Sheet2 - Numbers");
|
auto sheet2 = wb.get_sheet_by_name("Sheet2 - Numbers");
|
||||||
auto dimensions = sheet2.calculate_dimension();
|
auto dimensions = sheet2.calculate_dimension();
|
||||||
TS_ASSERT_EQUALS("D1:K30", dimensions);
|
TS_ASSERT_EQUALS("D1:K30", dimensions.to_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_get_highest_row_iter()
|
void test_get_highest_row_iter()
|
||||||
|
@ -132,27 +132,27 @@ public:
|
||||||
|
|
||||||
void test_read_general_style()
|
void test_read_general_style()
|
||||||
{
|
{
|
||||||
TS_ASSERT_EQUALS(worksheet_with_styles.cell("A1").get_style().get_number_format().get_format_code(), xlnt::number_format::format::general);
|
TS_ASSERT_EQUALS(worksheet_with_styles.get_cell("A1").get_style().get_number_format().get_format_code(), xlnt::number_format::format::general);
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_read_date_style()
|
void test_read_date_style()
|
||||||
{
|
{
|
||||||
TS_ASSERT_EQUALS(worksheet_with_styles.cell("A2").get_style().get_number_format().get_format_code(), xlnt::number_format::format::date_xlsx14);
|
TS_ASSERT_EQUALS(worksheet_with_styles.get_cell("A2").get_style().get_number_format().get_format_code(), xlnt::number_format::format::date_xlsx14);
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_read_number_style()
|
void test_read_number_style()
|
||||||
{
|
{
|
||||||
TS_ASSERT_EQUALS(worksheet_with_styles.cell("A3").get_style().get_number_format().get_format_code(), xlnt::number_format::format::number00);
|
TS_ASSERT_EQUALS(worksheet_with_styles.get_cell("A3").get_style().get_number_format().get_format_code(), xlnt::number_format::format::number00);
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_read_time_style()
|
void test_read_time_style()
|
||||||
{
|
{
|
||||||
TS_ASSERT_EQUALS(worksheet_with_styles.cell("A4").get_style().get_number_format().get_format_code(), xlnt::number_format::format::date_time3);
|
TS_ASSERT_EQUALS(worksheet_with_styles.get_cell("A4").get_style().get_number_format().get_format_code(), xlnt::number_format::format::date_time3);
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_read_percentage_style()
|
void test_read_percentage_style()
|
||||||
{
|
{
|
||||||
TS_ASSERT_EQUALS(worksheet_with_styles.cell("A5").get_style().get_number_format().get_format_code(), xlnt::number_format::format::percentage00)
|
TS_ASSERT_EQUALS(worksheet_with_styles.get_cell("A5").get_style().get_number_format().get_format_code(), xlnt::number_format::format::percentage00)
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_read_win_base_date()
|
void test_read_win_base_date()
|
||||||
|
@ -167,12 +167,12 @@ public:
|
||||||
|
|
||||||
void test_read_date_style_mac()
|
void test_read_date_style_mac()
|
||||||
{
|
{
|
||||||
TS_ASSERT_EQUALS(mac_ws.cell("A1").get_style().get_number_format().get_format_code(), xlnt::number_format::format::date_xlsx14);
|
TS_ASSERT_EQUALS(mac_ws.get_cell("A1").get_style().get_number_format().get_format_code(), xlnt::number_format::format::date_xlsx14);
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_read_date_style_win()
|
void test_read_date_style_win()
|
||||||
{
|
{
|
||||||
TS_ASSERT_EQUALS(win_ws.cell("A1").get_style().get_number_format().get_format_code(), xlnt::number_format::format::date_xlsx14);
|
TS_ASSERT_EQUALS(win_ws.get_cell("A1").get_style().get_number_format().get_format_code(), xlnt::number_format::format::date_xlsx14);
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_read_date_value()
|
void test_read_date_value()
|
||||||
|
|
|
@ -36,7 +36,7 @@ public:
|
||||||
|
|
||||||
void test_create_sheet_readonly()
|
void test_create_sheet_readonly()
|
||||||
{
|
{
|
||||||
xlnt::workbook wb(xlnt::optimized::read);
|
xlnt::workbook wb(xlnt::optimization::read);
|
||||||
TS_ASSERT_THROWS_ANYTHING(wb.create_sheet());
|
TS_ASSERT_THROWS_ANYTHING(wb.create_sheet());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -122,7 +122,7 @@ public:
|
||||||
|
|
||||||
void test_create_sheet_readonly2()
|
void test_create_sheet_readonly2()
|
||||||
{
|
{
|
||||||
xlnt::workbook wb(xlnt::optimized::read);
|
xlnt::workbook wb(xlnt::optimization::read);
|
||||||
TS_ASSERT_THROWS_ANYTHING(wb.create_sheet());
|
TS_ASSERT_THROWS_ANYTHING(wb.create_sheet());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -159,8 +159,7 @@ public:
|
||||||
{
|
{
|
||||||
xlnt::workbook wb;
|
xlnt::workbook wb;
|
||||||
auto new_sheet = wb.create_sheet();
|
auto new_sheet = wb.create_sheet();
|
||||||
xlnt::named_range named_range(new_sheet, "A1");
|
auto named_range = wb.create_named_range("test_nr", new_sheet, "A1");
|
||||||
wb.add_named_range("test_nr", named_range);
|
|
||||||
auto named_ranges_list = wb.get_named_ranges();
|
auto named_ranges_list = wb.get_named_ranges();
|
||||||
TS_ASSERT_DIFFERS(std::find(named_ranges_list.begin(), named_ranges_list.end(), named_range), named_ranges_list.end());
|
TS_ASSERT_DIFFERS(std::find(named_ranges_list.begin(), named_ranges_list.end(), named_range), named_ranges_list.end());
|
||||||
}
|
}
|
||||||
|
@ -169,8 +168,7 @@ public:
|
||||||
{
|
{
|
||||||
xlnt::workbook wb;
|
xlnt::workbook wb;
|
||||||
auto new_sheet = wb.create_sheet();
|
auto new_sheet = wb.create_sheet();
|
||||||
xlnt::named_range named_range(new_sheet, "A1");
|
auto named_range = wb.create_named_range("test_nr", new_sheet, "A1");
|
||||||
wb.add_named_range("test_nr", named_range);
|
|
||||||
auto found_named_range = wb.get_named_range("test_nr", new_sheet);
|
auto found_named_range = wb.get_named_range("test_nr", new_sheet);
|
||||||
TS_ASSERT_EQUALS(named_range, found_named_range);
|
TS_ASSERT_EQUALS(named_range, found_named_range);
|
||||||
}
|
}
|
||||||
|
@ -179,8 +177,7 @@ public:
|
||||||
{
|
{
|
||||||
xlnt::workbook wb;
|
xlnt::workbook wb;
|
||||||
auto new_sheet = wb.create_sheet();
|
auto new_sheet = wb.create_sheet();
|
||||||
xlnt::named_range named_range(new_sheet, "A1");
|
auto named_range = wb.create_named_range("test_nr", new_sheet, "A1");
|
||||||
wb.add_named_range("test_nr", named_range);
|
|
||||||
wb.remove_named_range(named_range);
|
wb.remove_named_range(named_range);
|
||||||
auto named_ranges_list = wb.get_named_ranges();
|
auto named_ranges_list = wb.get_named_ranges();
|
||||||
TS_ASSERT_EQUALS(std::find(named_ranges_list.begin(), named_ranges_list.end(), named_range), named_ranges_list.end());
|
TS_ASSERT_EQUALS(std::find(named_ranges_list.begin(), named_ranges_list.end(), named_range), named_ranges_list.end());
|
||||||
|
@ -191,9 +188,7 @@ public:
|
||||||
TemporaryFile temp_file;
|
TemporaryFile temp_file;
|
||||||
xlnt::workbook wb;
|
xlnt::workbook wb;
|
||||||
auto new_sheet = wb.create_sheet();
|
auto new_sheet = wb.create_sheet();
|
||||||
xlnt::named_range named_range(new_sheet, "A1");
|
wb.create_named_range("test_nr", new_sheet, "A1");
|
||||||
named_range.set_scope(new_sheet);
|
|
||||||
wb.add_named_range("test_nr", named_range);
|
|
||||||
auto dest_filename = temp_file.GetFilename();
|
auto dest_filename = temp_file.GetFilename();
|
||||||
wb.save(dest_filename);
|
wb.save(dest_filename);
|
||||||
}
|
}
|
||||||
|
@ -232,7 +227,7 @@ public:
|
||||||
float float_value = 1.0 / 3.0;
|
float float_value = 1.0 / 3.0;
|
||||||
xlnt::workbook book;
|
xlnt::workbook book;
|
||||||
auto sheet = book.get_active_sheet();
|
auto sheet = book.get_active_sheet();
|
||||||
sheet.cell("A1") = float_value;
|
sheet.get_cell("A1") = float_value;
|
||||||
auto dest_filename = temp_file.GetFilename();
|
auto dest_filename = temp_file.GetFilename();
|
||||||
book.save(dest_filename);
|
book.save(dest_filename);
|
||||||
|
|
||||||
|
@ -240,6 +235,6 @@ public:
|
||||||
test_book.load(dest_filename);
|
test_book.load(dest_filename);
|
||||||
auto test_sheet = test_book.get_active_sheet();
|
auto test_sheet = test_book.get_active_sheet();
|
||||||
|
|
||||||
TS_ASSERT_LESS_THAN_EQUALS(std::stod(test_sheet.cell("A1").get_value()) - float_value, 0.001);
|
TS_ASSERT_LESS_THAN_EQUALS(std::stod(test_sheet.get_cell("A1").get_value()) - float_value, 0.001);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -30,8 +30,8 @@ public:
|
||||||
void test_get_cell()
|
void test_get_cell()
|
||||||
{
|
{
|
||||||
xlnt::worksheet ws(wb);
|
xlnt::worksheet ws(wb);
|
||||||
auto cell = ws.cell("A1");
|
auto cell = ws.get_cell("A1");
|
||||||
TS_ASSERT_EQUALS(cell.get_coordinate(), "A1");
|
TS_ASSERT_EQUALS(cell.get_reference().to_string(), "A1");
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_set_bad_title()
|
void test_set_bad_title()
|
||||||
|
@ -54,16 +54,16 @@ public:
|
||||||
void test_worksheet_dimension()
|
void test_worksheet_dimension()
|
||||||
{
|
{
|
||||||
xlnt::worksheet ws(wb);
|
xlnt::worksheet ws(wb);
|
||||||
ws.cell("A1") = "AAA";
|
ws.get_cell("A1") = "AAA";
|
||||||
TS_ASSERT_EQUALS("A1:A1", ws.calculate_dimension());
|
TS_ASSERT_EQUALS("A1", ws.calculate_dimension().to_string());
|
||||||
ws.cell("B12") = "AAA";
|
ws.get_cell("B12") = "AAA";
|
||||||
TS_ASSERT_EQUALS("A1:B12", ws.calculate_dimension());
|
TS_ASSERT_EQUALS("A1:B12", ws.calculate_dimension().to_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_worksheet_range()
|
void test_worksheet_range()
|
||||||
{
|
{
|
||||||
xlnt::worksheet ws(wb);
|
xlnt::worksheet ws(wb);
|
||||||
auto xlrange = ws.range("A1:C4");
|
auto xlrange = ws.get_range("A1:C4");
|
||||||
TS_ASSERT_EQUALS(4, xlrange.size());
|
TS_ASSERT_EQUALS(4, xlrange.size());
|
||||||
TS_ASSERT_EQUALS(3, xlrange[0].size());
|
TS_ASSERT_EQUALS(3, xlrange[0].size());
|
||||||
}
|
}
|
||||||
|
@ -72,7 +72,7 @@ public:
|
||||||
{
|
{
|
||||||
xlnt::worksheet ws(wb);
|
xlnt::worksheet ws(wb);
|
||||||
wb.create_named_range("test_range", ws, "C5");
|
wb.create_named_range("test_range", ws, "C5");
|
||||||
auto xlrange = ws.range("test_range");
|
auto xlrange = ws.get_named_range("test_range");
|
||||||
TS_ASSERT_EQUALS(1, xlrange.size());
|
TS_ASSERT_EQUALS(1, xlrange.size());
|
||||||
TS_ASSERT_EQUALS(1, xlrange[0].size());
|
TS_ASSERT_EQUALS(1, xlrange[0].size());
|
||||||
TS_ASSERT_EQUALS(5, xlrange[0][0].get_row());
|
TS_ASSERT_EQUALS(5, xlrange[0][0].get_row());
|
||||||
|
@ -81,7 +81,7 @@ public:
|
||||||
void test_bad_named_range()
|
void test_bad_named_range()
|
||||||
{
|
{
|
||||||
xlnt::worksheet ws(wb);
|
xlnt::worksheet ws(wb);
|
||||||
TS_ASSERT_THROWS_ANYTHING(ws.range("bad_range"));
|
TS_ASSERT_THROWS_ANYTHING(ws.get_range("bad_range"));
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_named_range_wrong_sheet()
|
void test_named_range_wrong_sheet()
|
||||||
|
@ -89,39 +89,39 @@ public:
|
||||||
xlnt::worksheet ws1(wb);
|
xlnt::worksheet ws1(wb);
|
||||||
xlnt::worksheet ws2(wb);
|
xlnt::worksheet ws2(wb);
|
||||||
wb.create_named_range("wrong_sheet_range", ws1, "C5");
|
wb.create_named_range("wrong_sheet_range", ws1, "C5");
|
||||||
TS_ASSERT_THROWS_ANYTHING(ws2.range("wrong_sheet_range"));
|
TS_ASSERT_THROWS_ANYTHING(ws2.get_named_range("wrong_sheet_range"));
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_cell_offset()
|
void test_cell_offset()
|
||||||
{
|
{
|
||||||
xlnt::worksheet ws(wb);
|
xlnt::worksheet ws(wb);
|
||||||
TS_ASSERT_EQUALS("C17", ws.cell("B15").get_offset(2, 1).get_coordinate());
|
TS_ASSERT_EQUALS("C17", ws.get_cell("B15").get_offset(2, 1).get_reference().to_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_range_offset()
|
void test_range_offset()
|
||||||
{
|
{
|
||||||
xlnt::worksheet ws(wb);
|
xlnt::worksheet ws(wb);
|
||||||
auto xlrange = ws.range("A1:C4", 1, 3);
|
auto xlrange = ws.get_range(xlnt::range_reference("A1:C4").make_offset(3, 1));
|
||||||
TS_ASSERT_EQUALS(4, xlrange.size());
|
TS_ASSERT_EQUALS(4, xlrange.size());
|
||||||
TS_ASSERT_EQUALS(3, xlrange[0].size());
|
TS_ASSERT_EQUALS(3, xlrange[0].size());
|
||||||
TS_ASSERT_EQUALS("D2", xlrange[0][0].get_coordinate());
|
TS_ASSERT_EQUALS("D2", xlrange[0][0].get_reference().to_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_cell_alternate_coordinates()
|
void test_cell_alternate_coordinates()
|
||||||
{
|
{
|
||||||
xlnt::worksheet ws(wb);
|
xlnt::worksheet ws(wb);
|
||||||
auto cell = ws.cell(4, 8);
|
auto cell = ws.get_cell(xlnt::cell_reference(4, 8));
|
||||||
TS_ASSERT_EQUALS("E9", cell.get_coordinate());
|
TS_ASSERT_EQUALS("E9", cell.get_reference().to_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_cell_range_name()
|
void test_cell_range_name()
|
||||||
{
|
{
|
||||||
xlnt::worksheet ws(wb);
|
xlnt::worksheet ws(wb);
|
||||||
wb.create_named_range("test_range_single", ws, "B12");
|
wb.create_named_range("test_range_single", ws, "B12");
|
||||||
TS_ASSERT_THROWS(ws.cell("test_range_single"), xlnt::bad_cell_coordinates);
|
TS_ASSERT_THROWS(ws.get_cell("test_range_single"), xlnt::bad_cell_coordinates);
|
||||||
auto c_range_name = ws.range("test_range_single");
|
auto c_range_name = ws.get_named_range("test_range_single");
|
||||||
auto c_range_coord = ws.range("B12");
|
auto c_range_coord = ws.get_range("B12");
|
||||||
auto c_cell = ws.cell("B12");
|
auto c_cell = ws.get_cell("B12");
|
||||||
TS_ASSERT_EQUALS(c_range_coord, c_range_name);
|
TS_ASSERT_EQUALS(c_range_coord, c_range_name);
|
||||||
TS_ASSERT(c_range_coord[0][0] == c_cell);
|
TS_ASSERT(c_range_coord[0][0] == c_cell);
|
||||||
}
|
}
|
||||||
|
@ -130,13 +130,13 @@ public:
|
||||||
{
|
{
|
||||||
xlnt::worksheet ws(wb);
|
xlnt::worksheet ws(wb);
|
||||||
|
|
||||||
ws.cell("A1") = "";
|
ws.get_cell("A1") = "";
|
||||||
ws.cell("B2") = "0";
|
ws.get_cell("B2") = "0";
|
||||||
ws.cell("C4") = 0;
|
ws.get_cell("C4") = 0;
|
||||||
|
|
||||||
ws.garbage_collect();
|
ws.garbage_collect();
|
||||||
|
|
||||||
std::list<xlnt::cell> comparison_cells = {ws.cell("B2"), ws.cell("C4")};
|
std::list<xlnt::cell> comparison_cells = {ws.get_cell("B2"), ws.get_cell("C4")};
|
||||||
|
|
||||||
for(auto cell : ws.get_cell_collection())
|
for(auto cell : ws.get_cell_collection())
|
||||||
{
|
{
|
||||||
|
@ -154,16 +154,16 @@ public:
|
||||||
|
|
||||||
TS_ASSERT_EQUALS(ws.get_relationships().size(), 0);
|
TS_ASSERT_EQUALS(ws.get_relationships().size(), 0);
|
||||||
|
|
||||||
ws.cell("A1").set_hyperlink("http:test.com");
|
ws.get_cell("A1").set_hyperlink("http:test.com");
|
||||||
TS_ASSERT_EQUALS(ws.get_relationships().size(), 1);
|
TS_ASSERT_EQUALS(ws.get_relationships().size(), 1);
|
||||||
TS_ASSERT_EQUALS("rId1", ws.cell("A1").get_hyperlink_rel_id());
|
TS_ASSERT_EQUALS("rId1", ws.get_cell("A1").get_hyperlink_rel_id());
|
||||||
TS_ASSERT_EQUALS("rId1", ws.get_relationships()[0].get_id());
|
TS_ASSERT_EQUALS("rId1", ws.get_relationships()[0].get_id());
|
||||||
TS_ASSERT_EQUALS("http:test.com", ws.get_relationships()[0].get_target_uri());
|
TS_ASSERT_EQUALS("http:test.com", ws.get_relationships()[0].get_target_uri());
|
||||||
TS_ASSERT_EQUALS(xlnt::target_mode::external, ws.get_relationships()[0].get_target_mode());
|
TS_ASSERT_EQUALS(xlnt::target_mode::external, ws.get_relationships()[0].get_target_mode());
|
||||||
|
|
||||||
ws.cell("A2").set_hyperlink("http:test2.com");
|
ws.get_cell("A2").set_hyperlink("http:test2.com");
|
||||||
TS_ASSERT_EQUALS(ws.get_relationships().size(), 2);
|
TS_ASSERT_EQUALS(ws.get_relationships().size(), 2);
|
||||||
TS_ASSERT_EQUALS("rId2", ws.cell("A2").get_hyperlink_rel_id());
|
TS_ASSERT_EQUALS("rId2", ws.get_cell("A2").get_hyperlink_rel_id());
|
||||||
TS_ASSERT_EQUALS("rId2", ws.get_relationships()[1].get_id());
|
TS_ASSERT_EQUALS("rId2", ws.get_relationships()[1].get_id());
|
||||||
TS_ASSERT_EQUALS("http:test2.com", ws.get_relationships()[1].get_target_uri());
|
TS_ASSERT_EQUALS("http:test2.com", ws.get_relationships()[1].get_target_uri());
|
||||||
TS_ASSERT_EQUALS(xlnt::target_mode::external, ws.get_relationships()[1].get_target_mode());
|
TS_ASSERT_EQUALS(xlnt::target_mode::external, ws.get_relationships()[1].get_target_mode());
|
||||||
|
@ -180,8 +180,8 @@ public:
|
||||||
|
|
||||||
ws.append(std::vector<std::string> {"This is A1", "This is B1"});
|
ws.append(std::vector<std::string> {"This is A1", "This is B1"});
|
||||||
|
|
||||||
TS_ASSERT_EQUALS("This is A1", ws.cell("A1"));
|
TS_ASSERT_EQUALS("This is A1", ws.get_cell("A1"));
|
||||||
TS_ASSERT_EQUALS("This is B1", ws.cell("B1"));
|
TS_ASSERT_EQUALS("This is B1", ws.get_cell("B1"));
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_append_dict_letter()
|
void test_append_dict_letter()
|
||||||
|
@ -190,8 +190,8 @@ public:
|
||||||
|
|
||||||
ws.append(std::unordered_map<std::string, std::string> {{"A", "This is A1"}, {"C", "This is C1"}});
|
ws.append(std::unordered_map<std::string, std::string> {{"A", "This is A1"}, {"C", "This is C1"}});
|
||||||
|
|
||||||
TS_ASSERT_EQUALS("This is A1", ws.cell("A1"));
|
TS_ASSERT_EQUALS("This is A1", ws.get_cell("A1"));
|
||||||
TS_ASSERT_EQUALS("This is C1", ws.cell("C1"));
|
TS_ASSERT_EQUALS("This is C1", ws.get_cell("C1"));
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_append_dict_index()
|
void test_append_dict_index()
|
||||||
|
@ -200,8 +200,8 @@ public:
|
||||||
|
|
||||||
ws.append(std::unordered_map<int, std::string> {{0, "This is A1"}, {2, "This is C1"}});
|
ws.append(std::unordered_map<int, std::string> {{0, "This is A1"}, {2, "This is C1"}});
|
||||||
|
|
||||||
TS_ASSERT_EQUALS("This is A1", ws.cell("A1"));
|
TS_ASSERT_EQUALS("This is A1", ws.get_cell("A1"));
|
||||||
TS_ASSERT_EQUALS("This is C1", ws.cell("C1"));
|
TS_ASSERT_EQUALS("This is C1", ws.get_cell("C1"));
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_append_2d_list()
|
void test_append_2d_list()
|
||||||
|
@ -211,7 +211,7 @@ public:
|
||||||
ws.append(std::vector<std::string> {"This is A1", "This is B1"});
|
ws.append(std::vector<std::string> {"This is A1", "This is B1"});
|
||||||
ws.append(std::vector<std::string> {"This is A2", "This is B2"});
|
ws.append(std::vector<std::string> {"This is A2", "This is B2"});
|
||||||
|
|
||||||
auto vals = ws.range("A1:B2");
|
auto vals = ws.get_range("A1:B2");
|
||||||
|
|
||||||
TS_ASSERT_EQUALS(vals[0][0], "This is A1");
|
TS_ASSERT_EQUALS(vals[0][0], "This is A1");
|
||||||
TS_ASSERT_EQUALS(vals[0][1], "This is B1");
|
TS_ASSERT_EQUALS(vals[0][1], "This is B1");
|
||||||
|
@ -223,8 +223,8 @@ public:
|
||||||
{
|
{
|
||||||
xlnt::worksheet ws(wb);
|
xlnt::worksheet ws(wb);
|
||||||
|
|
||||||
ws.cell("A1") = "first";
|
ws.get_cell("A1") = "first";
|
||||||
ws.cell("C9") = "last";
|
ws.get_cell("C9") = "last";
|
||||||
|
|
||||||
auto rows = ws.rows();
|
auto rows = ws.rows();
|
||||||
|
|
||||||
|
@ -238,8 +238,8 @@ public:
|
||||||
{
|
{
|
||||||
xlnt::worksheet ws(wb);
|
xlnt::worksheet ws(wb);
|
||||||
|
|
||||||
ws.cell("A1") = "first";
|
ws.get_cell("A1") = "first";
|
||||||
ws.cell("C9") = "last";
|
ws.get_cell("C9") = "last";
|
||||||
|
|
||||||
auto cols = ws.columns();
|
auto cols = ws.columns();
|
||||||
|
|
||||||
|
@ -253,7 +253,7 @@ public:
|
||||||
{
|
{
|
||||||
xlnt::worksheet ws(wb);
|
xlnt::worksheet ws(wb);
|
||||||
|
|
||||||
ws.set_auto_filter(ws.range("a1:f1"));
|
ws.set_auto_filter(ws.get_range("a1:f1"));
|
||||||
TS_ASSERT_EQUALS(ws.get_auto_filter(), "A1:F1");
|
TS_ASSERT_EQUALS(ws.get_auto_filter(), "A1:F1");
|
||||||
|
|
||||||
ws.unset_auto_filter();
|
ws.unset_auto_filter();
|
||||||
|
@ -304,8 +304,8 @@ public:
|
||||||
|
|
||||||
std::vector<std::string> string_table = {"Cell A1", "Cell B1"};
|
std::vector<std::string> string_table = {"Cell A1", "Cell B1"};
|
||||||
|
|
||||||
ws.cell("A1") = "Cell A1";
|
ws.get_cell("A1") = "Cell A1";
|
||||||
ws.cell("B1") = "Cell B1";
|
ws.get_cell("B1") = "Cell B1";
|
||||||
auto xml_string = xlnt::writer::write_worksheet(ws, string_table);
|
auto xml_string = xlnt::writer::write_worksheet(ws, string_table);
|
||||||
pugi::xml_document doc;
|
pugi::xml_document doc;
|
||||||
doc.load(xml_string.c_str());
|
doc.load(xml_string.c_str());
|
||||||
|
@ -371,17 +371,17 @@ public:
|
||||||
{
|
{
|
||||||
xlnt::worksheet ws(wb);
|
xlnt::worksheet ws(wb);
|
||||||
|
|
||||||
ws.set_freeze_panes(ws.cell("b2"));
|
ws.freeze_panes(ws.get_cell("b2"));
|
||||||
TS_ASSERT_EQUALS(ws.get_freeze_panes().get_address(), "B2");
|
TS_ASSERT_EQUALS(ws.get_frozen_panes().to_string(), "B2");
|
||||||
|
|
||||||
ws.unfreeze_panes();
|
ws.unfreeze_panes();
|
||||||
TS_ASSERT_EQUALS(ws.get_freeze_panes(), nullptr);
|
TS_ASSERT(!ws.has_frozen_panes());
|
||||||
|
|
||||||
ws.set_freeze_panes("c5");
|
ws.freeze_panes("c5");
|
||||||
TS_ASSERT_EQUALS(ws.get_freeze_panes().get_address(), "C5");
|
TS_ASSERT_EQUALS(ws.get_frozen_panes().to_string(), "C5");
|
||||||
|
|
||||||
ws.set_freeze_panes(ws.cell("A1"));
|
ws.freeze_panes(ws.get_cell("A1"));
|
||||||
TS_ASSERT_EQUALS(ws.get_freeze_panes(), nullptr);
|
TS_ASSERT(!ws.has_frozen_panes());
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_printer_settings()
|
void test_printer_settings()
|
||||||
|
@ -389,7 +389,7 @@ public:
|
||||||
xlnt::worksheet ws(wb);
|
xlnt::worksheet ws(wb);
|
||||||
|
|
||||||
ws.get_page_setup().set_orientation(xlnt::page_setup::orientation::landscape);
|
ws.get_page_setup().set_orientation(xlnt::page_setup::orientation::landscape);
|
||||||
ws.get_page_setup().set_paper_size(xlnt::page_setup::paper_size::Tabloid);
|
ws.get_page_setup().set_paper_size(xlnt::page_setup::paper_size::tabloid);
|
||||||
ws.get_page_setup().set_fit_to_page(true);
|
ws.get_page_setup().set_fit_to_page(true);
|
||||||
ws.get_page_setup().set_fit_to_height(false);
|
ws.get_page_setup().set_fit_to_height(false);
|
||||||
ws.get_page_setup().set_fit_to_width(true);
|
ws.get_page_setup().set_fit_to_width(true);
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
|
|
||||||
#include "../xlnt.h"
|
#include "../xlnt.h"
|
||||||
#include "TemporaryFile.h"
|
#include "TemporaryFile.h"
|
||||||
|
#include "PathHelper.h"
|
||||||
|
|
||||||
class WriteTestSuite : public CxxTest::TestSuite
|
class WriteTestSuite : public CxxTest::TestSuite
|
||||||
{
|
{
|
||||||
|
@ -20,7 +21,7 @@ public:
|
||||||
xlnt::workbook wb;
|
xlnt::workbook wb;
|
||||||
auto dest_filename = temp_file.GetFilename();
|
auto dest_filename = temp_file.GetFilename();
|
||||||
wb.save(dest_filename);
|
wb.save(dest_filename);
|
||||||
TS_ASSERT(xlnt::file::exists(dest_filename));
|
TS_ASSERT(PathHelper::FileExists(dest_filename));
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_write_virtual_workbook()
|
void test_write_virtual_workbook()
|
||||||
|
@ -153,10 +154,10 @@ public:
|
||||||
{
|
{
|
||||||
xlnt::workbook wb;
|
xlnt::workbook wb;
|
||||||
auto ws = wb.create_sheet();
|
auto ws = wb.create_sheet();
|
||||||
ws.cell("A1").set_hyperlink("http:test.com");
|
ws.get_cell("A1").set_hyperlink("http:test.com");
|
||||||
TS_ASSERT_EQUALS("http:test.com", ws.cell("A1"));
|
TS_ASSERT_EQUALS("http:test.com", ws.get_cell("A1"));
|
||||||
ws.cell("A1") = "test";
|
ws.get_cell("A1") = "test";
|
||||||
TS_ASSERT_EQUALS("test", ws.cell("A1"));
|
TS_ASSERT_EQUALS("test", ws.get_cell("A1"));
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_write_auto_filter()
|
void test_write_auto_filter()
|
||||||
|
|
|
@ -21,7 +21,7 @@ int main( int argc, char *argv[] ) {
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
bool suite_CellTestSuite_init = false;
|
bool suite_CellTestSuite_init = false;
|
||||||
#include "c:\Users\taf656\Development\xlnt\source\tests\CellTestSuite.h"
|
#include "/Users/thomas/Development/xlnt/source/tests/CellTestSuite.h"
|
||||||
|
|
||||||
static CellTestSuite suite_CellTestSuite;
|
static CellTestSuite suite_CellTestSuite;
|
||||||
|
|
||||||
|
@ -184,7 +184,7 @@ public:
|
||||||
void runTest() { suite_CellTestSuite.test_is_not_date_color_format(); }
|
void runTest() { suite_CellTestSuite.test_is_not_date_color_format(); }
|
||||||
} testDescription_suite_CellTestSuite_test_is_not_date_color_format;
|
} testDescription_suite_CellTestSuite_test_is_not_date_color_format;
|
||||||
|
|
||||||
#include "c:\Users\taf656\Development\xlnt\source\tests\ChartTestSuite.h"
|
#include "/Users/thomas/Development/xlnt/source/tests/ChartTestSuite.h"
|
||||||
|
|
||||||
static ChartTestSuite suite_ChartTestSuite;
|
static ChartTestSuite suite_ChartTestSuite;
|
||||||
|
|
||||||
|
@ -275,7 +275,7 @@ public:
|
||||||
void runTest() { suite_ChartTestSuite.test_write_chart_scatter(); }
|
void runTest() { suite_ChartTestSuite.test_write_chart_scatter(); }
|
||||||
} testDescription_suite_ChartTestSuite_test_write_chart_scatter;
|
} testDescription_suite_ChartTestSuite_test_write_chart_scatter;
|
||||||
|
|
||||||
#include "c:\Users\taf656\Development\xlnt\source\tests\DumpTestSuite.h"
|
#include "/Users/thomas/Development/xlnt/source/tests/DumpTestSuite.h"
|
||||||
|
|
||||||
static DumpTestSuite suite_DumpTestSuite;
|
static DumpTestSuite suite_DumpTestSuite;
|
||||||
|
|
||||||
|
@ -318,7 +318,7 @@ public:
|
||||||
void runTest() { suite_DumpTestSuite.test_append_after_save(); }
|
void runTest() { suite_DumpTestSuite.test_append_after_save(); }
|
||||||
} testDescription_suite_DumpTestSuite_test_append_after_save;
|
} testDescription_suite_DumpTestSuite_test_append_after_save;
|
||||||
|
|
||||||
#include "c:\Users\taf656\Development\xlnt\source\tests\NamedRangeTestSuite.h"
|
#include "/Users/thomas/Development/xlnt/source/tests/NamedRangeTestSuite.h"
|
||||||
|
|
||||||
static NamedRangeTestSuite suite_NamedRangeTestSuite;
|
static NamedRangeTestSuite suite_NamedRangeTestSuite;
|
||||||
|
|
||||||
|
@ -409,44 +409,7 @@ public:
|
||||||
void runTest() { suite_NamedRangeTestSuite.test_can_be_saved(); }
|
void runTest() { suite_NamedRangeTestSuite.test_can_be_saved(); }
|
||||||
} testDescription_suite_NamedRangeTestSuite_test_can_be_saved;
|
} testDescription_suite_NamedRangeTestSuite_test_can_be_saved;
|
||||||
|
|
||||||
#include "c:\Users\taf656\Development\xlnt\source\tests\NullableTestSuite.h"
|
#include "/Users/thomas/Development/xlnt/source/tests/NumberFormatTestSuite.h"
|
||||||
|
|
||||||
static NullableTestSuite suite_NullableTestSuite;
|
|
||||||
|
|
||||||
static CxxTest::List Tests_NullableTestSuite = { 0, 0 };
|
|
||||||
CxxTest::StaticSuiteDescription suiteDescription_NullableTestSuite( "../../source/tests/NullableTestSuite.h", 8, "NullableTestSuite", suite_NullableTestSuite, Tests_NullableTestSuite );
|
|
||||||
|
|
||||||
static class TestDescription_suite_NullableTestSuite_test_has_value : public CxxTest::RealTestDescription {
|
|
||||||
public:
|
|
||||||
TestDescription_suite_NullableTestSuite_test_has_value() : CxxTest::RealTestDescription( Tests_NullableTestSuite, suiteDescription_NullableTestSuite, 16, "test_has_value" ) {}
|
|
||||||
void runTest() { suite_NullableTestSuite.test_has_value(); }
|
|
||||||
} testDescription_suite_NullableTestSuite_test_has_value;
|
|
||||||
|
|
||||||
static class TestDescription_suite_NullableTestSuite_test_get_value : public CxxTest::RealTestDescription {
|
|
||||||
public:
|
|
||||||
TestDescription_suite_NullableTestSuite_test_get_value() : CxxTest::RealTestDescription( Tests_NullableTestSuite, suiteDescription_NullableTestSuite, 22, "test_get_value" ) {}
|
|
||||||
void runTest() { suite_NullableTestSuite.test_get_value(); }
|
|
||||||
} testDescription_suite_NullableTestSuite_test_get_value;
|
|
||||||
|
|
||||||
static class TestDescription_suite_NullableTestSuite_test_equality : public CxxTest::RealTestDescription {
|
|
||||||
public:
|
|
||||||
TestDescription_suite_NullableTestSuite_test_equality() : CxxTest::RealTestDescription( Tests_NullableTestSuite, suiteDescription_NullableTestSuite, 29, "test_equality" ) {}
|
|
||||||
void runTest() { suite_NullableTestSuite.test_equality(); }
|
|
||||||
} testDescription_suite_NullableTestSuite_test_equality;
|
|
||||||
|
|
||||||
static class TestDescription_suite_NullableTestSuite_test_assignment : public CxxTest::RealTestDescription {
|
|
||||||
public:
|
|
||||||
TestDescription_suite_NullableTestSuite_test_assignment() : CxxTest::RealTestDescription( Tests_NullableTestSuite, suiteDescription_NullableTestSuite, 36, "test_assignment" ) {}
|
|
||||||
void runTest() { suite_NullableTestSuite.test_assignment(); }
|
|
||||||
} testDescription_suite_NullableTestSuite_test_assignment;
|
|
||||||
|
|
||||||
static class TestDescription_suite_NullableTestSuite_test_copy_constructor : public CxxTest::RealTestDescription {
|
|
||||||
public:
|
|
||||||
TestDescription_suite_NullableTestSuite_test_copy_constructor() : CxxTest::RealTestDescription( Tests_NullableTestSuite, suiteDescription_NullableTestSuite, 44, "test_copy_constructor" ) {}
|
|
||||||
void runTest() { suite_NullableTestSuite.test_copy_constructor(); }
|
|
||||||
} testDescription_suite_NullableTestSuite_test_copy_constructor;
|
|
||||||
|
|
||||||
#include "c:\Users\taf656\Development\xlnt\source\tests\NumberFormatTestSuite.h"
|
|
||||||
|
|
||||||
static NumberFormatTestSuite suite_NumberFormatTestSuite;
|
static NumberFormatTestSuite suite_NumberFormatTestSuite;
|
||||||
|
|
||||||
|
@ -549,7 +512,7 @@ public:
|
||||||
void runTest() { suite_NumberFormatTestSuite.test_mac_date(); }
|
void runTest() { suite_NumberFormatTestSuite.test_mac_date(); }
|
||||||
} testDescription_suite_NumberFormatTestSuite_test_mac_date;
|
} testDescription_suite_NumberFormatTestSuite_test_mac_date;
|
||||||
|
|
||||||
#include "c:\Users\taf656\Development\xlnt\source\tests\PasswordHashTestSuite.h"
|
#include "/Users/thomas/Development/xlnt/source/tests/PasswordHashTestSuite.h"
|
||||||
|
|
||||||
static PasswordHashTestSuite suite_PasswordHashTestSuite;
|
static PasswordHashTestSuite suite_PasswordHashTestSuite;
|
||||||
|
|
||||||
|
@ -568,7 +531,7 @@ public:
|
||||||
void runTest() { suite_PasswordHashTestSuite.test_sheet_protection(); }
|
void runTest() { suite_PasswordHashTestSuite.test_sheet_protection(); }
|
||||||
} testDescription_suite_PasswordHashTestSuite_test_sheet_protection;
|
} testDescription_suite_PasswordHashTestSuite_test_sheet_protection;
|
||||||
|
|
||||||
#include "c:\Users\taf656\Development\xlnt\source\tests\PropsTestSuite.h"
|
#include "/Users/thomas/Development/xlnt/source/tests/PropsTestSuite.h"
|
||||||
|
|
||||||
static PropsTestSuite suite_PropsTestSuite;
|
static PropsTestSuite suite_PropsTestSuite;
|
||||||
|
|
||||||
|
@ -611,7 +574,7 @@ public:
|
||||||
void runTest() { suite_PropsTestSuite.test_write_properties_app(); }
|
void runTest() { suite_PropsTestSuite.test_write_properties_app(); }
|
||||||
} testDescription_suite_PropsTestSuite_test_write_properties_app;
|
} testDescription_suite_PropsTestSuite_test_write_properties_app;
|
||||||
|
|
||||||
#include "c:\Users\taf656\Development\xlnt\source\tests\ReadTestSuite.h"
|
#include "/Users/thomas/Development/xlnt/source/tests/ReadTestSuite.h"
|
||||||
|
|
||||||
static ReadTestSuite suite_ReadTestSuite;
|
static ReadTestSuite suite_ReadTestSuite;
|
||||||
|
|
||||||
|
@ -744,7 +707,7 @@ public:
|
||||||
void runTest() { suite_ReadTestSuite.test_read_date_value(); }
|
void runTest() { suite_ReadTestSuite.test_read_date_value(); }
|
||||||
} testDescription_suite_ReadTestSuite_test_read_date_value;
|
} testDescription_suite_ReadTestSuite_test_read_date_value;
|
||||||
|
|
||||||
#include "c:\Users\taf656\Development\xlnt\source\tests\StringsTestSuite.h"
|
#include "/Users/thomas/Development/xlnt/source/tests/StringsTestSuite.h"
|
||||||
|
|
||||||
static StringsTestSuite suite_StringsTestSuite;
|
static StringsTestSuite suite_StringsTestSuite;
|
||||||
|
|
||||||
|
@ -775,7 +738,7 @@ public:
|
||||||
void runTest() { suite_StringsTestSuite.test_formatted_string_table(); }
|
void runTest() { suite_StringsTestSuite.test_formatted_string_table(); }
|
||||||
} testDescription_suite_StringsTestSuite_test_formatted_string_table;
|
} testDescription_suite_StringsTestSuite_test_formatted_string_table;
|
||||||
|
|
||||||
#include "c:\Users\taf656\Development\xlnt\source\tests\StyleTestSuite.h"
|
#include "/Users/thomas/Development/xlnt/source/tests/StyleTestSuite.h"
|
||||||
|
|
||||||
static StyleTestSuite suite_StyleTestSuite;
|
static StyleTestSuite suite_StyleTestSuite;
|
||||||
|
|
||||||
|
@ -872,7 +835,7 @@ public:
|
||||||
void runTest() { suite_StyleTestSuite.test_read_cell_style(); }
|
void runTest() { suite_StyleTestSuite.test_read_cell_style(); }
|
||||||
} testDescription_suite_StyleTestSuite_test_read_cell_style;
|
} testDescription_suite_StyleTestSuite_test_read_cell_style;
|
||||||
|
|
||||||
#include "c:\Users\taf656\Development\xlnt\source\tests\ThemeTestSuite.h"
|
#include "/Users/thomas/Development/xlnt/source/tests/ThemeTestSuite.h"
|
||||||
|
|
||||||
static ThemeTestSuite suite_ThemeTestSuite;
|
static ThemeTestSuite suite_ThemeTestSuite;
|
||||||
|
|
||||||
|
@ -885,7 +848,7 @@ public:
|
||||||
void runTest() { suite_ThemeTestSuite.test_write_theme(); }
|
void runTest() { suite_ThemeTestSuite.test_write_theme(); }
|
||||||
} testDescription_suite_ThemeTestSuite_test_write_theme;
|
} testDescription_suite_ThemeTestSuite_test_write_theme;
|
||||||
|
|
||||||
#include "c:\Users\taf656\Development\xlnt\source\tests\WorkbookTestSuite.h"
|
#include "/Users/thomas/Development/xlnt/source/tests/WorkbookTestSuite.h"
|
||||||
|
|
||||||
static WorkbookTestSuite suite_WorkbookTestSuite;
|
static WorkbookTestSuite suite_WorkbookTestSuite;
|
||||||
|
|
||||||
|
@ -996,35 +959,35 @@ public:
|
||||||
|
|
||||||
static class TestDescription_suite_WorkbookTestSuite_test_get_named_range2 : public CxxTest::RealTestDescription {
|
static class TestDescription_suite_WorkbookTestSuite_test_get_named_range2 : public CxxTest::RealTestDescription {
|
||||||
public:
|
public:
|
||||||
TestDescription_suite_WorkbookTestSuite_test_get_named_range2() : CxxTest::RealTestDescription( Tests_WorkbookTestSuite, suiteDescription_WorkbookTestSuite, 168, "test_get_named_range2" ) {}
|
TestDescription_suite_WorkbookTestSuite_test_get_named_range2() : CxxTest::RealTestDescription( Tests_WorkbookTestSuite, suiteDescription_WorkbookTestSuite, 167, "test_get_named_range2" ) {}
|
||||||
void runTest() { suite_WorkbookTestSuite.test_get_named_range2(); }
|
void runTest() { suite_WorkbookTestSuite.test_get_named_range2(); }
|
||||||
} testDescription_suite_WorkbookTestSuite_test_get_named_range2;
|
} testDescription_suite_WorkbookTestSuite_test_get_named_range2;
|
||||||
|
|
||||||
static class TestDescription_suite_WorkbookTestSuite_test_remove_named_range : public CxxTest::RealTestDescription {
|
static class TestDescription_suite_WorkbookTestSuite_test_remove_named_range : public CxxTest::RealTestDescription {
|
||||||
public:
|
public:
|
||||||
TestDescription_suite_WorkbookTestSuite_test_remove_named_range() : CxxTest::RealTestDescription( Tests_WorkbookTestSuite, suiteDescription_WorkbookTestSuite, 178, "test_remove_named_range" ) {}
|
TestDescription_suite_WorkbookTestSuite_test_remove_named_range() : CxxTest::RealTestDescription( Tests_WorkbookTestSuite, suiteDescription_WorkbookTestSuite, 176, "test_remove_named_range" ) {}
|
||||||
void runTest() { suite_WorkbookTestSuite.test_remove_named_range(); }
|
void runTest() { suite_WorkbookTestSuite.test_remove_named_range(); }
|
||||||
} testDescription_suite_WorkbookTestSuite_test_remove_named_range;
|
} testDescription_suite_WorkbookTestSuite_test_remove_named_range;
|
||||||
|
|
||||||
static class TestDescription_suite_WorkbookTestSuite_test_add_local_named_range : public CxxTest::RealTestDescription {
|
static class TestDescription_suite_WorkbookTestSuite_test_add_local_named_range : public CxxTest::RealTestDescription {
|
||||||
public:
|
public:
|
||||||
TestDescription_suite_WorkbookTestSuite_test_add_local_named_range() : CxxTest::RealTestDescription( Tests_WorkbookTestSuite, suiteDescription_WorkbookTestSuite, 189, "test_add_local_named_range" ) {}
|
TestDescription_suite_WorkbookTestSuite_test_add_local_named_range() : CxxTest::RealTestDescription( Tests_WorkbookTestSuite, suiteDescription_WorkbookTestSuite, 186, "test_add_local_named_range" ) {}
|
||||||
void runTest() { suite_WorkbookTestSuite.test_add_local_named_range(); }
|
void runTest() { suite_WorkbookTestSuite.test_add_local_named_range(); }
|
||||||
} testDescription_suite_WorkbookTestSuite_test_add_local_named_range;
|
} testDescription_suite_WorkbookTestSuite_test_add_local_named_range;
|
||||||
|
|
||||||
static class TestDescription_suite_WorkbookTestSuite_test_write_regular_date : public CxxTest::RealTestDescription {
|
static class TestDescription_suite_WorkbookTestSuite_test_write_regular_date : public CxxTest::RealTestDescription {
|
||||||
public:
|
public:
|
||||||
TestDescription_suite_WorkbookTestSuite_test_write_regular_date() : CxxTest::RealTestDescription( Tests_WorkbookTestSuite, suiteDescription_WorkbookTestSuite, 211, "test_write_regular_date" ) {}
|
TestDescription_suite_WorkbookTestSuite_test_write_regular_date() : CxxTest::RealTestDescription( Tests_WorkbookTestSuite, suiteDescription_WorkbookTestSuite, 206, "test_write_regular_date" ) {}
|
||||||
void runTest() { suite_WorkbookTestSuite.test_write_regular_date(); }
|
void runTest() { suite_WorkbookTestSuite.test_write_regular_date(); }
|
||||||
} testDescription_suite_WorkbookTestSuite_test_write_regular_date;
|
} testDescription_suite_WorkbookTestSuite_test_write_regular_date;
|
||||||
|
|
||||||
static class TestDescription_suite_WorkbookTestSuite_test_write_regular_float : public CxxTest::RealTestDescription {
|
static class TestDescription_suite_WorkbookTestSuite_test_write_regular_float : public CxxTest::RealTestDescription {
|
||||||
public:
|
public:
|
||||||
TestDescription_suite_WorkbookTestSuite_test_write_regular_float() : CxxTest::RealTestDescription( Tests_WorkbookTestSuite, suiteDescription_WorkbookTestSuite, 229, "test_write_regular_float" ) {}
|
TestDescription_suite_WorkbookTestSuite_test_write_regular_float() : CxxTest::RealTestDescription( Tests_WorkbookTestSuite, suiteDescription_WorkbookTestSuite, 224, "test_write_regular_float" ) {}
|
||||||
void runTest() { suite_WorkbookTestSuite.test_write_regular_float(); }
|
void runTest() { suite_WorkbookTestSuite.test_write_regular_float(); }
|
||||||
} testDescription_suite_WorkbookTestSuite_test_write_regular_float;
|
} testDescription_suite_WorkbookTestSuite_test_write_regular_float;
|
||||||
|
|
||||||
#include "c:\Users\taf656\Development\xlnt\source\tests\WorksheetTestSuite.h"
|
#include "/Users/thomas/Development/xlnt/source/tests/WorksheetTestSuite.h"
|
||||||
|
|
||||||
static WorksheetTestSuite suite_WorksheetTestSuite;
|
static WorksheetTestSuite suite_WorksheetTestSuite;
|
||||||
|
|
||||||
|
@ -1199,140 +1162,140 @@ public:
|
||||||
void runTest() { suite_WorksheetTestSuite.test_printer_settings(); }
|
void runTest() { suite_WorksheetTestSuite.test_printer_settings(); }
|
||||||
} testDescription_suite_WorksheetTestSuite_test_printer_settings;
|
} testDescription_suite_WorksheetTestSuite_test_printer_settings;
|
||||||
|
|
||||||
#include "c:\Users\taf656\Development\xlnt\source\tests\WriteTestSuite.h"
|
#include "/Users/thomas/Development/xlnt/source/tests/WriteTestSuite.h"
|
||||||
|
|
||||||
static WriteTestSuite suite_WriteTestSuite;
|
static WriteTestSuite suite_WriteTestSuite;
|
||||||
|
|
||||||
static CxxTest::List Tests_WriteTestSuite = { 0, 0 };
|
static CxxTest::List Tests_WriteTestSuite = { 0, 0 };
|
||||||
CxxTest::StaticSuiteDescription suiteDescription_WriteTestSuite( "../../source/tests/WriteTestSuite.h", 9, "WriteTestSuite", suite_WriteTestSuite, Tests_WriteTestSuite );
|
CxxTest::StaticSuiteDescription suiteDescription_WriteTestSuite( "../../source/tests/WriteTestSuite.h", 10, "WriteTestSuite", suite_WriteTestSuite, Tests_WriteTestSuite );
|
||||||
|
|
||||||
static class TestDescription_suite_WriteTestSuite_test_write_empty_workbook : public CxxTest::RealTestDescription {
|
static class TestDescription_suite_WriteTestSuite_test_write_empty_workbook : public CxxTest::RealTestDescription {
|
||||||
public:
|
public:
|
||||||
TestDescription_suite_WriteTestSuite_test_write_empty_workbook() : CxxTest::RealTestDescription( Tests_WriteTestSuite, suiteDescription_WriteTestSuite, 17, "test_write_empty_workbook" ) {}
|
TestDescription_suite_WriteTestSuite_test_write_empty_workbook() : CxxTest::RealTestDescription( Tests_WriteTestSuite, suiteDescription_WriteTestSuite, 18, "test_write_empty_workbook" ) {}
|
||||||
void runTest() { suite_WriteTestSuite.test_write_empty_workbook(); }
|
void runTest() { suite_WriteTestSuite.test_write_empty_workbook(); }
|
||||||
} testDescription_suite_WriteTestSuite_test_write_empty_workbook;
|
} testDescription_suite_WriteTestSuite_test_write_empty_workbook;
|
||||||
|
|
||||||
static class TestDescription_suite_WriteTestSuite_test_write_virtual_workbook : public CxxTest::RealTestDescription {
|
static class TestDescription_suite_WriteTestSuite_test_write_virtual_workbook : public CxxTest::RealTestDescription {
|
||||||
public:
|
public:
|
||||||
TestDescription_suite_WriteTestSuite_test_write_virtual_workbook() : CxxTest::RealTestDescription( Tests_WriteTestSuite, suiteDescription_WriteTestSuite, 26, "test_write_virtual_workbook" ) {}
|
TestDescription_suite_WriteTestSuite_test_write_virtual_workbook() : CxxTest::RealTestDescription( Tests_WriteTestSuite, suiteDescription_WriteTestSuite, 27, "test_write_virtual_workbook" ) {}
|
||||||
void runTest() { suite_WriteTestSuite.test_write_virtual_workbook(); }
|
void runTest() { suite_WriteTestSuite.test_write_virtual_workbook(); }
|
||||||
} testDescription_suite_WriteTestSuite_test_write_virtual_workbook;
|
} testDescription_suite_WriteTestSuite_test_write_virtual_workbook;
|
||||||
|
|
||||||
static class TestDescription_suite_WriteTestSuite_test_write_workbook_rels : public CxxTest::RealTestDescription {
|
static class TestDescription_suite_WriteTestSuite_test_write_workbook_rels : public CxxTest::RealTestDescription {
|
||||||
public:
|
public:
|
||||||
TestDescription_suite_WriteTestSuite_test_write_workbook_rels() : CxxTest::RealTestDescription( Tests_WriteTestSuite, suiteDescription_WriteTestSuite, 34, "test_write_workbook_rels" ) {}
|
TestDescription_suite_WriteTestSuite_test_write_workbook_rels() : CxxTest::RealTestDescription( Tests_WriteTestSuite, suiteDescription_WriteTestSuite, 35, "test_write_workbook_rels" ) {}
|
||||||
void runTest() { suite_WriteTestSuite.test_write_workbook_rels(); }
|
void runTest() { suite_WriteTestSuite.test_write_workbook_rels(); }
|
||||||
} testDescription_suite_WriteTestSuite_test_write_workbook_rels;
|
} testDescription_suite_WriteTestSuite_test_write_workbook_rels;
|
||||||
|
|
||||||
static class TestDescription_suite_WriteTestSuite_test_write_workbook : public CxxTest::RealTestDescription {
|
static class TestDescription_suite_WriteTestSuite_test_write_workbook : public CxxTest::RealTestDescription {
|
||||||
public:
|
public:
|
||||||
TestDescription_suite_WriteTestSuite_test_write_workbook() : CxxTest::RealTestDescription( Tests_WriteTestSuite, suiteDescription_WriteTestSuite, 42, "test_write_workbook" ) {}
|
TestDescription_suite_WriteTestSuite_test_write_workbook() : CxxTest::RealTestDescription( Tests_WriteTestSuite, suiteDescription_WriteTestSuite, 43, "test_write_workbook" ) {}
|
||||||
void runTest() { suite_WriteTestSuite.test_write_workbook(); }
|
void runTest() { suite_WriteTestSuite.test_write_workbook(); }
|
||||||
} testDescription_suite_WriteTestSuite_test_write_workbook;
|
} testDescription_suite_WriteTestSuite_test_write_workbook;
|
||||||
|
|
||||||
static class TestDescription_suite_WriteTestSuite_test_write_string_table : public CxxTest::RealTestDescription {
|
static class TestDescription_suite_WriteTestSuite_test_write_string_table : public CxxTest::RealTestDescription {
|
||||||
public:
|
public:
|
||||||
TestDescription_suite_WriteTestSuite_test_write_string_table() : CxxTest::RealTestDescription( Tests_WriteTestSuite, suiteDescription_WriteTestSuite, 51, "test_write_string_table" ) {}
|
TestDescription_suite_WriteTestSuite_test_write_string_table() : CxxTest::RealTestDescription( Tests_WriteTestSuite, suiteDescription_WriteTestSuite, 52, "test_write_string_table" ) {}
|
||||||
void runTest() { suite_WriteTestSuite.test_write_string_table(); }
|
void runTest() { suite_WriteTestSuite.test_write_string_table(); }
|
||||||
} testDescription_suite_WriteTestSuite_test_write_string_table;
|
} testDescription_suite_WriteTestSuite_test_write_string_table;
|
||||||
|
|
||||||
static class TestDescription_suite_WriteTestSuite_test_write_worksheet : public CxxTest::RealTestDescription {
|
static class TestDescription_suite_WriteTestSuite_test_write_worksheet : public CxxTest::RealTestDescription {
|
||||||
public:
|
public:
|
||||||
TestDescription_suite_WriteTestSuite_test_write_worksheet() : CxxTest::RealTestDescription( Tests_WriteTestSuite, suiteDescription_WriteTestSuite, 59, "test_write_worksheet" ) {}
|
TestDescription_suite_WriteTestSuite_test_write_worksheet() : CxxTest::RealTestDescription( Tests_WriteTestSuite, suiteDescription_WriteTestSuite, 60, "test_write_worksheet" ) {}
|
||||||
void runTest() { suite_WriteTestSuite.test_write_worksheet(); }
|
void runTest() { suite_WriteTestSuite.test_write_worksheet(); }
|
||||||
} testDescription_suite_WriteTestSuite_test_write_worksheet;
|
} testDescription_suite_WriteTestSuite_test_write_worksheet;
|
||||||
|
|
||||||
static class TestDescription_suite_WriteTestSuite_test_write_hidden_worksheet : public CxxTest::RealTestDescription {
|
static class TestDescription_suite_WriteTestSuite_test_write_hidden_worksheet : public CxxTest::RealTestDescription {
|
||||||
public:
|
public:
|
||||||
TestDescription_suite_WriteTestSuite_test_write_hidden_worksheet() : CxxTest::RealTestDescription( Tests_WriteTestSuite, suiteDescription_WriteTestSuite, 69, "test_write_hidden_worksheet" ) {}
|
TestDescription_suite_WriteTestSuite_test_write_hidden_worksheet() : CxxTest::RealTestDescription( Tests_WriteTestSuite, suiteDescription_WriteTestSuite, 70, "test_write_hidden_worksheet" ) {}
|
||||||
void runTest() { suite_WriteTestSuite.test_write_hidden_worksheet(); }
|
void runTest() { suite_WriteTestSuite.test_write_hidden_worksheet(); }
|
||||||
} testDescription_suite_WriteTestSuite_test_write_hidden_worksheet;
|
} testDescription_suite_WriteTestSuite_test_write_hidden_worksheet;
|
||||||
|
|
||||||
static class TestDescription_suite_WriteTestSuite_test_write_bool : public CxxTest::RealTestDescription {
|
static class TestDescription_suite_WriteTestSuite_test_write_bool : public CxxTest::RealTestDescription {
|
||||||
public:
|
public:
|
||||||
TestDescription_suite_WriteTestSuite_test_write_bool() : CxxTest::RealTestDescription( Tests_WriteTestSuite, suiteDescription_WriteTestSuite, 80, "test_write_bool" ) {}
|
TestDescription_suite_WriteTestSuite_test_write_bool() : CxxTest::RealTestDescription( Tests_WriteTestSuite, suiteDescription_WriteTestSuite, 81, "test_write_bool" ) {}
|
||||||
void runTest() { suite_WriteTestSuite.test_write_bool(); }
|
void runTest() { suite_WriteTestSuite.test_write_bool(); }
|
||||||
} testDescription_suite_WriteTestSuite_test_write_bool;
|
} testDescription_suite_WriteTestSuite_test_write_bool;
|
||||||
|
|
||||||
static class TestDescription_suite_WriteTestSuite_test_write_formula : public CxxTest::RealTestDescription {
|
static class TestDescription_suite_WriteTestSuite_test_write_formula : public CxxTest::RealTestDescription {
|
||||||
public:
|
public:
|
||||||
TestDescription_suite_WriteTestSuite_test_write_formula() : CxxTest::RealTestDescription( Tests_WriteTestSuite, suiteDescription_WriteTestSuite, 91, "test_write_formula" ) {}
|
TestDescription_suite_WriteTestSuite_test_write_formula() : CxxTest::RealTestDescription( Tests_WriteTestSuite, suiteDescription_WriteTestSuite, 92, "test_write_formula" ) {}
|
||||||
void runTest() { suite_WriteTestSuite.test_write_formula(); }
|
void runTest() { suite_WriteTestSuite.test_write_formula(); }
|
||||||
} testDescription_suite_WriteTestSuite_test_write_formula;
|
} testDescription_suite_WriteTestSuite_test_write_formula;
|
||||||
|
|
||||||
static class TestDescription_suite_WriteTestSuite_test_write_style : public CxxTest::RealTestDescription {
|
static class TestDescription_suite_WriteTestSuite_test_write_style : public CxxTest::RealTestDescription {
|
||||||
public:
|
public:
|
||||||
TestDescription_suite_WriteTestSuite_test_write_style() : CxxTest::RealTestDescription( Tests_WriteTestSuite, suiteDescription_WriteTestSuite, 103, "test_write_style" ) {}
|
TestDescription_suite_WriteTestSuite_test_write_style() : CxxTest::RealTestDescription( Tests_WriteTestSuite, suiteDescription_WriteTestSuite, 104, "test_write_style" ) {}
|
||||||
void runTest() { suite_WriteTestSuite.test_write_style(); }
|
void runTest() { suite_WriteTestSuite.test_write_style(); }
|
||||||
} testDescription_suite_WriteTestSuite_test_write_style;
|
} testDescription_suite_WriteTestSuite_test_write_style;
|
||||||
|
|
||||||
static class TestDescription_suite_WriteTestSuite_test_write_height : public CxxTest::RealTestDescription {
|
static class TestDescription_suite_WriteTestSuite_test_write_height : public CxxTest::RealTestDescription {
|
||||||
public:
|
public:
|
||||||
TestDescription_suite_WriteTestSuite_test_write_height() : CxxTest::RealTestDescription( Tests_WriteTestSuite, suiteDescription_WriteTestSuite, 114, "test_write_height" ) {}
|
TestDescription_suite_WriteTestSuite_test_write_height() : CxxTest::RealTestDescription( Tests_WriteTestSuite, suiteDescription_WriteTestSuite, 115, "test_write_height" ) {}
|
||||||
void runTest() { suite_WriteTestSuite.test_write_height(); }
|
void runTest() { suite_WriteTestSuite.test_write_height(); }
|
||||||
} testDescription_suite_WriteTestSuite_test_write_height;
|
} testDescription_suite_WriteTestSuite_test_write_height;
|
||||||
|
|
||||||
static class TestDescription_suite_WriteTestSuite_test_write_hyperlink : public CxxTest::RealTestDescription {
|
static class TestDescription_suite_WriteTestSuite_test_write_hyperlink : public CxxTest::RealTestDescription {
|
||||||
public:
|
public:
|
||||||
TestDescription_suite_WriteTestSuite_test_write_hyperlink() : CxxTest::RealTestDescription( Tests_WriteTestSuite, suiteDescription_WriteTestSuite, 125, "test_write_hyperlink" ) {}
|
TestDescription_suite_WriteTestSuite_test_write_hyperlink() : CxxTest::RealTestDescription( Tests_WriteTestSuite, suiteDescription_WriteTestSuite, 126, "test_write_hyperlink" ) {}
|
||||||
void runTest() { suite_WriteTestSuite.test_write_hyperlink(); }
|
void runTest() { suite_WriteTestSuite.test_write_hyperlink(); }
|
||||||
} testDescription_suite_WriteTestSuite_test_write_hyperlink;
|
} testDescription_suite_WriteTestSuite_test_write_hyperlink;
|
||||||
|
|
||||||
static class TestDescription_suite_WriteTestSuite_test_write_hyperlink_rels : public CxxTest::RealTestDescription {
|
static class TestDescription_suite_WriteTestSuite_test_write_hyperlink_rels : public CxxTest::RealTestDescription {
|
||||||
public:
|
public:
|
||||||
TestDescription_suite_WriteTestSuite_test_write_hyperlink_rels() : CxxTest::RealTestDescription( Tests_WriteTestSuite, suiteDescription_WriteTestSuite, 136, "test_write_hyperlink_rels" ) {}
|
TestDescription_suite_WriteTestSuite_test_write_hyperlink_rels() : CxxTest::RealTestDescription( Tests_WriteTestSuite, suiteDescription_WriteTestSuite, 137, "test_write_hyperlink_rels" ) {}
|
||||||
void runTest() { suite_WriteTestSuite.test_write_hyperlink_rels(); }
|
void runTest() { suite_WriteTestSuite.test_write_hyperlink_rels(); }
|
||||||
} testDescription_suite_WriteTestSuite_test_write_hyperlink_rels;
|
} testDescription_suite_WriteTestSuite_test_write_hyperlink_rels;
|
||||||
|
|
||||||
static class TestDescription_suite_WriteTestSuite_test_hyperlink_value : public CxxTest::RealTestDescription {
|
static class TestDescription_suite_WriteTestSuite_test_hyperlink_value : public CxxTest::RealTestDescription {
|
||||||
public:
|
public:
|
||||||
TestDescription_suite_WriteTestSuite_test_hyperlink_value() : CxxTest::RealTestDescription( Tests_WriteTestSuite, suiteDescription_WriteTestSuite, 152, "test_hyperlink_value" ) {}
|
TestDescription_suite_WriteTestSuite_test_hyperlink_value() : CxxTest::RealTestDescription( Tests_WriteTestSuite, suiteDescription_WriteTestSuite, 153, "test_hyperlink_value" ) {}
|
||||||
void runTest() { suite_WriteTestSuite.test_hyperlink_value(); }
|
void runTest() { suite_WriteTestSuite.test_hyperlink_value(); }
|
||||||
} testDescription_suite_WriteTestSuite_test_hyperlink_value;
|
} testDescription_suite_WriteTestSuite_test_hyperlink_value;
|
||||||
|
|
||||||
static class TestDescription_suite_WriteTestSuite_test_write_auto_filter : public CxxTest::RealTestDescription {
|
static class TestDescription_suite_WriteTestSuite_test_write_auto_filter : public CxxTest::RealTestDescription {
|
||||||
public:
|
public:
|
||||||
TestDescription_suite_WriteTestSuite_test_write_auto_filter() : CxxTest::RealTestDescription( Tests_WriteTestSuite, suiteDescription_WriteTestSuite, 162, "test_write_auto_filter" ) {}
|
TestDescription_suite_WriteTestSuite_test_write_auto_filter() : CxxTest::RealTestDescription( Tests_WriteTestSuite, suiteDescription_WriteTestSuite, 163, "test_write_auto_filter" ) {}
|
||||||
void runTest() { suite_WriteTestSuite.test_write_auto_filter(); }
|
void runTest() { suite_WriteTestSuite.test_write_auto_filter(); }
|
||||||
} testDescription_suite_WriteTestSuite_test_write_auto_filter;
|
} testDescription_suite_WriteTestSuite_test_write_auto_filter;
|
||||||
|
|
||||||
static class TestDescription_suite_WriteTestSuite_test_freeze_panes_horiz : public CxxTest::RealTestDescription {
|
static class TestDescription_suite_WriteTestSuite_test_freeze_panes_horiz : public CxxTest::RealTestDescription {
|
||||||
public:
|
public:
|
||||||
TestDescription_suite_WriteTestSuite_test_freeze_panes_horiz() : CxxTest::RealTestDescription( Tests_WriteTestSuite, suiteDescription_WriteTestSuite, 177, "test_freeze_panes_horiz" ) {}
|
TestDescription_suite_WriteTestSuite_test_freeze_panes_horiz() : CxxTest::RealTestDescription( Tests_WriteTestSuite, suiteDescription_WriteTestSuite, 178, "test_freeze_panes_horiz" ) {}
|
||||||
void runTest() { suite_WriteTestSuite.test_freeze_panes_horiz(); }
|
void runTest() { suite_WriteTestSuite.test_freeze_panes_horiz(); }
|
||||||
} testDescription_suite_WriteTestSuite_test_freeze_panes_horiz;
|
} testDescription_suite_WriteTestSuite_test_freeze_panes_horiz;
|
||||||
|
|
||||||
static class TestDescription_suite_WriteTestSuite_test_freeze_panes_vert : public CxxTest::RealTestDescription {
|
static class TestDescription_suite_WriteTestSuite_test_freeze_panes_vert : public CxxTest::RealTestDescription {
|
||||||
public:
|
public:
|
||||||
TestDescription_suite_WriteTestSuite_test_freeze_panes_vert() : CxxTest::RealTestDescription( Tests_WriteTestSuite, suiteDescription_WriteTestSuite, 188, "test_freeze_panes_vert" ) {}
|
TestDescription_suite_WriteTestSuite_test_freeze_panes_vert() : CxxTest::RealTestDescription( Tests_WriteTestSuite, suiteDescription_WriteTestSuite, 189, "test_freeze_panes_vert" ) {}
|
||||||
void runTest() { suite_WriteTestSuite.test_freeze_panes_vert(); }
|
void runTest() { suite_WriteTestSuite.test_freeze_panes_vert(); }
|
||||||
} testDescription_suite_WriteTestSuite_test_freeze_panes_vert;
|
} testDescription_suite_WriteTestSuite_test_freeze_panes_vert;
|
||||||
|
|
||||||
static class TestDescription_suite_WriteTestSuite_test_freeze_panes_both : public CxxTest::RealTestDescription {
|
static class TestDescription_suite_WriteTestSuite_test_freeze_panes_both : public CxxTest::RealTestDescription {
|
||||||
public:
|
public:
|
||||||
TestDescription_suite_WriteTestSuite_test_freeze_panes_both() : CxxTest::RealTestDescription( Tests_WriteTestSuite, suiteDescription_WriteTestSuite, 199, "test_freeze_panes_both" ) {}
|
TestDescription_suite_WriteTestSuite_test_freeze_panes_both() : CxxTest::RealTestDescription( Tests_WriteTestSuite, suiteDescription_WriteTestSuite, 200, "test_freeze_panes_both" ) {}
|
||||||
void runTest() { suite_WriteTestSuite.test_freeze_panes_both(); }
|
void runTest() { suite_WriteTestSuite.test_freeze_panes_both(); }
|
||||||
} testDescription_suite_WriteTestSuite_test_freeze_panes_both;
|
} testDescription_suite_WriteTestSuite_test_freeze_panes_both;
|
||||||
|
|
||||||
static class TestDescription_suite_WriteTestSuite_test_long_number : public CxxTest::RealTestDescription {
|
static class TestDescription_suite_WriteTestSuite_test_long_number : public CxxTest::RealTestDescription {
|
||||||
public:
|
public:
|
||||||
TestDescription_suite_WriteTestSuite_test_long_number() : CxxTest::RealTestDescription( Tests_WriteTestSuite, suiteDescription_WriteTestSuite, 210, "test_long_number" ) {}
|
TestDescription_suite_WriteTestSuite_test_long_number() : CxxTest::RealTestDescription( Tests_WriteTestSuite, suiteDescription_WriteTestSuite, 211, "test_long_number" ) {}
|
||||||
void runTest() { suite_WriteTestSuite.test_long_number(); }
|
void runTest() { suite_WriteTestSuite.test_long_number(); }
|
||||||
} testDescription_suite_WriteTestSuite_test_long_number;
|
} testDescription_suite_WriteTestSuite_test_long_number;
|
||||||
|
|
||||||
static class TestDescription_suite_WriteTestSuite_test_decimal : public CxxTest::RealTestDescription {
|
static class TestDescription_suite_WriteTestSuite_test_decimal : public CxxTest::RealTestDescription {
|
||||||
public:
|
public:
|
||||||
TestDescription_suite_WriteTestSuite_test_decimal() : CxxTest::RealTestDescription( Tests_WriteTestSuite, suiteDescription_WriteTestSuite, 220, "test_decimal" ) {}
|
TestDescription_suite_WriteTestSuite_test_decimal() : CxxTest::RealTestDescription( Tests_WriteTestSuite, suiteDescription_WriteTestSuite, 221, "test_decimal" ) {}
|
||||||
void runTest() { suite_WriteTestSuite.test_decimal(); }
|
void runTest() { suite_WriteTestSuite.test_decimal(); }
|
||||||
} testDescription_suite_WriteTestSuite_test_decimal;
|
} testDescription_suite_WriteTestSuite_test_decimal;
|
||||||
|
|
||||||
static class TestDescription_suite_WriteTestSuite_test_short_number : public CxxTest::RealTestDescription {
|
static class TestDescription_suite_WriteTestSuite_test_short_number : public CxxTest::RealTestDescription {
|
||||||
public:
|
public:
|
||||||
TestDescription_suite_WriteTestSuite_test_short_number() : CxxTest::RealTestDescription( Tests_WriteTestSuite, suiteDescription_WriteTestSuite, 230, "test_short_number" ) {}
|
TestDescription_suite_WriteTestSuite_test_short_number() : CxxTest::RealTestDescription( Tests_WriteTestSuite, suiteDescription_WriteTestSuite, 231, "test_short_number" ) {}
|
||||||
void runTest() { suite_WriteTestSuite.test_short_number(); }
|
void runTest() { suite_WriteTestSuite.test_short_number(); }
|
||||||
} testDescription_suite_WriteTestSuite_test_short_number;
|
} testDescription_suite_WriteTestSuite_test_short_number;
|
||||||
|
|
||||||
#include "c:\Users\taf656\Development\xlnt\source\tests\ZipFileTestSuite.h"
|
#include "/Users/thomas/Development/xlnt/source/tests/ZipFileTestSuite.h"
|
||||||
|
|
||||||
static ZipFileTestSuite suite_ZipFileTestSuite;
|
static ZipFileTestSuite suite_ZipFileTestSuite;
|
||||||
|
|
||||||
|
|
BIN
source/tests/test_data/genuine/empty-with-styles.zip
Normal file
BIN
source/tests/test_data/genuine/empty-with-styles.zip
Normal file
Binary file not shown.
BIN
source/tests/test_data/writer/new.xlsx
Normal file
BIN
source/tests/test_data/writer/new.xlsx
Normal file
Binary file not shown.
465
source/workbook.cpp
Normal file
465
source/workbook.cpp
Normal file
|
@ -0,0 +1,465 @@
|
||||||
|
#include <sstream>
|
||||||
|
#include <pugixml.hpp>
|
||||||
|
|
||||||
|
#include "workbook.h"
|
||||||
|
#include "custom_exceptions.h"
|
||||||
|
#include "drawing.h"
|
||||||
|
#include "named_range.h"
|
||||||
|
#include "reader.h"
|
||||||
|
#include "relationship.h"
|
||||||
|
#include "worksheet.h"
|
||||||
|
#include "writer.h"
|
||||||
|
#include "zip_file.h"
|
||||||
|
|
||||||
|
namespace xlnt {
|
||||||
|
|
||||||
|
workbook::workbook(optimization optimization)
|
||||||
|
: optimized_write_(optimization==optimization::write),
|
||||||
|
optimized_read_(optimization==optimization::read),
|
||||||
|
active_sheet_index_(0)
|
||||||
|
{
|
||||||
|
if(!optimized_write_)
|
||||||
|
{
|
||||||
|
create_sheet("Sheet1");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
workbook::~workbook()
|
||||||
|
{
|
||||||
|
clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
worksheet workbook::get_sheet_by_name(const std::string &name)
|
||||||
|
{
|
||||||
|
auto match = std::find_if(worksheets_.begin(), worksheets_.end(), [&](const worksheet &w) { return w.get_title() == name; });
|
||||||
|
if(match != worksheets_.end())
|
||||||
|
{
|
||||||
|
return worksheet(*match);
|
||||||
|
}
|
||||||
|
return worksheet(nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
worksheet workbook::get_active_sheet()
|
||||||
|
{
|
||||||
|
return worksheets_[active_sheet_index_];
|
||||||
|
}
|
||||||
|
|
||||||
|
bool workbook::has_named_range(const std::string &name, xlnt::worksheet ws) const
|
||||||
|
{
|
||||||
|
for(auto named_range : named_ranges_)
|
||||||
|
{
|
||||||
|
if(named_range.first == name && named_range.second.get_scope() == ws)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
worksheet workbook::create_sheet()
|
||||||
|
{
|
||||||
|
if(optimized_read_)
|
||||||
|
{
|
||||||
|
throw std::runtime_error("this is a read-only workbook");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string title = "Sheet1";
|
||||||
|
int index = 1;
|
||||||
|
while(get_sheet_by_name(title) != nullptr)
|
||||||
|
{
|
||||||
|
title = "Sheet" + std::to_string(++index);
|
||||||
|
}
|
||||||
|
|
||||||
|
worksheet ws = worksheet(worksheet::allocate(*this, title));
|
||||||
|
worksheets_.push_back(ws);
|
||||||
|
|
||||||
|
return get_sheet_by_name(title);
|
||||||
|
}
|
||||||
|
|
||||||
|
void workbook::add_sheet(xlnt::worksheet worksheet)
|
||||||
|
{
|
||||||
|
if(optimized_read_)
|
||||||
|
{
|
||||||
|
throw std::runtime_error("this is a read-only workbook");
|
||||||
|
}
|
||||||
|
|
||||||
|
for(auto ws : *this)
|
||||||
|
{
|
||||||
|
if(worksheet == ws)
|
||||||
|
{
|
||||||
|
throw std::runtime_error("worksheet already in workbook");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
worksheets_.push_back(worksheet);
|
||||||
|
}
|
||||||
|
|
||||||
|
void workbook::add_sheet(xlnt::worksheet worksheet, std::size_t index)
|
||||||
|
{
|
||||||
|
if(optimized_read_)
|
||||||
|
{
|
||||||
|
throw std::runtime_error("this is a read-only workbook");
|
||||||
|
}
|
||||||
|
|
||||||
|
for(auto ws : *this)
|
||||||
|
{
|
||||||
|
if(worksheet == ws)
|
||||||
|
{
|
||||||
|
throw std::runtime_error("worksheet already in workbook");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
worksheets_.push_back(worksheet);
|
||||||
|
std::swap(worksheets_[index], worksheets_.back());
|
||||||
|
}
|
||||||
|
|
||||||
|
int workbook::get_index(xlnt::worksheet worksheet)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
for(auto ws : *this)
|
||||||
|
{
|
||||||
|
if(worksheet == ws)
|
||||||
|
{
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
throw std::runtime_error("worksheet isn't owned by this workbook");
|
||||||
|
}
|
||||||
|
|
||||||
|
named_range workbook::create_named_range(const std::string &name, worksheet range_owner, const range_reference &reference)
|
||||||
|
{
|
||||||
|
for(auto ws : worksheets_)
|
||||||
|
{
|
||||||
|
if(ws == range_owner)
|
||||||
|
{
|
||||||
|
named_ranges_[name] = range_owner.create_named_range(name, reference);
|
||||||
|
return named_ranges_[name];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw std::runtime_error("worksheet isn't owned by this workbook");
|
||||||
|
}
|
||||||
|
|
||||||
|
void workbook::add_named_range(const std::string &name, named_range named_range)
|
||||||
|
{
|
||||||
|
for(auto ws : worksheets_)
|
||||||
|
{
|
||||||
|
if(ws == named_range.get_scope())
|
||||||
|
{
|
||||||
|
named_ranges_[name] = named_range;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw std::runtime_error("worksheet isn't owned by this workbook");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<named_range> workbook::get_named_ranges()
|
||||||
|
{
|
||||||
|
std::vector<named_range> named_ranges;
|
||||||
|
for(auto named_range : named_ranges_)
|
||||||
|
{
|
||||||
|
named_ranges.push_back(named_range.second);
|
||||||
|
}
|
||||||
|
return named_ranges;
|
||||||
|
}
|
||||||
|
|
||||||
|
void workbook::remove_named_range(named_range named_range)
|
||||||
|
{
|
||||||
|
std::string key_match = "";
|
||||||
|
for(auto r : named_ranges_)
|
||||||
|
{
|
||||||
|
if(r.second == named_range)
|
||||||
|
{
|
||||||
|
key_match = r.first;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(key_match == "")
|
||||||
|
{
|
||||||
|
throw std::runtime_error("range not found in worksheet");
|
||||||
|
}
|
||||||
|
named_ranges_.erase(key_match);
|
||||||
|
}
|
||||||
|
|
||||||
|
named_range workbook::get_named_range(const std::string &name, worksheet ws)
|
||||||
|
{
|
||||||
|
for(auto named_range : named_ranges_)
|
||||||
|
{
|
||||||
|
if(named_range.first == name && named_range.second.get_scope() == ws)
|
||||||
|
{
|
||||||
|
return named_range.second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw std::runtime_error("doesn't exist");
|
||||||
|
}
|
||||||
|
|
||||||
|
void workbook::load(const std::string &filename)
|
||||||
|
{
|
||||||
|
zip_file f(filename, file_mode::open);
|
||||||
|
//auto core_properties = read_core_properties();
|
||||||
|
//auto app_properties = read_app_properties();
|
||||||
|
auto root_relationships = reader::read_relationships(f.get_file_contents("_rels/.rels"));
|
||||||
|
auto content_types = reader::read_content_types(f.get_file_contents("[Content_Types].xml"));
|
||||||
|
|
||||||
|
auto type = reader::determine_document_type(root_relationships, content_types.second);
|
||||||
|
|
||||||
|
if(type != "excel")
|
||||||
|
{
|
||||||
|
throw std::runtime_error("unsupported document type: " + filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto workbook_relationships = reader::read_relationships(f.get_file_contents("xl/_rels/workbook.xml.rels"));
|
||||||
|
|
||||||
|
pugi::xml_document doc;
|
||||||
|
doc.load(f.get_file_contents("xl/workbook.xml").c_str());
|
||||||
|
|
||||||
|
auto root_node = doc.child("workbook");
|
||||||
|
auto sheets_node = root_node.child("sheets");
|
||||||
|
|
||||||
|
while(!worksheets_.empty())
|
||||||
|
{
|
||||||
|
remove_sheet(worksheets_.front());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> shared_strings;
|
||||||
|
if(f.has_file("xl/sharedStrings.xml"))
|
||||||
|
{
|
||||||
|
shared_strings = xlnt::reader::read_shared_string(f.get_file_contents("xl/sharedStrings.xml"));
|
||||||
|
}
|
||||||
|
|
||||||
|
for(auto sheet_node : sheets_node.children("sheet"))
|
||||||
|
{
|
||||||
|
auto relation_id = sheet_node.attribute("r:id").as_string();
|
||||||
|
auto ws = create_sheet(sheet_node.attribute("name").as_string());
|
||||||
|
std::string sheet_filename("xl/");
|
||||||
|
sheet_filename += workbook_relationships[relation_id].second;
|
||||||
|
xlnt::reader::read_worksheet(ws, f.get_file_contents(sheet_filename).c_str(), shared_strings);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void workbook::remove_sheet(worksheet ws)
|
||||||
|
{
|
||||||
|
auto match_iter = std::find(worksheets_.begin(), worksheets_.end(), ws);
|
||||||
|
if(match_iter == worksheets_.end())
|
||||||
|
{
|
||||||
|
throw std::runtime_error("worksheet not owned by this workbook");
|
||||||
|
}
|
||||||
|
worksheet::deallocate(*match_iter);
|
||||||
|
worksheets_.erase(match_iter);
|
||||||
|
}
|
||||||
|
|
||||||
|
worksheet workbook::create_sheet(std::size_t index)
|
||||||
|
{
|
||||||
|
auto ws = create_sheet();
|
||||||
|
if(index != worksheets_.size())
|
||||||
|
{
|
||||||
|
std::swap(worksheets_[index], worksheets_.back());
|
||||||
|
}
|
||||||
|
return ws;
|
||||||
|
}
|
||||||
|
|
||||||
|
worksheet workbook::create_sheet(std::size_t index, const std::string &title)
|
||||||
|
{
|
||||||
|
auto ws = create_sheet(index);
|
||||||
|
ws.set_title(title);
|
||||||
|
return ws;
|
||||||
|
}
|
||||||
|
|
||||||
|
worksheet workbook::create_sheet(const std::string &title)
|
||||||
|
{
|
||||||
|
if(title.length() > 31)
|
||||||
|
{
|
||||||
|
throw bad_sheet_title(title);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(std::find_if(title.begin(), title.end(),
|
||||||
|
[](char c) { return c == '*' || c == ':' || c == '/' || c == '\\' || c == '?' || c == '[' || c == ']'; }) != title.end())
|
||||||
|
{
|
||||||
|
throw bad_sheet_title(title);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(get_sheet_by_name(title) != nullptr)
|
||||||
|
{
|
||||||
|
throw std::runtime_error("sheet exists");
|
||||||
|
}
|
||||||
|
|
||||||
|
auto ws = worksheet::allocate(*this, title);
|
||||||
|
worksheets_.push_back(ws);
|
||||||
|
return worksheet(ws);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<worksheet>::iterator workbook::begin()
|
||||||
|
{
|
||||||
|
return worksheets_.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<worksheet>::iterator workbook::end()
|
||||||
|
{
|
||||||
|
return worksheets_.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> workbook::get_sheet_names() const
|
||||||
|
{
|
||||||
|
std::vector<std::string> names;
|
||||||
|
for(auto &ws : worksheets_)
|
||||||
|
{
|
||||||
|
names.push_back(ws.get_title());
|
||||||
|
}
|
||||||
|
return names;
|
||||||
|
}
|
||||||
|
|
||||||
|
worksheet workbook::operator[](const std::string &name)
|
||||||
|
{
|
||||||
|
for(auto sheet : worksheets_)
|
||||||
|
{
|
||||||
|
if(sheet.get_title() == name)
|
||||||
|
{
|
||||||
|
return sheet;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw std::runtime_error("sheet not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
worksheet workbook::operator[](int index)
|
||||||
|
{
|
||||||
|
return worksheets_[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
void workbook::clear()
|
||||||
|
{
|
||||||
|
while(!worksheets_.empty())
|
||||||
|
{
|
||||||
|
worksheet::deallocate(worksheets_.back());
|
||||||
|
worksheets_.pop_back();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void workbook::save(const std::string &filename)
|
||||||
|
{
|
||||||
|
zip_file f(filename, file_mode::create, file_access::write);
|
||||||
|
|
||||||
|
std::pair<std::unordered_map<std::string, std::string>, std::unordered_map<std::string, std::string>> content_types =
|
||||||
|
{
|
||||||
|
{
|
||||||
|
{"rels", "application/vnd.openxmlformats-package.relationships+xml"},
|
||||||
|
{"xml", "application/xml"}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
{"/xl/styles.xml", "application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml"},
|
||||||
|
{"/xl/workbook.xml", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml"},
|
||||||
|
{"/docProps/app.xml", "application/vnd.openxmlformats-officedocument.extended-properties+xml"},
|
||||||
|
{"/xl/worksheets/sheet1.xml", "application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml"},
|
||||||
|
{"/docProps/core.xml", "application/vnd.openxmlformats-package.core-properties+xml"},
|
||||||
|
{"/xl/theme/theme1.xml", "application/vnd.openxmlformats-officedocument.theme+xml"}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
f.set_file_contents("[Content_Types].xml", writer::write_content_types(content_types));
|
||||||
|
|
||||||
|
std::unordered_map<std::string, std::pair<std::string, std::string>> root_rels =
|
||||||
|
{
|
||||||
|
{"rId3", {"http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties", "docProps/app.xml"}},
|
||||||
|
{"rId2", {"http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties", "docProps/core.xml"}},
|
||||||
|
{"rId1", {"http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument", "xl/workbook.xml"}}
|
||||||
|
};
|
||||||
|
f.set_file_contents("_rels/.rels", writer::write_relationships(root_rels));
|
||||||
|
|
||||||
|
std::unordered_map<std::string, std::pair<std::string, std::string>> workbook_rels =
|
||||||
|
{
|
||||||
|
{"rId1", {"http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet", "worksheets/sheet1.xml"}},
|
||||||
|
{"rId2", {"http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles", "styles.xml"}},
|
||||||
|
{"rId3", {"http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme", "theme/theme1.xml"}}
|
||||||
|
};
|
||||||
|
f.set_file_contents("xl/_rels/workbook.xml.rels", writer::write_relationships(workbook_rels));
|
||||||
|
|
||||||
|
pugi::xml_document doc;
|
||||||
|
auto root_node = doc.append_child("workbook");
|
||||||
|
root_node.append_attribute("xmlns").set_value("http://schemas.openxmlformats.org/spreadsheetml/2006/main");
|
||||||
|
root_node.append_attribute("xmlns:r").set_value("http://schemas.openxmlformats.org/officeDocument/2006/relationships");
|
||||||
|
auto sheets_node = root_node.append_child("sheets");
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
for(auto ws : *this)
|
||||||
|
{
|
||||||
|
auto sheet_node = sheets_node.append_child("sheet");
|
||||||
|
sheet_node.append_attribute("name").set_value(ws.get_title().c_str());
|
||||||
|
sheet_node.append_attribute("sheetId").set_value(std::to_string(i + 1).c_str());
|
||||||
|
sheet_node.append_attribute("r:id").set_value((std::string("rId") + std::to_string(i + 1)).c_str());
|
||||||
|
std::string filename = "xl/worksheets/sheet";
|
||||||
|
f.set_file_contents(filename + std::to_string(i + 1) + ".xml", xlnt::writer::write_worksheet(ws));
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::stringstream ss;
|
||||||
|
doc.save(ss);
|
||||||
|
|
||||||
|
f.set_file_contents("xl/workbook.xml", ss.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool workbook::operator==(const workbook &rhs) const
|
||||||
|
{
|
||||||
|
if(optimized_write_ == rhs.optimized_write_
|
||||||
|
&& optimized_read_ == rhs.optimized_read_
|
||||||
|
&& guess_types_ == rhs.guess_types_
|
||||||
|
&& data_only_ == rhs.data_only_
|
||||||
|
&& active_sheet_index_ == rhs.active_sheet_index_)
|
||||||
|
{
|
||||||
|
if(worksheets_.size() != rhs.worksheets_.size())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(std::size_t i = 0; i < worksheets_.size(); i++)
|
||||||
|
{
|
||||||
|
if(worksheets_[i] != rhs.worksheets_[i])
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
if(named_ranges_.size() != rhs.named_ranges_.size())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(int i = 0; i < named_ranges_.size(); i++)
|
||||||
|
{
|
||||||
|
if(named_ranges_[i] != rhs.named_ranges_[i])
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(relationships_.size() != rhs.relationships_.size())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(int i = 0; i < relationships_.size(); i++)
|
||||||
|
{
|
||||||
|
if(relationships_[i] != rhs.relationships_[i])
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(drawings_.size() != rhs.drawings_.size())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(int i = 0; i < drawings_.size(); i++)
|
||||||
|
{
|
||||||
|
if(drawings_[i] != rhs.drawings_[i])
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
106
source/workbook.h
Normal file
106
source/workbook.h
Normal file
|
@ -0,0 +1,106 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <utility>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace xlnt {
|
||||||
|
|
||||||
|
class drawing;
|
||||||
|
class named_range;
|
||||||
|
class range_reference;
|
||||||
|
class relationship;
|
||||||
|
class worksheet;
|
||||||
|
|
||||||
|
enum class optimization
|
||||||
|
{
|
||||||
|
write,
|
||||||
|
read,
|
||||||
|
none
|
||||||
|
};
|
||||||
|
|
||||||
|
class workbook
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
//constructors
|
||||||
|
workbook(optimization optimization = optimization::none);
|
||||||
|
~workbook();
|
||||||
|
|
||||||
|
//prevent copy and assignment
|
||||||
|
workbook(const workbook &) = delete;
|
||||||
|
const workbook &operator=(const workbook &) = delete;
|
||||||
|
|
||||||
|
void read_workbook_settings(const std::string &xml_source);
|
||||||
|
|
||||||
|
//getters
|
||||||
|
worksheet get_active_sheet();
|
||||||
|
bool get_optimized_write() const { return optimized_write_; }
|
||||||
|
bool get_guess_types() const { return guess_types_; }
|
||||||
|
bool get_data_only() const { return data_only_; }
|
||||||
|
|
||||||
|
//create
|
||||||
|
worksheet create_sheet();
|
||||||
|
worksheet create_sheet(std::size_t index);
|
||||||
|
worksheet create_sheet(const std::string &title);
|
||||||
|
worksheet create_sheet(std::size_t index, const std::string &title);
|
||||||
|
|
||||||
|
//add
|
||||||
|
void add_sheet(worksheet worksheet);
|
||||||
|
void add_sheet(worksheet worksheet, std::size_t index);
|
||||||
|
|
||||||
|
//remove
|
||||||
|
void remove_sheet(worksheet worksheet);
|
||||||
|
void clear();
|
||||||
|
|
||||||
|
//container operations
|
||||||
|
worksheet get_sheet_by_name(const std::string &sheet_name);
|
||||||
|
|
||||||
|
bool contains(const std::string &key) const;
|
||||||
|
|
||||||
|
int get_index(worksheet worksheet);
|
||||||
|
|
||||||
|
worksheet operator[](const std::string &name);
|
||||||
|
worksheet operator[](int index);
|
||||||
|
|
||||||
|
std::vector<worksheet>::iterator begin();
|
||||||
|
std::vector<worksheet>::iterator end();
|
||||||
|
|
||||||
|
std::vector<worksheet>::const_iterator begin() const;
|
||||||
|
std::vector<worksheet>::const_iterator end() const;
|
||||||
|
|
||||||
|
std::vector<worksheet>::const_iterator cbegin() const;
|
||||||
|
std::vector<worksheet>::const_iterator cend() const;
|
||||||
|
|
||||||
|
std::vector<std::string> get_sheet_names() const;
|
||||||
|
|
||||||
|
//named ranges
|
||||||
|
named_range create_named_range(const std::string &name, worksheet worksheet, const range_reference &reference);
|
||||||
|
std::vector<named_range> get_named_ranges();
|
||||||
|
void add_named_range(const std::string &name, named_range named_range);
|
||||||
|
bool has_named_range(const std::string &name, worksheet ws) const;
|
||||||
|
named_range get_named_range(const std::string &name, worksheet ws);
|
||||||
|
void remove_named_range(named_range named_range);
|
||||||
|
|
||||||
|
//serialization
|
||||||
|
void save(const std::string &filename);
|
||||||
|
void load(const std::string &filename);
|
||||||
|
|
||||||
|
bool operator==(const workbook &rhs) const;
|
||||||
|
|
||||||
|
std::unordered_map<std::string, std::pair<std::string, std::string>> get_root_relationships() const;
|
||||||
|
std::unordered_map<std::string, std::pair<std::string, std::string>> get_relationships() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool optimized_write_;
|
||||||
|
bool optimized_read_;
|
||||||
|
bool guess_types_;
|
||||||
|
bool data_only_;
|
||||||
|
int active_sheet_index_;
|
||||||
|
std::vector<worksheet> worksheets_;
|
||||||
|
std::unordered_map<std::string, named_range> named_ranges_;
|
||||||
|
std::vector<relationship> relationships_;
|
||||||
|
std::vector<drawing> drawings_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace xlnt
|
558
source/worksheet.cpp
Normal file
558
source/worksheet.cpp
Normal file
|
@ -0,0 +1,558 @@
|
||||||
|
#include "worksheet.h"
|
||||||
|
#include "cell.h"
|
||||||
|
#include "named_range.h"
|
||||||
|
#include "reference.h"
|
||||||
|
#include "relationship.h"
|
||||||
|
#include "workbook.h"
|
||||||
|
|
||||||
|
namespace xlnt {
|
||||||
|
|
||||||
|
struct worksheet_struct
|
||||||
|
{
|
||||||
|
worksheet_struct(workbook &parent_workbook, const std::string &title)
|
||||||
|
: parent_(parent_workbook), title_(title), freeze_panes_("A1")
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
~worksheet_struct()
|
||||||
|
{
|
||||||
|
clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear()
|
||||||
|
{
|
||||||
|
while(!cell_map_.empty())
|
||||||
|
{
|
||||||
|
cell::deallocate(cell_map_.begin()->second.root_);
|
||||||
|
cell_map_.erase(cell_map_.begin()->first);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void garbage_collect()
|
||||||
|
{
|
||||||
|
std::vector<cell_reference> null_cell_keys;
|
||||||
|
|
||||||
|
for(auto key_cell_pair : cell_map_)
|
||||||
|
{
|
||||||
|
if(key_cell_pair.second.get_data_type() == cell::type::null)
|
||||||
|
{
|
||||||
|
null_cell_keys.push_back(key_cell_pair.first);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while(!null_cell_keys.empty())
|
||||||
|
{
|
||||||
|
cell_map_.erase(null_cell_keys.back());
|
||||||
|
null_cell_keys.pop_back();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::list<cell> get_cell_collection()
|
||||||
|
{
|
||||||
|
std::list<xlnt::cell> cells;
|
||||||
|
for(auto cell : cell_map_)
|
||||||
|
{
|
||||||
|
cells.push_front(xlnt::cell(cell.second));
|
||||||
|
}
|
||||||
|
return cells;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string get_title() const
|
||||||
|
{
|
||||||
|
return title_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_title(const std::string &title)
|
||||||
|
{
|
||||||
|
title_ = title;
|
||||||
|
}
|
||||||
|
|
||||||
|
cell_reference get_freeze_panes() const
|
||||||
|
{
|
||||||
|
return freeze_panes_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_freeze_panes(const cell_reference &ref)
|
||||||
|
{
|
||||||
|
freeze_panes_ = ref;
|
||||||
|
}
|
||||||
|
|
||||||
|
void unfreeze_panes()
|
||||||
|
{
|
||||||
|
freeze_panes_ = "A1";
|
||||||
|
}
|
||||||
|
|
||||||
|
xlnt::cell get_cell(const cell_reference &reference)
|
||||||
|
{
|
||||||
|
if(cell_map_.find(reference) == cell_map_.end())
|
||||||
|
{
|
||||||
|
auto cell = cell::allocate(this, reference.get_column_index(), reference.get_row_index());
|
||||||
|
cell_map_[reference] = cell;
|
||||||
|
}
|
||||||
|
|
||||||
|
return cell_map_[reference];
|
||||||
|
}
|
||||||
|
|
||||||
|
int get_highest_row() const
|
||||||
|
{
|
||||||
|
int highest = 0;
|
||||||
|
for(auto cell : cell_map_)
|
||||||
|
{
|
||||||
|
highest = (std::max)(highest, cell.first.get_row_index());
|
||||||
|
}
|
||||||
|
return highest + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int get_highest_column() const
|
||||||
|
{
|
||||||
|
int highest = 0;
|
||||||
|
for(auto cell : cell_map_)
|
||||||
|
{
|
||||||
|
highest = (std::max)(highest, cell.first.get_column_index());
|
||||||
|
}
|
||||||
|
return highest + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int get_lowest_row() const
|
||||||
|
{
|
||||||
|
if(cell_map_.empty())
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int lowest = cell_map_.begin()->first.get_row_index();
|
||||||
|
|
||||||
|
for(auto cell : cell_map_)
|
||||||
|
{
|
||||||
|
lowest = (std::min)(lowest, cell.first.get_row_index());
|
||||||
|
}
|
||||||
|
|
||||||
|
return lowest + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int get_lowest_column() const
|
||||||
|
{
|
||||||
|
if(cell_map_.empty())
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int lowest = cell_map_.begin()->first.get_column_index();
|
||||||
|
|
||||||
|
for(auto cell : cell_map_)
|
||||||
|
{
|
||||||
|
lowest = (std::min)(lowest, cell.first.get_column_index());
|
||||||
|
}
|
||||||
|
|
||||||
|
return lowest + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
range_reference calculate_dimension() const
|
||||||
|
{
|
||||||
|
int lowest_column = get_lowest_column();
|
||||||
|
int lowest_row = get_lowest_row();
|
||||||
|
|
||||||
|
int highest_column = get_highest_column();
|
||||||
|
int highest_row = get_highest_row();
|
||||||
|
|
||||||
|
return range_reference(lowest_column - 1, lowest_row - 1, highest_column - 1, highest_row - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
xlnt::range get_range(const range_reference &reference)
|
||||||
|
{
|
||||||
|
xlnt::range r;
|
||||||
|
|
||||||
|
if(!reference.is_single_cell())
|
||||||
|
{
|
||||||
|
cell_reference min_ref = reference.get_top_left();
|
||||||
|
cell_reference max_ref = reference.get_bottom_right();
|
||||||
|
|
||||||
|
for(int row = min_ref.get_row_index(); row <= max_ref.get_row_index(); row++)
|
||||||
|
{
|
||||||
|
r.push_back(std::vector<xlnt::cell>());
|
||||||
|
for(int column = min_ref.get_column_index(); column <= max_ref.get_column_index(); column++)
|
||||||
|
{
|
||||||
|
r.back().push_back(get_cell(cell_reference(column, row)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
r.push_back(std::vector<xlnt::cell>());
|
||||||
|
r.back().push_back(get_cell(reference.get_top_left()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
relationship create_relationship(const std::string &relationship_type, const std::string &target_uri)
|
||||||
|
{
|
||||||
|
std::string r_id = "rId" + std::to_string(relationships_.size() + 1);
|
||||||
|
relationships_.push_back(relationship(relationship_type, r_id, target_uri));
|
||||||
|
return relationships_.back();
|
||||||
|
}
|
||||||
|
|
||||||
|
//void add_chart(chart chart);
|
||||||
|
|
||||||
|
void merge_cells(const range_reference &reference)
|
||||||
|
{
|
||||||
|
merged_cells_.push_back(reference);
|
||||||
|
bool first = true;
|
||||||
|
for(auto row : get_range(reference))
|
||||||
|
{
|
||||||
|
for(auto cell : row)
|
||||||
|
{
|
||||||
|
cell.set_merged(true);
|
||||||
|
if(!first)
|
||||||
|
{
|
||||||
|
cell.bind_value();
|
||||||
|
}
|
||||||
|
first = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void unmerge_cells(const range_reference &reference)
|
||||||
|
{
|
||||||
|
auto match = std::find(merged_cells_.begin(), merged_cells_.end(), reference);
|
||||||
|
if(match == merged_cells_.end())
|
||||||
|
{
|
||||||
|
throw std::runtime_error("cells not merged");
|
||||||
|
}
|
||||||
|
merged_cells_.erase(match);
|
||||||
|
for(auto row : get_range(reference))
|
||||||
|
{
|
||||||
|
for(auto cell : row)
|
||||||
|
{
|
||||||
|
cell.set_merged(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void append(const std::vector<std::string> &cells)
|
||||||
|
{
|
||||||
|
int row = get_highest_row();
|
||||||
|
if(cell_map_.size() == 0)
|
||||||
|
{
|
||||||
|
row--;
|
||||||
|
}
|
||||||
|
int column = 0;
|
||||||
|
for(auto cell : cells)
|
||||||
|
{
|
||||||
|
this->get_cell(cell_reference(column++, row)) = cell;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void append(const std::unordered_map<std::string, std::string> &cells)
|
||||||
|
{
|
||||||
|
int row = get_highest_row() - 1;
|
||||||
|
if(cell_map_.size() != 0)
|
||||||
|
{
|
||||||
|
row++;
|
||||||
|
}
|
||||||
|
for(auto cell : cells)
|
||||||
|
{
|
||||||
|
this->get_cell(cell_reference(cell.first, row + 1)) = cell.second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void append(const std::unordered_map<int, std::string> &cells)
|
||||||
|
{
|
||||||
|
int row = get_highest_row() - 1;
|
||||||
|
if(cell_map_.size() != 0)
|
||||||
|
{
|
||||||
|
row++;
|
||||||
|
}
|
||||||
|
for(auto cell : cells)
|
||||||
|
{
|
||||||
|
this->get_cell(cell_reference(cell.first, row)) = cell.second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
xlnt::range rows()
|
||||||
|
{
|
||||||
|
return get_range(calculate_dimension());
|
||||||
|
}
|
||||||
|
|
||||||
|
xlnt::range columns()
|
||||||
|
{
|
||||||
|
int max_row = get_highest_row();
|
||||||
|
xlnt::range cols;
|
||||||
|
for(int col_idx = 0; col_idx < get_highest_column(); col_idx++)
|
||||||
|
{
|
||||||
|
cols.push_back(std::vector<xlnt::cell>());
|
||||||
|
for(auto row : get_range(range_reference(col_idx, 0, col_idx, max_row)))
|
||||||
|
{
|
||||||
|
cols.back().push_back(row[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return cols;
|
||||||
|
}
|
||||||
|
|
||||||
|
void operator=(const worksheet_struct &other) = delete;
|
||||||
|
|
||||||
|
workbook &parent_;
|
||||||
|
std::string title_;
|
||||||
|
cell_reference freeze_panes_;
|
||||||
|
std::unordered_map<cell_reference, xlnt::cell, cell_reference_hash> cell_map_;
|
||||||
|
std::vector<relationship> relationships_;
|
||||||
|
page_setup page_setup_;
|
||||||
|
range_reference auto_filter_;
|
||||||
|
margins page_margins_;
|
||||||
|
std::vector<range_reference> merged_cells_;
|
||||||
|
std::unordered_map<std::string, named_range> named_ranges_;
|
||||||
|
};
|
||||||
|
|
||||||
|
worksheet::worksheet() : root_(nullptr)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
worksheet::worksheet(worksheet_struct *root) : root_(root)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
worksheet::worksheet(workbook &parent)
|
||||||
|
{
|
||||||
|
*this = parent.create_sheet();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool worksheet::has_frozen_panes() const
|
||||||
|
{
|
||||||
|
return !(get_frozen_panes() == cell_reference("A1"));
|
||||||
|
}
|
||||||
|
|
||||||
|
named_range worksheet::create_named_range(const std::string &name, const range_reference &reference)
|
||||||
|
{
|
||||||
|
root_->named_ranges_[name] = named_range(named_range::allocate(name, *this, reference));
|
||||||
|
return root_->named_ranges_[name];
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<range_reference> worksheet::get_merged_ranges() const
|
||||||
|
{
|
||||||
|
return root_->merged_cells_;
|
||||||
|
}
|
||||||
|
|
||||||
|
margins &worksheet::get_page_margins()
|
||||||
|
{
|
||||||
|
return root_->page_margins_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void worksheet::set_auto_filter(const range_reference &reference)
|
||||||
|
{
|
||||||
|
root_->auto_filter_ = reference;
|
||||||
|
}
|
||||||
|
|
||||||
|
void worksheet::set_auto_filter(const xlnt::range &range)
|
||||||
|
{
|
||||||
|
set_auto_filter(range_reference(range[0][0].get_reference(), range.back().back().get_reference()));
|
||||||
|
}
|
||||||
|
|
||||||
|
range_reference worksheet::get_auto_filter() const
|
||||||
|
{
|
||||||
|
return root_->auto_filter_;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool worksheet::has_auto_filter() const
|
||||||
|
{
|
||||||
|
return root_->auto_filter_.get_width() > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void worksheet::unset_auto_filter()
|
||||||
|
{
|
||||||
|
root_->auto_filter_ = range_reference(0, 0, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
page_setup &worksheet::get_page_setup()
|
||||||
|
{
|
||||||
|
return root_->page_setup_;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string worksheet::to_string() const
|
||||||
|
{
|
||||||
|
return "<Worksheet \"" + root_->title_ + "\">";
|
||||||
|
}
|
||||||
|
|
||||||
|
workbook &worksheet::get_parent() const
|
||||||
|
{
|
||||||
|
return root_->parent_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void worksheet::garbage_collect()
|
||||||
|
{
|
||||||
|
root_->garbage_collect();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::list<cell> worksheet::get_cell_collection()
|
||||||
|
{
|
||||||
|
return root_->get_cell_collection();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string worksheet::get_title() const
|
||||||
|
{
|
||||||
|
if(root_ == nullptr)
|
||||||
|
{
|
||||||
|
throw std::runtime_error("null worksheet");
|
||||||
|
}
|
||||||
|
return root_->title_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void worksheet::set_title(const std::string &title)
|
||||||
|
{
|
||||||
|
root_->title_ = title;
|
||||||
|
}
|
||||||
|
|
||||||
|
cell_reference worksheet::get_frozen_panes() const
|
||||||
|
{
|
||||||
|
return root_->freeze_panes_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void worksheet::freeze_panes(xlnt::cell top_left_cell)
|
||||||
|
{
|
||||||
|
root_->set_freeze_panes(top_left_cell.get_reference());
|
||||||
|
}
|
||||||
|
|
||||||
|
void worksheet::freeze_panes(const std::string &top_left_coordinate)
|
||||||
|
{
|
||||||
|
root_->set_freeze_panes(top_left_coordinate);
|
||||||
|
}
|
||||||
|
|
||||||
|
void worksheet::unfreeze_panes()
|
||||||
|
{
|
||||||
|
root_->unfreeze_panes();
|
||||||
|
}
|
||||||
|
|
||||||
|
cell worksheet::get_cell(const cell_reference &reference)
|
||||||
|
{
|
||||||
|
return root_->get_cell(reference);
|
||||||
|
}
|
||||||
|
|
||||||
|
range worksheet::get_named_range(const std::string &name)
|
||||||
|
{
|
||||||
|
return get_range(root_->parent_.get_named_range(name, *this).get_target_range());
|
||||||
|
}
|
||||||
|
|
||||||
|
int worksheet::get_highest_row() const
|
||||||
|
{
|
||||||
|
return root_->get_highest_row();
|
||||||
|
}
|
||||||
|
|
||||||
|
int worksheet::get_highest_column() const
|
||||||
|
{
|
||||||
|
return root_->get_highest_column();
|
||||||
|
}
|
||||||
|
|
||||||
|
range_reference worksheet::calculate_dimension() const
|
||||||
|
{
|
||||||
|
return root_->calculate_dimension();
|
||||||
|
}
|
||||||
|
|
||||||
|
range worksheet::get_range(const range_reference &reference)
|
||||||
|
{
|
||||||
|
return root_->get_range(reference);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<relationship> worksheet::get_relationships()
|
||||||
|
{
|
||||||
|
return root_->relationships_;
|
||||||
|
}
|
||||||
|
|
||||||
|
relationship worksheet::create_relationship(const std::string &relationship_type, const std::string &target_uri)
|
||||||
|
{
|
||||||
|
return root_->create_relationship(relationship_type, target_uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
//void worksheet::add_chart(chart chart);
|
||||||
|
|
||||||
|
void worksheet::merge_cells(const range_reference &reference)
|
||||||
|
{
|
||||||
|
root_->merge_cells(reference);
|
||||||
|
}
|
||||||
|
|
||||||
|
void worksheet::unmerge_cells(const range_reference &reference)
|
||||||
|
{
|
||||||
|
root_->unmerge_cells(reference);
|
||||||
|
}
|
||||||
|
|
||||||
|
void worksheet::append(const std::vector<std::string> &cells)
|
||||||
|
{
|
||||||
|
root_->append(cells);
|
||||||
|
}
|
||||||
|
|
||||||
|
void worksheet::append(const std::unordered_map<std::string, std::string> &cells)
|
||||||
|
{
|
||||||
|
root_->append(cells);
|
||||||
|
}
|
||||||
|
|
||||||
|
void worksheet::append(const std::unordered_map<int, std::string> &cells)
|
||||||
|
{
|
||||||
|
root_->append(cells);
|
||||||
|
}
|
||||||
|
|
||||||
|
xlnt::range worksheet::rows() const
|
||||||
|
{
|
||||||
|
return root_->rows();
|
||||||
|
}
|
||||||
|
|
||||||
|
xlnt::range worksheet::columns() const
|
||||||
|
{
|
||||||
|
return root_->columns();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool worksheet::operator==(const worksheet &other) const
|
||||||
|
{
|
||||||
|
return root_ == other.root_;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool worksheet::operator!=(const worksheet &other) const
|
||||||
|
{
|
||||||
|
return root_ != other.root_;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool worksheet::operator==(std::nullptr_t) const
|
||||||
|
{
|
||||||
|
return root_ == nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool worksheet::operator!=(std::nullptr_t) const
|
||||||
|
{
|
||||||
|
return root_ != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void worksheet::operator=(const worksheet &other)
|
||||||
|
{
|
||||||
|
root_ = other.root_;
|
||||||
|
}
|
||||||
|
|
||||||
|
cell worksheet::operator[](const cell_reference &ref)
|
||||||
|
{
|
||||||
|
return get_cell(ref);
|
||||||
|
}
|
||||||
|
|
||||||
|
range worksheet::operator[](const range_reference &ref)
|
||||||
|
{
|
||||||
|
return get_range(ref);
|
||||||
|
}
|
||||||
|
|
||||||
|
range worksheet::operator[](const std::string &name)
|
||||||
|
{
|
||||||
|
if(root_->parent_.has_named_range(name, *this))
|
||||||
|
{
|
||||||
|
return get_named_range(name);
|
||||||
|
}
|
||||||
|
return get_range(range_reference(name));
|
||||||
|
}
|
||||||
|
|
||||||
|
worksheet worksheet::allocate(xlnt::workbook &owner, const std::string &title)
|
||||||
|
{
|
||||||
|
return new worksheet_struct(owner, title);
|
||||||
|
}
|
||||||
|
|
||||||
|
void worksheet::deallocate(xlnt::worksheet ws)
|
||||||
|
{
|
||||||
|
delete ws.root_;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace xlnt
|
199
source/worksheet.h
Normal file
199
source/worksheet.h
Normal file
|
@ -0,0 +1,199 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <list>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
|
#include "range.h"
|
||||||
|
|
||||||
|
namespace xlnt {
|
||||||
|
|
||||||
|
class cell;
|
||||||
|
class cell_reference;
|
||||||
|
class named_range;
|
||||||
|
class range_reference;
|
||||||
|
class relationship;
|
||||||
|
class workbook;
|
||||||
|
|
||||||
|
struct worksheet_struct;
|
||||||
|
|
||||||
|
struct page_setup
|
||||||
|
{
|
||||||
|
enum class page_break
|
||||||
|
{
|
||||||
|
none = 0,
|
||||||
|
row = 1,
|
||||||
|
column = 2
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class sheet_state
|
||||||
|
{
|
||||||
|
visible,
|
||||||
|
hidden,
|
||||||
|
very_hidden
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class paper_size
|
||||||
|
{
|
||||||
|
letter = 1,
|
||||||
|
letter_small = 2,
|
||||||
|
tabloid = 3,
|
||||||
|
ledger = 4,
|
||||||
|
legal = 5,
|
||||||
|
statement = 6,
|
||||||
|
executive = 7,
|
||||||
|
a3 = 8,
|
||||||
|
a4 = 9,
|
||||||
|
a4_small = 10,
|
||||||
|
a5 = 11
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class orientation
|
||||||
|
{
|
||||||
|
portrait,
|
||||||
|
landscape
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
page_setup() : default_(true), break_(page_break::none), sheet_state_(sheet_state::visible), paper_size_(paper_size::letter),
|
||||||
|
orientation_(orientation::portrait), fit_to_page_(false), fit_to_height_(false), fit_to_width_(false) {}
|
||||||
|
bool is_default() const { return default_; }
|
||||||
|
page_break get_break() const { return break_; }
|
||||||
|
void set_break(page_break b) { default_ = false; break_ = b; }
|
||||||
|
sheet_state get_sheet_state() const { return sheet_state_; }
|
||||||
|
void set_sheet_state(sheet_state sheet_state) { default_ = false; sheet_state_ = sheet_state; }
|
||||||
|
paper_size get_paper_size() const { return paper_size_; }
|
||||||
|
void set_paper_size(paper_size paper_size) { default_ = false; paper_size_ = paper_size; }
|
||||||
|
orientation get_orientation() const { return orientation_; }
|
||||||
|
void set_orientation(orientation orientation) { default_ = false; orientation_ = orientation; }
|
||||||
|
bool fit_to_page() const { return fit_to_page_; }
|
||||||
|
void set_fit_to_page(bool fit_to_page) { default_ = false; fit_to_page_ = fit_to_page; }
|
||||||
|
bool fit_to_height() const { return fit_to_height_; }
|
||||||
|
void set_fit_to_height(bool fit_to_height) { default_ = false; fit_to_height_ = fit_to_height; }
|
||||||
|
bool fit_to_width() const { return fit_to_width_; }
|
||||||
|
void set_fit_to_width(bool fit_to_width) { default_ = false; fit_to_width_ = fit_to_width; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool default_;
|
||||||
|
page_break break_;
|
||||||
|
sheet_state sheet_state_;
|
||||||
|
paper_size paper_size_;
|
||||||
|
orientation orientation_;
|
||||||
|
bool fit_to_page_;
|
||||||
|
bool fit_to_height_;
|
||||||
|
bool fit_to_width_;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct margins
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
margins() : default_(true), top_(0), left_(0), bottom_(0), right_(0), header_(0), footer_(0) {}
|
||||||
|
|
||||||
|
bool is_default() const { return default_; }
|
||||||
|
double get_top() const { return top_; }
|
||||||
|
void set_top(double top) { default_ = false; top_ = top; }
|
||||||
|
double get_left() const { return left_; }
|
||||||
|
void set_left(double left) { default_ = false; left_ = left; }
|
||||||
|
double get_bottom() const { return bottom_; }
|
||||||
|
void set_bottom(double bottom) { default_ = false; bottom_ = bottom; }
|
||||||
|
double get_right() const { return right_; }
|
||||||
|
void set_right(double right) { default_ = false; right_ = right; }
|
||||||
|
double get_header() const { return header_; }
|
||||||
|
void set_header(double header) { default_ = false; header_ = header; }
|
||||||
|
double get_footer() const { return footer_; }
|
||||||
|
void set_footer(double footer) { default_ = false; footer_ = footer; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool default_;
|
||||||
|
double top_;
|
||||||
|
double left_;
|
||||||
|
double bottom_;
|
||||||
|
double right_;
|
||||||
|
double header_;
|
||||||
|
double footer_;
|
||||||
|
};
|
||||||
|
|
||||||
|
class worksheet
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
worksheet();
|
||||||
|
worksheet(workbook &parent);
|
||||||
|
worksheet(worksheet_struct *root);
|
||||||
|
|
||||||
|
std::string to_string() const;
|
||||||
|
workbook &get_parent() const;
|
||||||
|
void garbage_collect();
|
||||||
|
|
||||||
|
// title
|
||||||
|
std::string get_title() const;
|
||||||
|
void set_title(const std::string &title);
|
||||||
|
|
||||||
|
// freeze panes
|
||||||
|
cell_reference get_frozen_panes() const;
|
||||||
|
void freeze_panes(cell top_left_cell);
|
||||||
|
void freeze_panes(const std::string &top_left_coordinate);
|
||||||
|
void unfreeze_panes();
|
||||||
|
bool has_frozen_panes() const;
|
||||||
|
|
||||||
|
// container
|
||||||
|
cell get_cell(const cell_reference &reference);
|
||||||
|
range get_range(const range_reference &reference);
|
||||||
|
range get_named_range(const std::string &name);
|
||||||
|
range rows() const;
|
||||||
|
range columns() const;
|
||||||
|
std::list<cell> get_cell_collection();
|
||||||
|
named_range create_named_range(const std::string &name, const range_reference &reference);
|
||||||
|
|
||||||
|
// extents
|
||||||
|
int get_highest_row() const;
|
||||||
|
int get_highest_column() const;
|
||||||
|
range_reference calculate_dimension() const;
|
||||||
|
|
||||||
|
// relationships
|
||||||
|
relationship create_relationship(const std::string &relationship_type, const std::string &target_uri);
|
||||||
|
std::vector<relationship> get_relationships();
|
||||||
|
|
||||||
|
// charts
|
||||||
|
//void add_chart(chart chart);
|
||||||
|
|
||||||
|
// cell merge
|
||||||
|
void merge_cells(const range_reference &reference);
|
||||||
|
void unmerge_cells(const range_reference &reference);
|
||||||
|
std::vector<range_reference> get_merged_ranges() const;
|
||||||
|
|
||||||
|
// append
|
||||||
|
void append(const std::vector<std::string> &cells);
|
||||||
|
void append(const std::unordered_map<std::string, std::string> &cells);
|
||||||
|
void append(const std::unordered_map<int, std::string> &cells);
|
||||||
|
|
||||||
|
// operators
|
||||||
|
bool operator==(const worksheet &other) const;
|
||||||
|
bool operator!=(const worksheet &other) const;
|
||||||
|
bool operator==(std::nullptr_t) const;
|
||||||
|
bool operator!=(std::nullptr_t) const;
|
||||||
|
void operator=(const worksheet &other);
|
||||||
|
cell operator[](const cell_reference &reference);
|
||||||
|
range operator[](const range_reference &reference);
|
||||||
|
range operator[](const std::string &named_range);
|
||||||
|
|
||||||
|
// page
|
||||||
|
page_setup &get_page_setup();
|
||||||
|
margins &get_page_margins();
|
||||||
|
|
||||||
|
// auto filter
|
||||||
|
range_reference get_auto_filter() const;
|
||||||
|
void set_auto_filter(const xlnt::range &range);
|
||||||
|
void set_auto_filter(const range_reference &reference);
|
||||||
|
void unset_auto_filter();
|
||||||
|
bool has_auto_filter() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class workbook;
|
||||||
|
friend class cell;
|
||||||
|
|
||||||
|
static worksheet allocate(workbook &owner, const std::string &title);
|
||||||
|
static void deallocate(worksheet ws);
|
||||||
|
|
||||||
|
worksheet_struct *root_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace xlnt
|
1046
source/writer.cpp
Normal file
1046
source/writer.cpp
Normal file
File diff suppressed because it is too large
Load Diff
20
source/writer.h
Normal file
20
source/writer.h
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace xlnt {
|
||||||
|
|
||||||
|
class worksheet;
|
||||||
|
|
||||||
|
class writer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static std::string write_worksheet(worksheet ws);
|
||||||
|
static std::string write_worksheet(worksheet ws, const std::vector<std::string> &string_table);
|
||||||
|
static std::string write_theme();
|
||||||
|
static std::string write_content_types(const std::pair<std::unordered_map<std::string, std::string>, std::unordered_map<std::string, std::string>> &content_types);
|
||||||
|
static std::string write_relationships(const std::unordered_map<std::string, std::pair<std::string, std::string>> &relationships);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace xlnt
|
3434
source/xlnt.cpp
3434
source/xlnt.cpp
File diff suppressed because it is too large
Load Diff
1178
source/xlnt.h
1178
source/xlnt.h
File diff suppressed because it is too large
Load Diff
401
source/zip_file.cpp
Normal file
401
source/zip_file.cpp
Normal file
|
@ -0,0 +1,401 @@
|
||||||
|
#include <array>
|
||||||
|
#include <fstream>
|
||||||
|
|
||||||
|
#include "zip_file.h"
|
||||||
|
|
||||||
|
namespace xlnt {
|
||||||
|
|
||||||
|
zip_file::zip_file(const std::string &filename, file_mode mode, file_access access)
|
||||||
|
: zip_file_(nullptr),
|
||||||
|
unzip_file_(nullptr),
|
||||||
|
current_state_(state::closed),
|
||||||
|
filename_(filename),
|
||||||
|
modified_(false),
|
||||||
|
// mode_(mode),
|
||||||
|
access_(access)
|
||||||
|
{
|
||||||
|
switch(mode)
|
||||||
|
{
|
||||||
|
case file_mode::open:
|
||||||
|
read_all();
|
||||||
|
break;
|
||||||
|
case file_mode::open_or_create:
|
||||||
|
if(file_exists(filename))
|
||||||
|
{
|
||||||
|
read_all();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
flush(true);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case file_mode::create:
|
||||||
|
flush(true);
|
||||||
|
break;
|
||||||
|
case file_mode::create_new:
|
||||||
|
if(file_exists(filename))
|
||||||
|
{
|
||||||
|
throw std::runtime_error("file exists");
|
||||||
|
}
|
||||||
|
flush(true);
|
||||||
|
break;
|
||||||
|
case file_mode::truncate:
|
||||||
|
if((int)access & (int)file_access::read)
|
||||||
|
{
|
||||||
|
throw std::runtime_error("cannot read from file opened with file_mode truncate");
|
||||||
|
}
|
||||||
|
flush(true);
|
||||||
|
break;
|
||||||
|
case file_mode::append:
|
||||||
|
read_all();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
zip_file::~zip_file()
|
||||||
|
{
|
||||||
|
change_state(state::closed);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string zip_file::get_file_contents(const std::string &filename)
|
||||||
|
{
|
||||||
|
return files_[filename];
|
||||||
|
}
|
||||||
|
|
||||||
|
void zip_file::set_file_contents(const std::string &filename, const std::string &contents)
|
||||||
|
{
|
||||||
|
if(!has_file(filename) || files_[filename] != contents)
|
||||||
|
{
|
||||||
|
modified_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
files_[filename] = contents;
|
||||||
|
}
|
||||||
|
|
||||||
|
void zip_file::delete_file(const std::string &filename)
|
||||||
|
{
|
||||||
|
files_.erase(filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool zip_file::has_file(const std::string &filename)
|
||||||
|
{
|
||||||
|
return files_.find(filename) != files_.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
void zip_file::flush(bool force_write)
|
||||||
|
{
|
||||||
|
if(modified_ || force_write)
|
||||||
|
{
|
||||||
|
write_all();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void zip_file::read_all()
|
||||||
|
{
|
||||||
|
if(!((int)access_ & (int)file_access::read))
|
||||||
|
{
|
||||||
|
throw std::runtime_error("don't have read access");
|
||||||
|
}
|
||||||
|
|
||||||
|
change_state(state::read);
|
||||||
|
|
||||||
|
int result = unzGoToFirstFile(unzip_file_);
|
||||||
|
|
||||||
|
std::array<char, 1000> file_name_buffer = {{'\0'}};
|
||||||
|
std::vector<char> file_buffer;
|
||||||
|
|
||||||
|
while(result == UNZ_OK)
|
||||||
|
{
|
||||||
|
unz_file_info file_info;
|
||||||
|
file_name_buffer.fill('\0');
|
||||||
|
|
||||||
|
result = unzGetCurrentFileInfo(unzip_file_, &file_info, file_name_buffer.data(),
|
||||||
|
static_cast<uLong>(file_name_buffer.size()), nullptr, 0, nullptr, 0);
|
||||||
|
|
||||||
|
if(result != UNZ_OK)
|
||||||
|
{
|
||||||
|
throw result;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = unzOpenCurrentFile(unzip_file_);
|
||||||
|
|
||||||
|
if(result != UNZ_OK)
|
||||||
|
{
|
||||||
|
throw result;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(file_buffer.size() < file_info.uncompressed_size + 1)
|
||||||
|
{
|
||||||
|
file_buffer.resize(file_info.uncompressed_size + 1);
|
||||||
|
}
|
||||||
|
file_buffer[file_info.uncompressed_size] = '\0';
|
||||||
|
|
||||||
|
result = unzReadCurrentFile(unzip_file_, file_buffer.data(), file_info.uncompressed_size);
|
||||||
|
|
||||||
|
if(result != static_cast<int>(file_info.uncompressed_size))
|
||||||
|
{
|
||||||
|
throw result;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string current_filename(file_name_buffer.begin(), file_name_buffer.begin() + file_info.size_filename);
|
||||||
|
std::string contents(file_buffer.begin(), file_buffer.begin() + file_info.uncompressed_size);
|
||||||
|
|
||||||
|
if(current_filename.back() != '/')
|
||||||
|
{
|
||||||
|
files_[current_filename] = contents;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
directories_.push_back(current_filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
result = unzCloseCurrentFile(unzip_file_);
|
||||||
|
|
||||||
|
if(result != UNZ_OK)
|
||||||
|
{
|
||||||
|
throw result;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = unzGoToNextFile(unzip_file_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void zip_file::write_all()
|
||||||
|
{
|
||||||
|
if(!((int)access_ & (int)file_access::write))
|
||||||
|
{
|
||||||
|
throw std::runtime_error("don't have write access");
|
||||||
|
}
|
||||||
|
|
||||||
|
change_state(state::write, false);
|
||||||
|
|
||||||
|
for(auto file : files_)
|
||||||
|
{
|
||||||
|
write_to_zip(file.first, file.second, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
modified_ = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string zip_file::read_from_zip(const std::string &filename)
|
||||||
|
{
|
||||||
|
if(!((int)access_ & (int)file_access::read))
|
||||||
|
{
|
||||||
|
throw std::runtime_error("don't have read access");
|
||||||
|
}
|
||||||
|
|
||||||
|
change_state(state::read);
|
||||||
|
|
||||||
|
auto result = unzLocateFile(unzip_file_, filename.c_str(), 1);
|
||||||
|
|
||||||
|
if(result != UNZ_OK)
|
||||||
|
{
|
||||||
|
throw result;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = unzOpenCurrentFile(unzip_file_);
|
||||||
|
|
||||||
|
if(result != UNZ_OK)
|
||||||
|
{
|
||||||
|
throw result;
|
||||||
|
}
|
||||||
|
|
||||||
|
unz_file_info file_info;
|
||||||
|
std::array<char, 1000> file_name_buffer;
|
||||||
|
std::array<char, 1000> extra_field_buffer;
|
||||||
|
std::array<char, 1000> comment_buffer;
|
||||||
|
|
||||||
|
unzGetCurrentFileInfo(unzip_file_, &file_info,
|
||||||
|
file_name_buffer.data(), static_cast<uLong>(file_name_buffer.size()),
|
||||||
|
extra_field_buffer.data(), static_cast<uLong>(extra_field_buffer.size()),
|
||||||
|
comment_buffer.data(), static_cast<uLong>(comment_buffer.size()));
|
||||||
|
|
||||||
|
std::vector<char> file_buffer(file_info.uncompressed_size + 1, '\0');
|
||||||
|
result = unzReadCurrentFile(unzip_file_, file_buffer.data(), file_info.uncompressed_size);
|
||||||
|
|
||||||
|
if(result != static_cast<int>(file_info.uncompressed_size))
|
||||||
|
{
|
||||||
|
throw result;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = unzCloseCurrentFile(unzip_file_);
|
||||||
|
|
||||||
|
if(result != UNZ_OK)
|
||||||
|
{
|
||||||
|
throw result;
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::string(file_buffer.begin(), file_buffer.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
void zip_file::write_to_zip(const std::string &filename, const std::string &content, bool append)
|
||||||
|
{
|
||||||
|
if(!((int)access_ & (int)file_access::write))
|
||||||
|
{
|
||||||
|
throw std::runtime_error("don't have write access");
|
||||||
|
}
|
||||||
|
|
||||||
|
change_state(state::write, append);
|
||||||
|
|
||||||
|
zip_fileinfo file_info;
|
||||||
|
|
||||||
|
int result = zipOpenNewFileInZip(zip_file_, filename.c_str(), &file_info, nullptr, 0, nullptr, 0, nullptr, Z_DEFLATED, Z_DEFAULT_COMPRESSION);
|
||||||
|
|
||||||
|
if(result != UNZ_OK)
|
||||||
|
{
|
||||||
|
throw result;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = zipWriteInFileInZip(zip_file_, content.data(), static_cast<int>(content.size()));
|
||||||
|
|
||||||
|
if(result != UNZ_OK)
|
||||||
|
{
|
||||||
|
throw result;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = zipCloseFileInZip(zip_file_);
|
||||||
|
|
||||||
|
if(result != UNZ_OK)
|
||||||
|
{
|
||||||
|
throw result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void zip_file::change_state(state new_state, bool append)
|
||||||
|
{
|
||||||
|
if(new_state == current_state_ && append)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(new_state)
|
||||||
|
{
|
||||||
|
case state::closed:
|
||||||
|
if(current_state_ == state::write)
|
||||||
|
{
|
||||||
|
stop_write();
|
||||||
|
}
|
||||||
|
else if(current_state_ == state::read)
|
||||||
|
{
|
||||||
|
stop_read();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case state::read:
|
||||||
|
if(current_state_ == state::write)
|
||||||
|
{
|
||||||
|
stop_write();
|
||||||
|
}
|
||||||
|
start_read();
|
||||||
|
break;
|
||||||
|
case state::write:
|
||||||
|
if(current_state_ == state::read)
|
||||||
|
{
|
||||||
|
stop_read();
|
||||||
|
}
|
||||||
|
if(current_state_ != state::write)
|
||||||
|
{
|
||||||
|
start_write(append);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw std::runtime_error("bad enum");
|
||||||
|
}
|
||||||
|
|
||||||
|
current_state_ = new_state;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool zip_file::file_exists(const std::string& name)
|
||||||
|
{
|
||||||
|
std::ifstream f(name.c_str());
|
||||||
|
return f.good();
|
||||||
|
}
|
||||||
|
|
||||||
|
void zip_file::start_read()
|
||||||
|
{
|
||||||
|
if(unzip_file_ != nullptr || zip_file_ != nullptr)
|
||||||
|
{
|
||||||
|
throw std::runtime_error("bad state");
|
||||||
|
}
|
||||||
|
|
||||||
|
unzip_file_ = unzOpen(filename_.c_str());
|
||||||
|
|
||||||
|
if(unzip_file_ == nullptr)
|
||||||
|
{
|
||||||
|
throw std::runtime_error("bad or non-existant file");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void zip_file::stop_read()
|
||||||
|
{
|
||||||
|
if(unzip_file_ == nullptr)
|
||||||
|
{
|
||||||
|
throw std::runtime_error("bad state");
|
||||||
|
}
|
||||||
|
|
||||||
|
int result = unzClose(unzip_file_);
|
||||||
|
|
||||||
|
if(result != UNZ_OK)
|
||||||
|
{
|
||||||
|
throw result;
|
||||||
|
}
|
||||||
|
|
||||||
|
unzip_file_ = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void zip_file::start_write(bool append)
|
||||||
|
{
|
||||||
|
if(unzip_file_ != nullptr || zip_file_ != nullptr)
|
||||||
|
{
|
||||||
|
throw std::runtime_error("bad state");
|
||||||
|
}
|
||||||
|
|
||||||
|
int append_status;
|
||||||
|
|
||||||
|
if(append)
|
||||||
|
{
|
||||||
|
if(!file_exists(filename_))
|
||||||
|
{
|
||||||
|
throw std::runtime_error("can't append to non-existent file");
|
||||||
|
}
|
||||||
|
append_status = APPEND_STATUS_ADDINZIP;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
append_status = APPEND_STATUS_CREATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
zip_file_ = zipOpen(filename_.c_str(), append_status);
|
||||||
|
|
||||||
|
if(zip_file_ == nullptr)
|
||||||
|
{
|
||||||
|
if(append)
|
||||||
|
{
|
||||||
|
throw std::runtime_error("couldn't append to zip file");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw std::runtime_error("couldn't create zip file");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void zip_file::stop_write()
|
||||||
|
{
|
||||||
|
if(zip_file_ == nullptr)
|
||||||
|
{
|
||||||
|
throw std::runtime_error("bad state");
|
||||||
|
}
|
||||||
|
|
||||||
|
flush();
|
||||||
|
|
||||||
|
int result = zipClose(zip_file_, nullptr);
|
||||||
|
|
||||||
|
if(result != UNZ_OK)
|
||||||
|
{
|
||||||
|
throw result;
|
||||||
|
}
|
||||||
|
|
||||||
|
zip_file_ = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
109
source/zip_file.h
Normal file
109
source/zip_file.h
Normal file
|
@ -0,0 +1,109 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <zip.h>
|
||||||
|
#include <unzip.h>
|
||||||
|
|
||||||
|
namespace xlnt {
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines constants for read, write, or read/write access to a file.
|
||||||
|
/// </summary>
|
||||||
|
enum class file_access
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Read access to the file. Data can only be read from the file. Combine with write for read/write access.
|
||||||
|
/// </summary>
|
||||||
|
read = 0x01,
|
||||||
|
/// <summary>
|
||||||
|
/// Read and write access to the file. Data can be both written to and read from the file.
|
||||||
|
/// </summary>
|
||||||
|
read_write = 0x03,
|
||||||
|
/// <summary>
|
||||||
|
/// Write access to the file. Data can only be written to the file. Combine with read for read/write access.
|
||||||
|
/// </summary>
|
||||||
|
write = 0x02
|
||||||
|
};
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Specifies how the operating system should open a file.
|
||||||
|
/// </summary>
|
||||||
|
enum class file_mode
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Opens the file if it exists and seeks to the end of the file, or creates a new file.This requires FileIOPermissionAccess.Append permission.file_mode.Append can be used only in conjunction with file_access.Write.Trying to seek to a position before the end of the file throws an IOException exception, and any attempt to read fails and throws a NotSupportedException exception.
|
||||||
|
/// </summary>
|
||||||
|
append,
|
||||||
|
/// <summary>
|
||||||
|
/// Specifies that the operating system should create a new file. If the file already exists, it will be overwritten. This requires FileIOPermissionAccess.Write permission. file_mode.Create is equivalent to requesting that if the file does not exist, use CreateNew; otherwise, use Truncate. If the file already exists but is a hidden file, an UnauthorizedAccessException exception is thrown.
|
||||||
|
/// </summary>
|
||||||
|
create,
|
||||||
|
/// <summary>
|
||||||
|
/// Specifies that the operating system should create a new file. This requires FileIOPermissionAccess.Write permission. If the file already exists, an IOException exception is thrown.
|
||||||
|
/// </summary>
|
||||||
|
create_new,
|
||||||
|
/// <summary>
|
||||||
|
/// Specifies that the operating system should open an existing file. The ability to open the file is dependent on the value specified by the file_access enumeration. A System.IO.FileNotFoundException exception is thrown if the file does not exist.
|
||||||
|
/// </summary>
|
||||||
|
open,
|
||||||
|
/// <summary>
|
||||||
|
/// Specifies that the operating system should open a file if it exists; otherwise, a new file should be created. If the file is opened with file_access.Read, FileIOPermissionAccess.Read permission is required. If the file access is file_access.Write, FileIOPermissionAccess.Write permission is required. If the file is opened with file_access.ReadWrite, both FileIOPermissionAccess.Read and FileIOPermissionAccess.Write permissions are required.
|
||||||
|
/// </summary>
|
||||||
|
open_or_create,
|
||||||
|
/// <summary>
|
||||||
|
/// Specifies that the operating system should open an existing file. When the file is opened, it should be truncated so that its size is zero bytes. This requires FileIOPermissionAccess.Write permission. Attempts to read from a file opened with file_mode.Truncate cause an ArgumentException exception.
|
||||||
|
/// </summary>
|
||||||
|
truncate
|
||||||
|
};
|
||||||
|
|
||||||
|
class zip_file
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
enum class state
|
||||||
|
{
|
||||||
|
read,
|
||||||
|
write,
|
||||||
|
closed
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
zip_file(const std::string &filename, file_mode mode, file_access access = file_access::read);
|
||||||
|
|
||||||
|
~zip_file();
|
||||||
|
|
||||||
|
std::string get_file_contents(const std::string &filename);
|
||||||
|
|
||||||
|
void set_file_contents(const std::string &filename, const std::string &contents);
|
||||||
|
|
||||||
|
void delete_file(const std::string &filename);
|
||||||
|
|
||||||
|
bool has_file(const std::string &filename);
|
||||||
|
|
||||||
|
void flush(bool force_write = false);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void read_all();
|
||||||
|
void write_all();
|
||||||
|
std::string read_from_zip(const std::string &filename);
|
||||||
|
void write_to_zip(const std::string &filename, const std::string &content, bool append = true);
|
||||||
|
void change_state(state new_state, bool append = true);
|
||||||
|
static bool file_exists(const std::string& name);
|
||||||
|
void start_read();
|
||||||
|
void stop_read();
|
||||||
|
void start_write(bool append);
|
||||||
|
void stop_write();
|
||||||
|
|
||||||
|
zipFile zip_file_;
|
||||||
|
unzFile unzip_file_;
|
||||||
|
state current_state_;
|
||||||
|
std::string filename_;
|
||||||
|
std::unordered_map<std::string, std::string> files_;
|
||||||
|
bool modified_;
|
||||||
|
file_access access_;
|
||||||
|
std::vector<std::string> directories_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace xlnt
|
Loading…
Reference in New Issue
Block a user