mirror of
https://github.com/tfussell/xlnt.git
synced 2024-03-22 13:11:17 +08:00
finished minimal styles implementation
This commit is contained in:
parent
21b3d366d6
commit
c802a1f591
|
@ -111,7 +111,9 @@ public:
|
||||||
bool has_hyperlink() const;
|
bool has_hyperlink() const;
|
||||||
|
|
||||||
// style
|
// style
|
||||||
|
bool has_style() const;
|
||||||
std::size_t get_style_id() const;
|
std::size_t get_style_id() const;
|
||||||
|
void set_style_id(std::size_t style_id);
|
||||||
const number_format &get_number_format() const;
|
const number_format &get_number_format() const;
|
||||||
void set_number_format(const number_format &format);
|
void set_number_format(const number_format &format);
|
||||||
const font &get_font() const;
|
const font &get_font() const;
|
||||||
|
|
15
include/xlnt/common/hash_combine.hpp
Normal file
15
include/xlnt/common/hash_combine.hpp
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
namespace xlnt {
|
||||||
|
|
||||||
|
//TODO: Can this be in source->detail, or must it be in a header?
|
||||||
|
template <class T>
|
||||||
|
inline void hash_combine(std::size_t& seed, const T& v)
|
||||||
|
{
|
||||||
|
std::hash<T> hasher;
|
||||||
|
seed ^= hasher(v) + 0x9e3779b9 + (seed<<6) + (seed>>2);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace xlnt
|
|
@ -23,6 +23,7 @@
|
||||||
// @author: see AUTHORS file
|
// @author: see AUTHORS file
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
@ -30,9 +31,15 @@ namespace xlnt {
|
||||||
|
|
||||||
class workbook;
|
class workbook;
|
||||||
|
|
||||||
std::string CentralDirectorySignature();
|
class excel_reader
|
||||||
std::string repair_central_directory(const std::string &original);
|
{
|
||||||
workbook load_workbook(const std::string &filename, bool guess_types = false, bool data_only = false);
|
public:
|
||||||
workbook load_workbook(const std::vector<std::uint8_t> &bytes, bool guess_types = false, bool data_only = false);
|
static std::string CentralDirectorySignature();
|
||||||
|
static std::string repair_central_directory(const std::string &original);
|
||||||
|
|
||||||
|
static workbook load_workbook(std::istream &stream, bool guess_types = false, bool data_only = false);
|
||||||
|
static workbook load_workbook(const std::string &filename, bool guess_types = false, bool data_only = false);
|
||||||
|
static workbook load_workbook(const std::vector<std::uint8_t> &bytes, bool guess_types = false, bool data_only = false);
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace xlnt
|
} // namespace xlnt
|
||||||
|
|
|
@ -28,9 +28,15 @@
|
||||||
|
|
||||||
namespace xlnt {
|
namespace xlnt {
|
||||||
|
|
||||||
std::vector<std::string> read_shared_strings(const std::string &xml_string);
|
class zip_file;
|
||||||
|
|
||||||
|
class shared_strings_reader
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
std::vector<std::string> read_strings(zip_file &archive);
|
||||||
void read_string_table(const std::string &xml_source);
|
void read_string_table(const std::string &xml_source);
|
||||||
std::string get_string();
|
std::string get_string();
|
||||||
std::string get_text();
|
std::string get_text();
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace xlnt
|
} // namespace xlnt
|
||||||
|
|
|
@ -27,21 +27,60 @@
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "style.h"
|
#include "xlnt/workbook/workbook.hpp"
|
||||||
|
|
||||||
|
namespace pugi {
|
||||||
|
class xml_node;
|
||||||
|
} // namespace pugi
|
||||||
|
|
||||||
namespace xlnt {
|
namespace xlnt {
|
||||||
|
|
||||||
void read_styles();
|
class border;
|
||||||
void read_custom_num_formats();
|
class fill;
|
||||||
|
class font;
|
||||||
|
class named_style;
|
||||||
|
class number_format;
|
||||||
|
class style;
|
||||||
|
class zip_file;
|
||||||
|
|
||||||
|
class style_reader
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
style_reader(workbook &wb);
|
||||||
|
|
||||||
|
void read_styles(zip_file &archive);
|
||||||
|
|
||||||
|
const std::vector<style> &get_styles() const { return styles_; }
|
||||||
|
|
||||||
|
const std::vector<border> &get_borders() const { return borders_; }
|
||||||
|
const std::vector<fill> &get_fills() const { return fills_; }
|
||||||
|
const std::vector<font> &get_fonts() const { return fonts_; }
|
||||||
|
const std::vector<number_format> &get_number_formats() const { return number_formats_; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
style read_style(pugi::xml_node stylesheet_node, pugi::xml_node xf_node);
|
||||||
|
|
||||||
|
void read_borders(pugi::xml_node borders_node);
|
||||||
|
void read_fills(pugi::xml_node fills_node);
|
||||||
|
void read_fonts(pugi::xml_node fonts_node);
|
||||||
|
void read_number_formats(pugi::xml_node num_fmt_node);
|
||||||
|
|
||||||
void read_color_index();
|
void read_color_index();
|
||||||
void read_dxfs();
|
void read_dxfs();
|
||||||
void read_fonts();
|
void read_named_styles(pugi::xml_node named_styles_node);
|
||||||
void read_fills();
|
|
||||||
void read_borders();
|
|
||||||
void read_named_styles();
|
|
||||||
void read_style_names();
|
void read_style_names();
|
||||||
void read_cell_styles();
|
void read_cell_styles();
|
||||||
void read_xfs();
|
void read_xfs();
|
||||||
void read_style_table();
|
void read_style_table();
|
||||||
|
|
||||||
|
workbook wb_;
|
||||||
|
|
||||||
|
std::vector<style> styles_;
|
||||||
|
|
||||||
|
std::vector<border> borders_;
|
||||||
|
std::vector<fill> fills_;
|
||||||
|
std::vector<font> fonts_;
|
||||||
|
std::vector<number_format> number_formats_;
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace xlnt
|
} // namespace xlnt
|
||||||
|
|
|
@ -23,19 +23,16 @@
|
||||||
// @author: see AUTHORS file
|
// @author: see AUTHORS file
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <unordered_map>
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace xlnt {
|
namespace xlnt {
|
||||||
|
|
||||||
|
class relationship;
|
||||||
class workbook;
|
class workbook;
|
||||||
class worksheet;
|
class zip_file;
|
||||||
|
|
||||||
worksheet read_worksheet(std::istream &handle, workbook &wb, const std::string &title, const std::vector<std::string> &string_table, const std::unordered_map<int, std::string> &custom_number_formats);
|
void read_worksheet(worksheet ws, zip_file &archive, const relationship &rel, const std::vector<std::string> &shared_strings);
|
||||||
void read_worksheet(worksheet ws, std::istream &stream, const std::vector<std::string> &string_table, const std::vector<int> &number_format_ids, const std::unordered_map<int, std::string> &custom_number_formats);
|
|
||||||
void read_worksheet(worksheet ws, const std::string &xml_string, const std::vector<std::string> &string_table, const std::vector<int> &number_format_ids, const std::unordered_map<int, std::string> &custom_number_formats);
|
|
||||||
std::string read_dimension(const std::string &xml_string);
|
std::string read_dimension(const std::string &xml_string);
|
||||||
|
|
||||||
} // namespace xlnt
|
} // namespace xlnt
|
||||||
|
|
|
@ -23,6 +23,8 @@
|
||||||
// @author: see AUTHORS file
|
// @author: see AUTHORS file
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <xlnt/common/hash_combine.hpp>
|
||||||
|
|
||||||
namespace xlnt {
|
namespace xlnt {
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -33,6 +35,7 @@ class alignment
|
||||||
public:
|
public:
|
||||||
enum class horizontal_alignment
|
enum class horizontal_alignment
|
||||||
{
|
{
|
||||||
|
none,
|
||||||
general,
|
general,
|
||||||
left,
|
left,
|
||||||
right,
|
right,
|
||||||
|
@ -43,27 +46,72 @@ public:
|
||||||
|
|
||||||
enum class vertical_alignment
|
enum class vertical_alignment
|
||||||
{
|
{
|
||||||
|
none,
|
||||||
bottom,
|
bottom,
|
||||||
top,
|
top,
|
||||||
center,
|
center,
|
||||||
justify
|
justify
|
||||||
};
|
};
|
||||||
|
|
||||||
|
bool get_wrap_text() const
|
||||||
|
{
|
||||||
|
return wrap_text_;
|
||||||
|
}
|
||||||
|
|
||||||
void set_wrap_text(bool wrap_text)
|
void set_wrap_text(bool wrap_text)
|
||||||
{
|
{
|
||||||
wrap_text_ = wrap_text;
|
wrap_text_ = wrap_text;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool has_horizontal() const
|
||||||
|
{
|
||||||
|
return horizontal_ != horizontal_alignment::none;
|
||||||
|
}
|
||||||
|
|
||||||
|
horizontal_alignment get_horizontal() const
|
||||||
|
{
|
||||||
|
return horizontal_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_horizontal(horizontal_alignment horizontal)
|
||||||
|
{
|
||||||
|
horizontal_ = horizontal;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool has_vertical() const
|
||||||
|
{
|
||||||
|
return vertical_ != vertical_alignment::none;
|
||||||
|
}
|
||||||
|
|
||||||
|
vertical_alignment get_vertical() const
|
||||||
|
{
|
||||||
|
return vertical_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_vertical(vertical_alignment vertical)
|
||||||
|
{
|
||||||
|
vertical_ = vertical;
|
||||||
|
}
|
||||||
|
|
||||||
bool operator==(const alignment &other) const
|
bool operator==(const alignment &other) const
|
||||||
{
|
{
|
||||||
return hash() == other.hash();
|
return hash() == other.hash();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::size_t hash() const { return 0; }
|
std::size_t hash() const
|
||||||
|
{
|
||||||
|
std::size_t seed = wrap_text_;
|
||||||
|
seed = seed << 1 & shrink_to_fit_;
|
||||||
|
hash_combine(seed, static_cast<std::size_t>(horizontal_));
|
||||||
|
hash_combine(seed, static_cast<std::size_t>(vertical_));
|
||||||
|
hash_combine(seed, text_rotation_);
|
||||||
|
hash_combine(seed, indent_);
|
||||||
|
return seed;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
horizontal_alignment horizontal_ = horizontal_alignment::general;
|
horizontal_alignment horizontal_ = horizontal_alignment::none;
|
||||||
vertical_alignment vertical_ = vertical_alignment::bottom;
|
vertical_alignment vertical_ = vertical_alignment::none;
|
||||||
int text_rotation_ = 0;
|
int text_rotation_ = 0;
|
||||||
bool wrap_text_ = false;
|
bool wrap_text_ = false;
|
||||||
bool shrink_to_fit_ = false;
|
bool shrink_to_fit_ = false;
|
||||||
|
|
|
@ -24,18 +24,13 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
#include "side.hpp"
|
#include "side.hpp"
|
||||||
|
#include "../common/hash_combine.hpp"
|
||||||
|
|
||||||
namespace xlnt {
|
namespace xlnt {
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
struct optional
|
|
||||||
{
|
|
||||||
T value;
|
|
||||||
bool initialized;
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class diagonal_direction
|
enum class diagonal_direction
|
||||||
{
|
{
|
||||||
none,
|
none,
|
||||||
|
@ -49,28 +44,52 @@ class border
|
||||||
public:
|
public:
|
||||||
static border default_border();
|
static border default_border();
|
||||||
|
|
||||||
optional<side> start;
|
bool start_assigned;
|
||||||
optional<side> end;
|
side start;
|
||||||
optional<side> left;
|
bool end_assigned;
|
||||||
optional<side> right;
|
side end;
|
||||||
optional<side> top;
|
bool left_assigned;
|
||||||
optional<side> bottom;
|
side left;
|
||||||
optional<side> diagonal;
|
bool right_assigned;
|
||||||
optional<side> vertical;
|
side right;
|
||||||
optional<side> horizontal;
|
bool top_assigned;
|
||||||
|
side top;
|
||||||
|
bool bottom_assigned;
|
||||||
|
side bottom;
|
||||||
|
bool diagonal_assigned;
|
||||||
|
side diagonal;
|
||||||
|
bool vertical_assigned;
|
||||||
|
side vertical;
|
||||||
|
bool horizontal_assigned;
|
||||||
|
side horizontal;
|
||||||
|
|
||||||
bool outline;
|
bool outline = false;
|
||||||
bool diagonal_up;
|
bool diagonal_up = false;
|
||||||
bool diagonal_down;
|
bool diagonal_down = false;
|
||||||
|
|
||||||
diagonal_direction diagonal_direction_;
|
diagonal_direction diagonal_direction_ = diagonal_direction::none;
|
||||||
|
|
||||||
bool operator==(const border &other) const
|
bool operator==(const border &other) const
|
||||||
{
|
{
|
||||||
return hash() == other.hash();
|
return hash() == other.hash();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::size_t hash() const { return 0; }
|
std::size_t hash() const
|
||||||
|
{
|
||||||
|
std::size_t seed = 0;
|
||||||
|
|
||||||
|
if(start_assigned) hash_combine(seed, start.hash());
|
||||||
|
if(end_assigned) hash_combine(seed, end.hash());
|
||||||
|
if(left_assigned) hash_combine(seed, left.hash());
|
||||||
|
if(right_assigned) hash_combine(seed, right.hash());
|
||||||
|
if(top_assigned) hash_combine(seed, top.hash());
|
||||||
|
if(bottom_assigned) hash_combine(seed, bottom.hash());
|
||||||
|
if(diagonal_assigned) hash_combine(seed, diagonal.hash());
|
||||||
|
if(vertical_assigned) hash_combine(seed, vertical.hash());
|
||||||
|
if(horizontal_assigned) hash_combine(seed, horizontal.hash());
|
||||||
|
|
||||||
|
return seed;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace xlnt
|
} // namespace xlnt
|
||||||
|
|
|
@ -28,6 +28,13 @@ namespace xlnt {
|
||||||
class color
|
class color
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
enum class type
|
||||||
|
{
|
||||||
|
indexed,
|
||||||
|
theme,
|
||||||
|
auto_
|
||||||
|
};
|
||||||
|
|
||||||
static const color black;
|
static const color black;
|
||||||
static const color white;
|
static const color white;
|
||||||
static const color red;
|
static const color red;
|
||||||
|
@ -39,17 +46,74 @@ public:
|
||||||
static const color yellow;
|
static const color yellow;
|
||||||
static const color darkyellow;
|
static const color darkyellow;
|
||||||
|
|
||||||
color(int index) : index_(index)
|
color() {}
|
||||||
|
|
||||||
|
color(type t, std::size_t v) : type_(t), index_(v)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator==(const color &other) const
|
bool operator==(const color &other) const
|
||||||
{
|
{
|
||||||
|
if(type_ != other.type_) return false;
|
||||||
return index_ == other.index_;
|
return index_ == other.index_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void set_auto(int auto_index)
|
||||||
|
{
|
||||||
|
type_ = type::auto_;
|
||||||
|
index_ = auto_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_index(int index)
|
||||||
|
{
|
||||||
|
type_ = type::indexed;
|
||||||
|
index_ = index;
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_theme(int theme)
|
||||||
|
{
|
||||||
|
type_ = type::theme;
|
||||||
|
index_ = theme;
|
||||||
|
}
|
||||||
|
|
||||||
|
type get_type() const
|
||||||
|
{
|
||||||
|
return type_;
|
||||||
|
}
|
||||||
|
|
||||||
|
int get_auto() const
|
||||||
|
{
|
||||||
|
if(type_ != type::auto_)
|
||||||
|
{
|
||||||
|
throw std::runtime_error("not auto color");
|
||||||
|
}
|
||||||
|
|
||||||
|
return index_;
|
||||||
|
}
|
||||||
|
|
||||||
|
int get_index() const
|
||||||
|
{
|
||||||
|
if(type_ != type::indexed)
|
||||||
|
{
|
||||||
|
throw std::runtime_error("not indexed color");
|
||||||
|
}
|
||||||
|
|
||||||
|
return index_;
|
||||||
|
}
|
||||||
|
|
||||||
|
int get_theme() const
|
||||||
|
{
|
||||||
|
if(type_ != type::theme)
|
||||||
|
{
|
||||||
|
throw std::runtime_error("not theme color");
|
||||||
|
}
|
||||||
|
|
||||||
|
return index_;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int index_;
|
type type_ = type::indexed;
|
||||||
|
int index_ = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace xlnt
|
} // namespace xlnt
|
||||||
|
|
|
@ -23,7 +23,8 @@
|
||||||
// @author: see AUTHORS file
|
// @author: see AUTHORS file
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "color.hpp"
|
#include "../common/hash_combine.hpp"
|
||||||
|
#include "../styles/color.hpp"
|
||||||
|
|
||||||
namespace xlnt {
|
namespace xlnt {
|
||||||
|
|
||||||
|
@ -34,38 +35,139 @@ public:
|
||||||
{
|
{
|
||||||
none,
|
none,
|
||||||
solid,
|
solid,
|
||||||
gradient_linear,
|
gradient,
|
||||||
gradient_path,
|
pattern
|
||||||
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;
|
enum class gradient_type
|
||||||
int rotation = 0;
|
{
|
||||||
color start_color = color::white;
|
linear,
|
||||||
color end_color = color::black;
|
path
|
||||||
|
};
|
||||||
|
|
||||||
virtual bool operator==(const fill &other) const
|
enum class pattern_type
|
||||||
|
{
|
||||||
|
none,
|
||||||
|
solid,
|
||||||
|
darkdown,
|
||||||
|
darkgray,
|
||||||
|
darkgrid,
|
||||||
|
darkhorizontal,
|
||||||
|
darktrellis,
|
||||||
|
darkup,
|
||||||
|
darkvertical,
|
||||||
|
gray0625,
|
||||||
|
gray125,
|
||||||
|
lightdown,
|
||||||
|
lightgray,
|
||||||
|
lightgrid,
|
||||||
|
lighthorizontal,
|
||||||
|
lighttrellis,
|
||||||
|
lightup,
|
||||||
|
lightvertical,
|
||||||
|
mediumgray,
|
||||||
|
};
|
||||||
|
|
||||||
|
type get_type() const { return type_; }
|
||||||
|
void set_type(type t) { type_ = t; }
|
||||||
|
std::string get_pattern_type_string() const
|
||||||
|
{
|
||||||
|
if(type_ != type::pattern)
|
||||||
|
{
|
||||||
|
throw std::runtime_error("not pattern fill");
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(pattern_type_)
|
||||||
|
{
|
||||||
|
case pattern_type::none: return "none";
|
||||||
|
case pattern_type::solid: return "solid";
|
||||||
|
case pattern_type::darkdown: return "darkdown";
|
||||||
|
case pattern_type::darkgray: return "darkgray";
|
||||||
|
case pattern_type::darkgrid: return "darkgrid";
|
||||||
|
case pattern_type::darkhorizontal: return "darkhorizontal";
|
||||||
|
case pattern_type::darktrellis: return "darktrellis";
|
||||||
|
case pattern_type::darkup: return "darkup";
|
||||||
|
case pattern_type::darkvertical: return "darkvertical";
|
||||||
|
case pattern_type::gray0625: return "gray0625";
|
||||||
|
case pattern_type::gray125: return "gray125";
|
||||||
|
case pattern_type::lightdown: return "lightdown";
|
||||||
|
case pattern_type::lightgray: return "lightgray";
|
||||||
|
case pattern_type::lightgrid: return "lightgrid";
|
||||||
|
case pattern_type::lighthorizontal: return "lighthorizontal";
|
||||||
|
case pattern_type::lighttrellis: return "lighttrellis";
|
||||||
|
case pattern_type::lightup: return "lightup";
|
||||||
|
case pattern_type::lightvertical: return "lightvertical";
|
||||||
|
case pattern_type::mediumgray: return "mediumgray";
|
||||||
|
default: throw std::runtime_error("invalid type");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pattern_type get_pattern_type() const
|
||||||
|
{
|
||||||
|
return pattern_type_;
|
||||||
|
}
|
||||||
|
void set_pattern_type(pattern_type t) { pattern_type_ = t; }
|
||||||
|
void set_gradient_type(gradient_type t) { gradient_type_ = t; }
|
||||||
|
|
||||||
|
void set_foreground_color(const color &c)
|
||||||
|
{
|
||||||
|
foreground_color_ = c;
|
||||||
|
foreground_color_assigned_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_background_color(const color &c)
|
||||||
|
{
|
||||||
|
background_color_ = c;
|
||||||
|
background_color_assigned_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
color get_foreground_color() const
|
||||||
|
{
|
||||||
|
return foreground_color_;
|
||||||
|
}
|
||||||
|
|
||||||
|
color get_background_color() const
|
||||||
|
{
|
||||||
|
return background_color_;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool has_foreground_color() const
|
||||||
|
{
|
||||||
|
return foreground_color_assigned_;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool has_background_color() const
|
||||||
|
{
|
||||||
|
return background_color_assigned_;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(const fill &other) const
|
||||||
{
|
{
|
||||||
return hash() == other.hash();
|
return hash() == other.hash();
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual std::size_t hash() const { return 0; }
|
std::size_t hash() const
|
||||||
|
{
|
||||||
|
auto seed = static_cast<std::size_t>(type_);
|
||||||
|
|
||||||
|
if(type_ == type::pattern)
|
||||||
|
{
|
||||||
|
hash_combine(seed, static_cast<std::size_t>(pattern_type_));
|
||||||
|
}
|
||||||
|
|
||||||
|
return seed;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
type type_ = type::none;
|
||||||
|
pattern_type pattern_type_;
|
||||||
|
gradient_type gradient_type_;
|
||||||
|
int rotation_ = 0;
|
||||||
|
bool foreground_color_assigned_ = false;
|
||||||
|
color foreground_color_ = color::black;
|
||||||
|
bool background_color_assigned_ = false;
|
||||||
|
color background_color_ = color::white;
|
||||||
|
color start_color_ = color::white;
|
||||||
|
color end_color_ = color::black;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace xlnt
|
} // namespace xlnt
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
#include <xlnt/common/hash_combine.hpp>
|
||||||
#include <xlnt/styles/color.hpp>
|
#include <xlnt/styles/color.hpp>
|
||||||
|
|
||||||
namespace xlnt {
|
namespace xlnt {
|
||||||
|
@ -44,18 +45,51 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
void set_bold(bool bold) { bold_ = bold; }
|
void set_bold(bool bold) { bold_ = bold; }
|
||||||
|
bool is_bold() const { return bold_; }
|
||||||
|
|
||||||
|
void set_size(int size) { size_ = size; }
|
||||||
|
int get_size() const { return size_; }
|
||||||
|
|
||||||
|
void set_name(const std::string &name) { name_ = name; }
|
||||||
|
std::string get_name() const { return name_; }
|
||||||
|
|
||||||
|
void set_color(color c) { color_ = c; }
|
||||||
|
void set_family(int family) { has_family_ = true; family_ = family; }
|
||||||
|
void set_scheme(const std::string &scheme) { has_scheme_ = true; scheme_ = scheme; }
|
||||||
|
|
||||||
|
color get_color() const { return color_; }
|
||||||
|
|
||||||
|
bool has_family() const { return has_family_; }
|
||||||
|
bool has_scheme() const { return has_scheme_; }
|
||||||
|
|
||||||
|
std::size_t hash() const
|
||||||
|
{
|
||||||
|
std::size_t seed = bold_;
|
||||||
|
seed = seed << 1 & italic_;
|
||||||
|
seed = seed << 1 & superscript_;
|
||||||
|
seed = seed << 1 & subscript_;
|
||||||
|
seed = seed << 1 & strikethrough_;
|
||||||
|
hash_combine(seed, name_);
|
||||||
|
hash_combine(seed, size_);
|
||||||
|
hash_combine(seed, static_cast<std::size_t>(underline_));
|
||||||
|
hash_combine(seed, static_cast<std::size_t>(color_.get_type()));
|
||||||
|
switch(color_.get_type())
|
||||||
|
{
|
||||||
|
case color::type::indexed: hash_combine(seed, color_.get_index()); break;
|
||||||
|
case color::type::theme: hash_combine(seed, color_.get_theme()); break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
hash_combine(seed, family_);
|
||||||
|
hash_combine(seed, scheme_);
|
||||||
|
|
||||||
|
return seed;
|
||||||
|
}
|
||||||
|
|
||||||
bool operator==(const font &other) const
|
bool operator==(const font &other) const
|
||||||
{
|
{
|
||||||
return hash() == other.hash();
|
return hash() == other.hash();
|
||||||
}
|
}
|
||||||
|
|
||||||
int get_size() const { return size_; }
|
|
||||||
std::string get_name() const { return name_; }
|
|
||||||
bool is_bold() const { return bold_; }
|
|
||||||
|
|
||||||
std::size_t hash() const { return 0; }
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class style;
|
friend class style;
|
||||||
|
|
||||||
|
@ -67,7 +101,11 @@ private:
|
||||||
bool subscript_ = false;
|
bool subscript_ = false;
|
||||||
underline underline_ = underline::none;
|
underline underline_ = underline::none;
|
||||||
bool strikethrough_ = false;
|
bool strikethrough_ = false;
|
||||||
color color_ = color::black;
|
color color_;
|
||||||
|
bool has_family_ = false;
|
||||||
|
int family_;
|
||||||
|
bool has_scheme_ = false;
|
||||||
|
std::string scheme_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace xlnt
|
} // namespace xlnt
|
||||||
|
|
|
@ -1,39 +0,0 @@
|
||||||
// Copyright (c) 2015 Thomas Fussell
|
|
||||||
// Copyright (c) 2010-2015 openpyxl
|
|
||||||
//
|
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
// of this software and associated documentation files (the "Software"), to deal
|
|
||||||
// in the Software without restriction, including without limitation the rights
|
|
||||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
// copies of the Software, and to permit persons to whom the Software is
|
|
||||||
// furnished to do so, subject to the following conditions:
|
|
||||||
//
|
|
||||||
// The above copyright notice and this permission notice shall be included in
|
|
||||||
// all copies or substantial portions of the Software.
|
|
||||||
//
|
|
||||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, WRISING FROM,
|
|
||||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
// THE SOFTWARE
|
|
||||||
//
|
|
||||||
// @license: http://www.opensource.org/licenses/mit-license.php
|
|
||||||
// @author: see AUTHORS file
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "fill.hpp"
|
|
||||||
|
|
||||||
namespace xlnt {
|
|
||||||
|
|
||||||
class gradient_fill : public fill
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
std::size_t hash() const override { return 0; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace xlnt
|
|
|
@ -23,68 +23,25 @@
|
||||||
// @author: see AUTHORS file
|
// @author: see AUTHORS file
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "alignment.hpp"
|
#include "style.hpp"
|
||||||
#include "borders.hpp"
|
|
||||||
#include "fill.hpp"
|
|
||||||
#include "font.hpp"
|
|
||||||
#include "number_format.hpp"
|
|
||||||
#include "protection.hpp"
|
|
||||||
|
|
||||||
namespace xlnt {
|
namespace xlnt {
|
||||||
|
|
||||||
class workbook;
|
class named_style
|
||||||
|
|
||||||
class style
|
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
style();
|
named_style();
|
||||||
|
|
||||||
std::size_t hash() const;
|
std::size_t hash() const;
|
||||||
|
|
||||||
const alignment get_alignment() const;
|
bool operator==(const named_style &other) const
|
||||||
const border get_border() const;
|
|
||||||
const fill get_fill() const;
|
|
||||||
const font get_font() const;
|
|
||||||
const number_format get_number_format() const;
|
|
||||||
const protection get_protection() const;
|
|
||||||
bool pivot_button() const;
|
|
||||||
bool quote_prefix() const;
|
|
||||||
|
|
||||||
std::size_t get_fill_index() const { return fill_index_; }
|
|
||||||
std::size_t get_font_index() const { return font_index_; }
|
|
||||||
std::size_t get_border_index() const { return border_index_; }
|
|
||||||
std::size_t get_number_format_index() const { return number_format_index_; }
|
|
||||||
|
|
||||||
bool operator==(const style &other) const
|
|
||||||
{
|
{
|
||||||
return hash() == other.hash();
|
return style_.hash() == other.style_.hash();
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class workbook;
|
std::string name_;
|
||||||
|
style style_;
|
||||||
std::size_t style_index_;
|
|
||||||
|
|
||||||
std::size_t alignment_index_;
|
|
||||||
alignment alignment_;
|
|
||||||
|
|
||||||
std::size_t border_index_;
|
|
||||||
border border_;
|
|
||||||
|
|
||||||
std::size_t fill_index_;
|
|
||||||
fill fill_;
|
|
||||||
|
|
||||||
std::size_t font_index_;
|
|
||||||
font font_;
|
|
||||||
|
|
||||||
std::size_t number_format_index_;
|
|
||||||
number_format number_format_;
|
|
||||||
|
|
||||||
std::size_t protection_index_;
|
|
||||||
protection protection_;
|
|
||||||
|
|
||||||
bool pivot_button_;
|
|
||||||
bool quote_prefix_;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace xlnt
|
} // namespace xlnt
|
||||||
|
|
|
@ -32,80 +32,52 @@ namespace xlnt {
|
||||||
class number_format
|
class number_format
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
enum class format
|
static const number_format general();
|
||||||
{
|
static const number_format text();
|
||||||
general,
|
static const number_format number();
|
||||||
text,
|
static const number_format number_00();
|
||||||
number,
|
static const number_format number_comma_separated1();
|
||||||
number_00,
|
static const number_format number_comma_separated2();
|
||||||
number_comma_separated1,
|
static const number_format percentage();
|
||||||
number_comma_separated2,
|
static const number_format percentage_00();
|
||||||
percentage,
|
static const number_format date_yyyymmdd2();
|
||||||
percentage_00,
|
static const number_format date_yyyymmdd();
|
||||||
date_yyyymmdd2,
|
static const number_format date_ddmmyyyy();
|
||||||
date_yyyymmdd,
|
static const number_format date_dmyslash();
|
||||||
date_ddmmyyyy,
|
static const number_format date_dmyminus();
|
||||||
date_dmyslash,
|
static const number_format date_dmminus();
|
||||||
date_dmyminus,
|
static const number_format date_myminus();
|
||||||
date_dmminus,
|
static const number_format date_xlsx14();
|
||||||
date_myminus,
|
static const number_format date_xlsx15();
|
||||||
date_xlsx14,
|
static const number_format date_xlsx16();
|
||||||
date_xlsx15,
|
static const number_format date_xlsx17();
|
||||||
date_xlsx16,
|
static const number_format date_xlsx22();
|
||||||
date_xlsx17,
|
static const number_format date_datetime();
|
||||||
date_xlsx22,
|
static const number_format date_time1();
|
||||||
date_datetime,
|
static const number_format date_time2();
|
||||||
date_time1,
|
static const number_format date_time3();
|
||||||
date_time2,
|
static const number_format date_time4();
|
||||||
date_time3,
|
static const number_format date_time5();
|
||||||
date_time4,
|
static const number_format date_time6();
|
||||||
date_time5,
|
static const number_format date_time7();
|
||||||
date_time6,
|
static const number_format date_time8();
|
||||||
date_time7,
|
static const number_format date_timedelta();
|
||||||
date_time8,
|
static const number_format date_yyyymmddslash();
|
||||||
date_timedelta,
|
static const number_format currency_usd_simple();
|
||||||
date_yyyymmddslash,
|
static const number_format currency_usd();
|
||||||
currency_usd_simple,
|
static const number_format currency_eur_simple();
|
||||||
currency_usd,
|
|
||||||
currency_eur_simple,
|
|
||||||
unknown
|
|
||||||
};
|
|
||||||
|
|
||||||
struct format_hash
|
static number_format from_builtin_id(int builtin_id);
|
||||||
{
|
|
||||||
std::size_t operator()(format f) const
|
|
||||||
{
|
|
||||||
return std::hash<int>()((int)f);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
static const std::unordered_map<format, std::string, format_hash> &format_strings();
|
|
||||||
static const std::unordered_map<int, std::string> &builtin_formats();
|
|
||||||
static const std::unordered_map<std::string, int> &reversed_builtin_formats();
|
|
||||||
|
|
||||||
static std::string builtin_format_code(int index);
|
|
||||||
static format lookup_format(int code);
|
|
||||||
|
|
||||||
static bool is_builtin(const std::string &format);
|
|
||||||
|
|
||||||
static const number_format &default_number_format()
|
|
||||||
{
|
|
||||||
static number_format default_;
|
|
||||||
return default_;
|
|
||||||
}
|
|
||||||
|
|
||||||
number_format();
|
number_format();
|
||||||
number_format(format code);
|
number_format(int builtin_id);
|
||||||
number_format(const std::string &code);
|
number_format(const std::string &code, int custom_id = -1);
|
||||||
|
|
||||||
format get_format_code() const;
|
void set_format_string(const std::string &format_code, int id = -1);
|
||||||
|
|
||||||
void set_format_code(format format_code);
|
|
||||||
|
|
||||||
void set_format_string(const std::string &format_code);
|
|
||||||
std::string get_format_string() const;
|
std::string get_format_string() const;
|
||||||
|
|
||||||
int get_format_index() const { return format_index_; }
|
void set_id(int id) { id_ = id; }
|
||||||
|
int get_id() const { return id_; }
|
||||||
|
|
||||||
std::size_t hash() const;
|
std::size_t hash() const;
|
||||||
|
|
||||||
|
@ -115,8 +87,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
format format_code_;
|
int id_;
|
||||||
int format_index_;
|
|
||||||
std::string format_string_;
|
std::string format_string_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,43 +0,0 @@
|
||||||
// Copyright (c) 2015 Thomas Fussell
|
|
||||||
// Copyright (c) 2010-2015 openpyxl
|
|
||||||
//
|
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
// of this software and associated documentation files (the "Software"), to deal
|
|
||||||
// in the Software without restriction, including without limitation the rights
|
|
||||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
// copies of the Software, and to permit persons to whom the Software is
|
|
||||||
// furnished to do so, subject to the following conditions:
|
|
||||||
//
|
|
||||||
// The above copyright notice and this permission notice shall be included in
|
|
||||||
// all copies or substantial portions of the Software.
|
|
||||||
//
|
|
||||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, WRISING FROM,
|
|
||||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
// THE SOFTWARE
|
|
||||||
//
|
|
||||||
// @license: http://www.opensource.org/licenses/mit-license.php
|
|
||||||
// @author: see AUTHORS file
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "color.hpp"
|
|
||||||
|
|
||||||
namespace xlnt {
|
|
||||||
|
|
||||||
class pattern_fill : public fill
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
void set_pattern_type(const std::string &type) { type_ = type; }
|
|
||||||
void set_foreground_color(const std::string &hex) { foreground_color_ = hex; }
|
|
||||||
|
|
||||||
std::size_t hash() const override { return 0; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::string type_;
|
|
||||||
std::string foreground_color_;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace xlnt
|
|
|
@ -25,6 +25,8 @@
|
||||||
|
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
|
|
||||||
|
#include <xlnt/common/hash_combine.hpp>
|
||||||
|
|
||||||
namespace xlnt {
|
namespace xlnt {
|
||||||
|
|
||||||
class protection
|
class protection
|
||||||
|
@ -40,9 +42,14 @@ public:
|
||||||
protection();
|
protection();
|
||||||
protection(type locked);
|
protection(type locked);
|
||||||
|
|
||||||
void set_locked(bool locked)
|
void set_locked(type locked_type)
|
||||||
{
|
{
|
||||||
locked_ = locked ? type::protected_ : type::unprotected;
|
locked_ = locked_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_hidden(type hidden_type)
|
||||||
|
{
|
||||||
|
hidden_ = hidden_type;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator==(const protection &other) const
|
bool operator==(const protection &other) const
|
||||||
|
@ -50,7 +57,13 @@ public:
|
||||||
return hash() == other.hash();
|
return hash() == other.hash();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::size_t hash() const { return 0; }
|
std::size_t hash() const
|
||||||
|
{
|
||||||
|
std::size_t seed = static_cast<std::size_t>(locked_);
|
||||||
|
hash_combine(seed, static_cast<std::size_t>(hidden_));
|
||||||
|
|
||||||
|
return seed;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
type locked_;
|
type locked_;
|
||||||
|
|
|
@ -25,7 +25,7 @@
|
||||||
|
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
|
|
||||||
#include <xlnt/styles/color.hpp>
|
#include "../common/hash_combine.hpp"
|
||||||
|
|
||||||
namespace xlnt {
|
namespace xlnt {
|
||||||
|
|
||||||
|
@ -50,16 +50,81 @@ enum class border_style
|
||||||
class side
|
class side
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
side(border_style style = border_style::none, color = color::black);
|
enum class color_type
|
||||||
|
{
|
||||||
|
theme,
|
||||||
|
indexed
|
||||||
|
};
|
||||||
|
|
||||||
|
side();
|
||||||
|
|
||||||
|
std::size_t hash() const
|
||||||
|
{
|
||||||
|
std::size_t seed = 0;
|
||||||
|
|
||||||
|
if(style_assigned_)
|
||||||
|
{
|
||||||
|
hash_combine(seed, static_cast<std::size_t>(style_));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(color_assigned_)
|
||||||
|
{
|
||||||
|
hash_combine(seed, static_cast<std::size_t>(color_type_));
|
||||||
|
hash_combine(seed, color_);
|
||||||
|
}
|
||||||
|
|
||||||
|
return seed;
|
||||||
|
}
|
||||||
|
|
||||||
|
border_style get_style() const
|
||||||
|
{
|
||||||
|
return style_;
|
||||||
|
}
|
||||||
|
|
||||||
|
color_type get_color_type() const
|
||||||
|
{
|
||||||
|
return color_type_;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t get_color() const
|
||||||
|
{
|
||||||
|
return color_;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_style_assigned() const
|
||||||
|
{
|
||||||
|
return style_assigned_;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_color_assigned() const
|
||||||
|
{
|
||||||
|
return color_assigned_;
|
||||||
|
}
|
||||||
|
|
||||||
bool operator==(const side &other) const
|
bool operator==(const side &other) const
|
||||||
{
|
{
|
||||||
return other.style_ == style_;
|
return other.style_ == style_ && color_type_ == other.color_type_ && color_ == other.color_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_border_style(border_style bs)
|
||||||
|
{
|
||||||
|
style_assigned_ = true;
|
||||||
|
style_ = bs;
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_color(color_type type, std::size_t color)
|
||||||
|
{
|
||||||
|
color_assigned_ = true;
|
||||||
|
color_type_ = type;
|
||||||
|
color_ = color;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
border_style style_;
|
bool style_assigned_ = false;
|
||||||
color color_;
|
border_style style_ = border_style::none;
|
||||||
|
bool color_assigned_ = false;
|
||||||
|
color_type color_type_ = color_type::indexed;
|
||||||
|
std::size_t color_ = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace xlnt
|
} // namespace xlnt
|
||||||
|
|
|
@ -38,6 +38,8 @@ class style
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
style();
|
style();
|
||||||
|
style(const style &other);
|
||||||
|
style &operator=(const style &other);
|
||||||
|
|
||||||
std::size_t hash() const;
|
std::size_t hash() const;
|
||||||
|
|
||||||
|
@ -50,10 +52,19 @@ public:
|
||||||
bool pivot_button() const;
|
bool pivot_button() const;
|
||||||
bool quote_prefix() const;
|
bool quote_prefix() const;
|
||||||
|
|
||||||
std::size_t get_fill_index() const { return fill_index_; }
|
std::size_t get_id() const { return id_; }
|
||||||
std::size_t get_font_index() const { return font_index_; }
|
|
||||||
std::size_t get_border_index() const { return border_index_; }
|
std::size_t get_fill_id() const { return fill_id_; }
|
||||||
std::size_t get_number_format_index() const { return number_format_index_; }
|
std::size_t get_font_id() const { return font_id_; }
|
||||||
|
std::size_t get_border_id() const { return border_id_; }
|
||||||
|
std::size_t get_number_format_id() const { return number_format_id_; }
|
||||||
|
|
||||||
|
void apply_alignment(bool apply) { alignment_apply_ = apply; }
|
||||||
|
void apply_border(bool apply) { border_apply_ = apply; }
|
||||||
|
void apply_fill(bool apply) { fill_apply_ = apply; }
|
||||||
|
void apply_font(bool apply) { font_apply_ = apply; }
|
||||||
|
void apply_number_format(bool apply) { number_format_apply_ = apply; }
|
||||||
|
void apply_protection(bool apply) { protection_apply_ = apply; }
|
||||||
|
|
||||||
bool operator==(const style &other) const
|
bool operator==(const style &other) const
|
||||||
{
|
{
|
||||||
|
@ -61,26 +72,32 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
friend class style_reader;
|
||||||
|
friend class style_writer;
|
||||||
friend class workbook;
|
friend class workbook;
|
||||||
|
|
||||||
std::size_t style_index_;
|
std::size_t id_;
|
||||||
|
|
||||||
std::size_t alignment_index_;
|
bool alignment_apply_;
|
||||||
alignment alignment_;
|
alignment alignment_;
|
||||||
|
|
||||||
std::size_t border_index_;
|
bool border_apply_;
|
||||||
|
std::size_t border_id_;
|
||||||
border border_;
|
border border_;
|
||||||
|
|
||||||
std::size_t fill_index_;
|
bool fill_apply_;
|
||||||
|
std::size_t fill_id_;
|
||||||
fill fill_;
|
fill fill_;
|
||||||
|
|
||||||
std::size_t font_index_;
|
bool font_apply_;
|
||||||
|
std::size_t font_id_;
|
||||||
font font_;
|
font font_;
|
||||||
|
|
||||||
std::size_t number_format_index_;
|
bool number_format_apply_;
|
||||||
|
std::size_t number_format_id_;
|
||||||
number_format number_format_;
|
number_format number_format_;
|
||||||
|
|
||||||
std::size_t protection_index_;
|
bool protection_apply_;
|
||||||
protection protection_;
|
protection protection_;
|
||||||
|
|
||||||
bool pivot_button_;
|
bool pivot_button_;
|
||||||
|
|
|
@ -177,7 +177,7 @@ public:
|
||||||
bool save(const std::string &filename);
|
bool save(const std::string &filename);
|
||||||
bool load(const std::vector<unsigned char> &data);
|
bool load(const std::vector<unsigned char> &data);
|
||||||
bool load(const std::string &filename);
|
bool load(const std::string &filename);
|
||||||
bool load(const std::istream &stream);
|
bool load(std::istream &stream);
|
||||||
bool load(zip_file &archive);
|
bool load(zip_file &archive);
|
||||||
|
|
||||||
bool operator==(const workbook &rhs) const;
|
bool operator==(const workbook &rhs) const;
|
||||||
|
@ -200,22 +200,20 @@ public:
|
||||||
relationship get_relationship(const std::string &id) const;
|
relationship get_relationship(const std::string &id) const;
|
||||||
std::vector<relationship> get_relationships() const;
|
std::vector<relationship> get_relationships() const;
|
||||||
|
|
||||||
void add_alignment(alignment a);
|
void add_alignment(const alignment &a);
|
||||||
void add_border(border b);
|
void add_border(const border &b);
|
||||||
void add_fill(fill &f);
|
void add_fill(const fill &f);
|
||||||
void add_font(font f);
|
void add_font(const font &f);
|
||||||
void add_protection(protection p);
|
void add_color(const color &c);
|
||||||
void add_color(color c);
|
void add_number_format(const number_format &format);
|
||||||
void add_number_format(const std::string &format);
|
void add_protection(const protection &p);
|
||||||
|
|
||||||
std::vector<style> get_styles() const;
|
std::vector<style> get_styles() const;
|
||||||
|
|
||||||
std::vector<alignment> get_alignments() const;
|
|
||||||
std::vector<border> get_borders() const;
|
std::vector<border> get_borders() const;
|
||||||
std::vector<fill> get_fills() const;
|
std::vector<fill> get_fills() const;
|
||||||
std::vector<font> get_fonts() const;
|
std::vector<font> get_fonts() const;
|
||||||
std::vector<number_format> get_number_formats() const;
|
std::vector<number_format> get_number_formats() const;
|
||||||
std::vector<protection> get_protections() const;
|
|
||||||
|
|
||||||
const number_format &get_number_format(std::size_t style_id) const;
|
const number_format &get_number_format(std::size_t style_id) const;
|
||||||
std::size_t set_number_format(const number_format &format, std::size_t style_id);
|
std::size_t set_number_format(const number_format &format, std::size_t style_id);
|
||||||
|
@ -237,8 +235,8 @@ public:
|
||||||
bool has_loaded_theme();
|
bool has_loaded_theme();
|
||||||
std::string get_loaded_theme();
|
std::string get_loaded_theme();
|
||||||
|
|
||||||
style get_style(std::size_t style_id);
|
const style &get_style(std::size_t style_id) const;
|
||||||
std::size_t add_style(style style_);
|
std::size_t add_style(const style &style_);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class worksheet;
|
friend class worksheet;
|
||||||
|
|
|
@ -23,11 +23,34 @@
|
||||||
// @author: see AUTHORS file
|
// @author: see AUTHORS file
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
namespace xlnt {
|
namespace xlnt {
|
||||||
|
|
||||||
|
class workbook;
|
||||||
|
class zip_file;
|
||||||
|
|
||||||
class excel_writer
|
class excel_writer
|
||||||
{
|
{
|
||||||
|
public:
|
||||||
|
excel_writer(workbook &wb);
|
||||||
|
|
||||||
|
void save(const std::string &filename, bool as_template);
|
||||||
|
|
||||||
|
void write_data(zip_file &archive, bool as_template);
|
||||||
|
void write_shared_strings(zip_file &archive, const std::vector<std::string> &shared_strings);
|
||||||
|
void write_images(zip_file &archive);
|
||||||
|
void write_charts(zip_file &archive);
|
||||||
|
void write_chartsheets(zip_file &archive);
|
||||||
|
void write_worksheets(zip_file &archive, const std::vector<std::string> &shared_strings);
|
||||||
|
void write_external_links(zip_file &archive);
|
||||||
|
|
||||||
|
private:
|
||||||
|
workbook wb_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
bool save_workbook(workbook &wb, const std::string &filename, bool as_template = false);
|
||||||
|
std::vector<std::uint8_t> save_virtual_workbook(xlnt::workbook &wb, bool as_template = false);
|
||||||
|
|
||||||
} // namespace xlnt
|
} // namespace xlnt
|
||||||
|
|
|
@ -30,29 +30,6 @@
|
||||||
|
|
||||||
namespace xlnt {
|
namespace xlnt {
|
||||||
|
|
||||||
class workbook;
|
|
||||||
class zip_file;
|
|
||||||
|
|
||||||
class excel_writer
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
excel_writer(workbook &wb);
|
|
||||||
|
|
||||||
void save(const std::string &filename, bool as_template);
|
|
||||||
void write_data(zip_file &archive, bool as_template);
|
|
||||||
void write_string_table(zip_file &archive);
|
|
||||||
void write_images(zip_file &archive);
|
|
||||||
void write_charts(zip_file &archive);
|
|
||||||
void write_chartsheets(zip_file &archive);
|
|
||||||
void write_worksheets(zip_file &archive);
|
|
||||||
void write_external_links(zip_file &archive);
|
|
||||||
|
|
||||||
private:
|
|
||||||
workbook wb_;
|
|
||||||
style_writer style_writer_;
|
|
||||||
std::vector<std::string> shared_strings_;
|
|
||||||
};
|
|
||||||
|
|
||||||
std::string write_shared_strings(const std::vector<std::string> &string_table);
|
std::string write_shared_strings(const std::vector<std::string> &string_table);
|
||||||
std::string write_properties_core(const document_properties &prop);
|
std::string write_properties_core(const document_properties &prop);
|
||||||
std::string write_worksheet_rels(worksheet ws);
|
std::string write_worksheet_rels(worksheet ws);
|
||||||
|
@ -63,7 +40,4 @@ std::string write_workbook(const workbook &wb);
|
||||||
std::string write_workbook_rels(const workbook &wb);
|
std::string write_workbook_rels(const workbook &wb);
|
||||||
std::string write_defined_names(const xlnt::workbook &wb);
|
std::string write_defined_names(const xlnt::workbook &wb);
|
||||||
|
|
||||||
bool save_workbook(workbook &wb, const std::string &filename, bool as_template = false);
|
|
||||||
std::vector<std::uint8_t> save_virtual_workbook(xlnt::workbook &wb, bool as_template = false);
|
|
||||||
|
|
||||||
} // namespace xlnt
|
} // namespace xlnt
|
||||||
|
|
|
@ -558,9 +558,6 @@ std::string format_text(const std::string &text, const std::string &format)
|
||||||
|
|
||||||
namespace xlnt {
|
namespace xlnt {
|
||||||
|
|
||||||
const xlnt::color xlnt::color::black(0);
|
|
||||||
const xlnt::color xlnt::color::white(1);
|
|
||||||
|
|
||||||
const std::unordered_map<std::string, int> cell::ErrorCodes =
|
const std::unordered_map<std::string, int> cell::ErrorCodes =
|
||||||
{
|
{
|
||||||
{"#NULL!", 0},
|
{"#NULL!", 0},
|
||||||
|
@ -594,7 +591,7 @@ cell::cell(worksheet worksheet, const cell_reference &reference, const T &initia
|
||||||
|
|
||||||
bool cell::garbage_collectible() const
|
bool cell::garbage_collectible() const
|
||||||
{
|
{
|
||||||
return !(get_data_type() != type::null || is_merged() || has_comment() || has_formula());
|
return !(get_data_type() != type::null || is_merged() || has_comment() || has_formula() || has_style());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -737,7 +734,7 @@ void cell::set_value(date d)
|
||||||
{
|
{
|
||||||
d_->type_ = type::numeric;
|
d_->type_ = type::numeric;
|
||||||
d_->value_numeric_ = d.to_number(get_base_date());
|
d_->value_numeric_ = d.to_number(get_base_date());
|
||||||
set_number_format(number_format(number_format::format::date_yyyymmdd2));
|
set_number_format(number_format::date_yyyymmdd2());
|
||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
|
@ -745,7 +742,7 @@ void cell::set_value(datetime d)
|
||||||
{
|
{
|
||||||
d_->type_ = type::numeric;
|
d_->type_ = type::numeric;
|
||||||
d_->value_numeric_ = d.to_number(get_base_date());
|
d_->value_numeric_ = d.to_number(get_base_date());
|
||||||
set_number_format(number_format(number_format::format::date_datetime));
|
set_number_format(number_format::date_datetime());
|
||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
|
@ -753,7 +750,7 @@ void cell::set_value(time t)
|
||||||
{
|
{
|
||||||
d_->type_ = type::numeric;
|
d_->type_ = type::numeric;
|
||||||
d_->value_numeric_ = t.to_number();
|
d_->value_numeric_ = t.to_number();
|
||||||
set_number_format(number_format(number_format::format::date_time6));
|
set_number_format(number_format::date_time6());
|
||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
|
@ -761,7 +758,7 @@ void cell::set_value(timedelta t)
|
||||||
{
|
{
|
||||||
d_->type_ = type::numeric;
|
d_->type_ = type::numeric;
|
||||||
d_->value_numeric_ = t.to_number();
|
d_->value_numeric_ = t.to_number();
|
||||||
set_number_format(number_format(number_format::format::date_timedelta));
|
set_number_format(number_format::date_timedelta());
|
||||||
}
|
}
|
||||||
|
|
||||||
row_t cell::get_row() const
|
row_t cell::get_row() const
|
||||||
|
@ -1035,13 +1032,15 @@ std::size_t cell::get_xf_index() const
|
||||||
|
|
||||||
const number_format &cell::get_number_format() const
|
const number_format &cell::get_number_format() const
|
||||||
{
|
{
|
||||||
|
static const number_format default_format;
|
||||||
|
|
||||||
if(d_->has_style_)
|
if(d_->has_style_)
|
||||||
{
|
{
|
||||||
return get_parent().get_parent().get_number_format(d_->style_id_);
|
return get_parent().get_parent().get_number_format(d_->style_id_);
|
||||||
}
|
}
|
||||||
else if(get_parent().get_parent().get_number_formats().empty())
|
else if(get_parent().get_parent().get_number_formats().empty())
|
||||||
{
|
{
|
||||||
return number_format::default_number_format();
|
return default_format;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -1239,6 +1238,17 @@ std::size_t cell::get_style_id() const
|
||||||
return d_->style_id_;
|
return d_->style_id_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool cell::has_style() const
|
||||||
|
{
|
||||||
|
return d_->has_style_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cell::set_style_id(std::size_t style_id)
|
||||||
|
{
|
||||||
|
d_->style_id_ = style_id;
|
||||||
|
d_->has_style_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
calendar cell::get_base_date() const
|
calendar cell::get_base_date() const
|
||||||
{
|
{
|
||||||
return get_parent().get_parent().get_properties().excel_base_date;
|
return get_parent().get_parent().get_properties().excel_base_date;
|
||||||
|
|
|
@ -152,7 +152,7 @@ struct cell_impl
|
||||||
{
|
{
|
||||||
value_numeric_ = percentage.second;
|
value_numeric_ = percentage.second;
|
||||||
type_ = cell::type::numeric;
|
type_ = cell::type::numeric;
|
||||||
self().set_number_format(xlnt::number_format(xlnt::number_format::format::percentage));
|
self().set_number_format(xlnt::number_format::percentage());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -161,7 +161,7 @@ struct cell_impl
|
||||||
if (time.first)
|
if (time.first)
|
||||||
{
|
{
|
||||||
type_ = cell::type::numeric;
|
type_ = cell::type::numeric;
|
||||||
self().set_number_format(xlnt::number_format(number_format::format::date_time6));
|
self().set_number_format(number_format::date_time6());
|
||||||
value_numeric_ = time.second.to_number();
|
value_numeric_ = time.second.to_number();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
|
@ -19,12 +19,10 @@ struct workbook_impl
|
||||||
guess_types_(other.guess_types_),
|
guess_types_(other.guess_types_),
|
||||||
data_only_(other.data_only_),
|
data_only_(other.data_only_),
|
||||||
styles_(other.styles_),
|
styles_(other.styles_),
|
||||||
alignments_(other.alignments_),
|
|
||||||
borders_(other.borders_),
|
borders_(other.borders_),
|
||||||
fills_(other.fills_),
|
fills_(other.fills_),
|
||||||
fonts_(other.fonts_),
|
fonts_(other.fonts_),
|
||||||
number_formats_(other.number_formats_),
|
number_formats_(other.number_formats_)
|
||||||
protections_(other.protections_)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,12 +39,10 @@ struct workbook_impl
|
||||||
guess_types_ = other.guess_types_;
|
guess_types_ = other.guess_types_;
|
||||||
data_only_ = other.data_only_;
|
data_only_ = other.data_only_;
|
||||||
styles_ = other.styles_;
|
styles_ = other.styles_;
|
||||||
alignments_ = other.alignments_;
|
|
||||||
borders_ = other.borders_;
|
borders_ = other.borders_;
|
||||||
fills_ = other.fills_;
|
fills_ = other.fills_;
|
||||||
fonts_ = other.fonts_;
|
fonts_ = other.fonts_;
|
||||||
number_formats_ = other.number_formats_;
|
number_formats_ = other.number_formats_;
|
||||||
protections_ = other.protections_;
|
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
@ -63,12 +59,12 @@ struct workbook_impl
|
||||||
|
|
||||||
std::vector<style> styles_;
|
std::vector<style> styles_;
|
||||||
|
|
||||||
std::vector<alignment> alignments_;
|
std::size_t next_custom_format_id_;
|
||||||
|
|
||||||
std::vector<border> borders_;
|
std::vector<border> borders_;
|
||||||
std::vector<fill> fills_;
|
std::vector<fill> fills_;
|
||||||
std::vector<font> fonts_;
|
std::vector<font> fonts_;
|
||||||
std::vector<number_format> number_formats_;
|
std::vector<number_format> number_formats_;
|
||||||
std::vector<protection> protections_;
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,17 @@
|
||||||
|
#include <xlnt/common/datetime.hpp>
|
||||||
|
#include <xlnt/common/exceptions.hpp>
|
||||||
|
#include <xlnt/common/zip_file.hpp>
|
||||||
|
#include <xlnt/styles/style.hpp>
|
||||||
#include <xlnt/reader/excel_reader.hpp>
|
#include <xlnt/reader/excel_reader.hpp>
|
||||||
|
#include <xlnt/reader/shared_strings_reader.hpp>
|
||||||
|
#include <xlnt/reader/style_reader.hpp>
|
||||||
|
#include <xlnt/reader/workbook_reader.hpp>
|
||||||
|
#include <xlnt/reader/worksheet_reader.hpp>
|
||||||
|
#include <xlnt/workbook/document_properties.hpp>
|
||||||
#include <xlnt/workbook/workbook.hpp>
|
#include <xlnt/workbook/workbook.hpp>
|
||||||
|
#include <xlnt/worksheet/worksheet.hpp>
|
||||||
|
|
||||||
|
#include "detail/include_pugixml.hpp"
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
@ -20,17 +32,92 @@ std::string::size_type find_string_in_string(const std::string &string, const st
|
||||||
return possible_match_index;
|
return possible_match_index;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
xlnt::workbook load_workbook(xlnt::zip_file &archive, bool guess_types, bool data_only)
|
||||||
|
{
|
||||||
|
xlnt::workbook wb;
|
||||||
|
|
||||||
|
wb.set_guess_types(guess_types);
|
||||||
|
wb.set_data_only(data_only);
|
||||||
|
|
||||||
|
auto content_types = xlnt::read_content_types(archive);
|
||||||
|
auto type = xlnt::determine_document_type(content_types);
|
||||||
|
|
||||||
|
if(type != "excel")
|
||||||
|
{
|
||||||
|
throw xlnt::invalid_file_exception("");
|
||||||
|
}
|
||||||
|
|
||||||
|
wb.clear();
|
||||||
|
|
||||||
|
auto workbook_relationships = read_relationships(archive, "xl/workbook.xml");
|
||||||
|
|
||||||
|
for(auto relationship : workbook_relationships)
|
||||||
|
{
|
||||||
|
wb.create_relationship(relationship.get_id(), relationship.get_target_uri(), relationship.get_type());
|
||||||
|
}
|
||||||
|
|
||||||
|
pugi::xml_document doc;
|
||||||
|
doc.load(archive.read("xl/workbook.xml").c_str());
|
||||||
|
|
||||||
|
auto root_node = doc.child("workbook");
|
||||||
|
|
||||||
|
auto workbook_pr_node = root_node.child("workbookPr");
|
||||||
|
wb.get_properties().excel_base_date = (workbook_pr_node.attribute("date1904") != nullptr && workbook_pr_node.attribute("date1904").as_int() != 0) ? xlnt::calendar::mac_1904 : xlnt::calendar::windows_1900;
|
||||||
|
|
||||||
|
auto sheets_node = root_node.child("sheets");
|
||||||
|
|
||||||
|
xlnt::shared_strings_reader shared_strings_reader_;
|
||||||
|
auto shared_strings = shared_strings_reader_.read_strings(archive);
|
||||||
|
|
||||||
|
xlnt::style_reader style_reader_(wb);
|
||||||
|
style_reader_.read_styles(archive);
|
||||||
|
|
||||||
|
for(const auto &border_ : style_reader_.get_borders())
|
||||||
|
{
|
||||||
|
wb.add_border(border_);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(const auto &fill_ : style_reader_.get_fills())
|
||||||
|
{
|
||||||
|
wb.add_fill(fill_);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(const auto &font_ : style_reader_.get_fonts())
|
||||||
|
{
|
||||||
|
wb.add_font(font_);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(const auto &number_format_ : style_reader_.get_number_formats())
|
||||||
|
{
|
||||||
|
wb.add_number_format(number_format_);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(const auto &style : style_reader_.get_styles())
|
||||||
|
{
|
||||||
|
wb.add_style(style);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(auto sheet_node : sheets_node.children("sheet"))
|
||||||
|
{
|
||||||
|
auto rel = wb.get_relationship(sheet_node.attribute("r:id").as_string());
|
||||||
|
auto ws = wb.create_sheet(sheet_node.attribute("name").as_string(), rel);
|
||||||
|
|
||||||
|
xlnt::read_worksheet(ws, archive, rel, shared_strings);
|
||||||
|
}
|
||||||
|
|
||||||
|
return wb;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
namespace xlnt {
|
namespace xlnt {
|
||||||
|
|
||||||
std::string CentralDirectorySignature()
|
std::string excel_reader::CentralDirectorySignature()
|
||||||
{
|
{
|
||||||
return "\x50\x4b\x05\x06";
|
return "\x50\x4b\x05\x06";
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string repair_central_directory(const std::string &original)
|
std::string excel_reader::repair_central_directory(const std::string &original)
|
||||||
{
|
{
|
||||||
auto pos = find_string_in_string(original, CentralDirectorySignature());
|
auto pos = find_string_in_string(original, CentralDirectorySignature());
|
||||||
|
|
||||||
|
@ -42,26 +129,36 @@ std::string repair_central_directory(const std::string &original)
|
||||||
return original;
|
return original;
|
||||||
}
|
}
|
||||||
|
|
||||||
workbook load_workbook(const std::string &filename, bool guess_types, bool data_only)
|
workbook excel_reader::load_workbook(std::istream &stream, bool guess_types, bool data_only)
|
||||||
{
|
{
|
||||||
workbook wb;
|
std::vector<std::uint8_t> bytes((std::istream_iterator<char>(stream)),
|
||||||
|
std::istream_iterator<char>());
|
||||||
|
|
||||||
wb.set_guess_types(guess_types);
|
return load_workbook(bytes, guess_types, data_only);
|
||||||
wb.set_data_only(data_only);
|
|
||||||
wb.load(filename);
|
|
||||||
|
|
||||||
return wb;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
xlnt::workbook load_workbook(const std::vector<std::uint8_t> &bytes, bool guess_types, bool data_only)
|
workbook excel_reader::load_workbook(const std::string &filename, bool guess_types, bool data_only)
|
||||||
{
|
{
|
||||||
xlnt::workbook wb;
|
xlnt::zip_file archive;
|
||||||
|
|
||||||
wb.set_guess_types(guess_types);
|
try
|
||||||
wb.set_data_only(data_only);
|
{
|
||||||
wb.load(bytes);
|
archive.load(filename);
|
||||||
|
}
|
||||||
|
catch(std::runtime_error)
|
||||||
|
{
|
||||||
|
throw invalid_file_exception(filename);
|
||||||
|
}
|
||||||
|
|
||||||
return wb;
|
return ::load_workbook(archive, guess_types, data_only);
|
||||||
|
}
|
||||||
|
|
||||||
|
xlnt::workbook excel_reader::load_workbook(const std::vector<std::uint8_t> &bytes, bool guess_types, bool data_only)
|
||||||
|
{
|
||||||
|
xlnt::zip_file archive;
|
||||||
|
archive.load(bytes);
|
||||||
|
|
||||||
|
return ::load_workbook(archive, guess_types, data_only);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace xlnt
|
} // namespace xlnt
|
||||||
|
|
|
@ -1,18 +1,27 @@
|
||||||
|
#include <xlnt/common/zip_file.hpp>
|
||||||
#include <xlnt/reader/shared_strings_reader.hpp>
|
#include <xlnt/reader/shared_strings_reader.hpp>
|
||||||
|
|
||||||
#include "detail/include_pugixml.hpp"
|
#include "detail/include_pugixml.hpp"
|
||||||
|
|
||||||
namespace xlnt {
|
namespace xlnt {
|
||||||
|
|
||||||
std::vector<std::string> read_shared_strings(const std::string &xml_string)
|
std::vector<std::string> shared_strings_reader::read_strings(zip_file &archive)
|
||||||
{
|
{
|
||||||
std::vector<std::string> shared_strings;
|
static const std::string shared_strings_filename = "xl/sharedStrings.xml";
|
||||||
|
|
||||||
|
if(!archive.has_file(shared_strings_filename))
|
||||||
|
{
|
||||||
|
return { };
|
||||||
|
}
|
||||||
|
|
||||||
pugi::xml_document doc;
|
pugi::xml_document doc;
|
||||||
doc.load(xml_string.c_str());
|
doc.load(archive.read(shared_strings_filename).c_str());
|
||||||
|
|
||||||
auto root_node = doc.child("sst");
|
auto root_node = doc.child("sst");
|
||||||
//int count = root_node.attribute("count").as_int();
|
|
||||||
int unique_count = root_node.attribute("uniqueCount").as_int();
|
int unique_count = root_node.attribute("uniqueCount").as_int();
|
||||||
|
|
||||||
|
std::vector<std::string> shared_strings;
|
||||||
|
|
||||||
for(auto si_node : root_node)
|
for(auto si_node : root_node)
|
||||||
{
|
{
|
||||||
shared_strings.push_back(si_node.child("t").text().as_string());
|
shared_strings.push_back(si_node.child("t").text().as_string());
|
||||||
|
|
505
source/reader/style_reader.cpp
Normal file
505
source/reader/style_reader.cpp
Normal file
|
@ -0,0 +1,505 @@
|
||||||
|
#include <xlnt/common/zip_file.hpp>
|
||||||
|
#include <xlnt/styles/border.hpp>
|
||||||
|
#include <xlnt/styles/fill.hpp>
|
||||||
|
#include <xlnt/styles/font.hpp>
|
||||||
|
#include <xlnt/styles/named_style.hpp>
|
||||||
|
#include <xlnt/styles/number_format.hpp>
|
||||||
|
#include <xlnt/styles/style.hpp>
|
||||||
|
#include <xlnt/reader/style_reader.hpp>
|
||||||
|
|
||||||
|
#include "detail/include_pugixml.hpp"
|
||||||
|
|
||||||
|
namespace xlnt {
|
||||||
|
|
||||||
|
protection read_protection(pugi::xml_node node)
|
||||||
|
{
|
||||||
|
auto prot_type_from_string = [](const std::string &type_string)
|
||||||
|
{
|
||||||
|
if(type_string == "true") return protection::type::protected_;
|
||||||
|
else if(type_string == "inherit") return protection::type::inherit;
|
||||||
|
return protection::type::unprotected;
|
||||||
|
};
|
||||||
|
|
||||||
|
protection prot;
|
||||||
|
prot.set_locked(prot_type_from_string(node.attribute("locked").as_string()));
|
||||||
|
prot.set_hidden(prot_type_from_string(node.attribute("hidden").as_string()));
|
||||||
|
return prot;
|
||||||
|
}
|
||||||
|
|
||||||
|
alignment read_alignment(pugi::xml_node node)
|
||||||
|
{
|
||||||
|
alignment align;
|
||||||
|
|
||||||
|
align.set_wrap_text(node.attribute("wrapText").as_int() != 0);
|
||||||
|
|
||||||
|
bool has_vertical = node.attribute("vertical") != nullptr;
|
||||||
|
std::string vertical = has_vertical ? node.attribute("vertical").as_string() : "";
|
||||||
|
|
||||||
|
if(has_vertical)
|
||||||
|
{
|
||||||
|
if(vertical == "bottom")
|
||||||
|
{
|
||||||
|
align.set_vertical(alignment::vertical_alignment::bottom);
|
||||||
|
}
|
||||||
|
else if(vertical =="center")
|
||||||
|
{
|
||||||
|
align.set_vertical(alignment::vertical_alignment::center);
|
||||||
|
}
|
||||||
|
else if(vertical =="justify")
|
||||||
|
{
|
||||||
|
align.set_vertical(alignment::vertical_alignment::justify);
|
||||||
|
}
|
||||||
|
else if(vertical =="top")
|
||||||
|
{
|
||||||
|
align.set_vertical(alignment::vertical_alignment::top);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw "unknown alignment";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool has_horizontal = node.attribute("horizontal") != nullptr;
|
||||||
|
std::string horizontal = has_horizontal ? node.attribute("horizontal").as_string() : "";
|
||||||
|
|
||||||
|
if(has_horizontal)
|
||||||
|
{
|
||||||
|
if(horizontal == "left")
|
||||||
|
{
|
||||||
|
align.set_horizontal(alignment::horizontal_alignment::left);
|
||||||
|
}
|
||||||
|
else if(horizontal == "center")
|
||||||
|
{
|
||||||
|
align.set_horizontal(alignment::horizontal_alignment::center);
|
||||||
|
}
|
||||||
|
else if(horizontal == "center-continuous")
|
||||||
|
{
|
||||||
|
align.set_horizontal(alignment::horizontal_alignment::center_continuous);
|
||||||
|
}
|
||||||
|
else if(horizontal == "right")
|
||||||
|
{
|
||||||
|
align.set_horizontal(alignment::horizontal_alignment::right);
|
||||||
|
}
|
||||||
|
else if(horizontal == "justify")
|
||||||
|
{
|
||||||
|
align.set_horizontal(alignment::horizontal_alignment::justify);
|
||||||
|
}
|
||||||
|
else if(horizontal == "general")
|
||||||
|
{
|
||||||
|
align.set_horizontal(alignment::horizontal_alignment::general);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw "unknown alignment";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return align;
|
||||||
|
}
|
||||||
|
|
||||||
|
style style_reader::read_style(pugi::xml_node stylesheet_node, pugi::xml_node xf_node)
|
||||||
|
{
|
||||||
|
style s;
|
||||||
|
|
||||||
|
s.apply_number_format(xf_node.attribute("applyNumberFormat").as_bool());
|
||||||
|
s.number_format_id_ = xf_node.attribute("numFmtId").as_int();
|
||||||
|
|
||||||
|
bool builtin_format = true;
|
||||||
|
|
||||||
|
for(auto num_fmt : number_formats_)
|
||||||
|
{
|
||||||
|
if(num_fmt.get_id() == s.get_number_format_id())
|
||||||
|
{
|
||||||
|
s.number_format_ = num_fmt;
|
||||||
|
builtin_format = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(builtin_format)
|
||||||
|
{
|
||||||
|
s.number_format_ = number_format::from_builtin_id(s.get_number_format_id());
|
||||||
|
}
|
||||||
|
|
||||||
|
s.apply_font(xf_node.attribute("applyFont").as_bool());
|
||||||
|
s.font_id_ = xf_node.attribute("fontId") != nullptr ? xf_node.attribute("fontId").as_int() : 0;
|
||||||
|
s.font_ = fonts_[s.font_id_];
|
||||||
|
|
||||||
|
s.apply_fill(xf_node.attribute("applyFill").as_bool());
|
||||||
|
s.fill_id_ = xf_node.attribute("fillId").as_int();
|
||||||
|
s.fill_ = fills_[s.fill_id_];
|
||||||
|
|
||||||
|
s.apply_border(xf_node.attribute("applyBorder").as_bool());
|
||||||
|
s.border_id_ = xf_node.attribute("borderId").as_int();
|
||||||
|
s.border_ = borders_[s.border_id_];
|
||||||
|
|
||||||
|
s.apply_protection(xf_node.attribute("protection") != nullptr);
|
||||||
|
|
||||||
|
if(s.protection_apply_)
|
||||||
|
{
|
||||||
|
auto inline_protection = read_protection(xf_node.child("protection"));
|
||||||
|
s.protection_ = inline_protection;
|
||||||
|
}
|
||||||
|
|
||||||
|
s.apply_alignment(xf_node.child("alignment") != nullptr);
|
||||||
|
|
||||||
|
if(s.alignment_apply_)
|
||||||
|
{
|
||||||
|
auto inline_alignment = read_alignment(xf_node.child("alignment"));
|
||||||
|
s.alignment_ = inline_alignment;
|
||||||
|
}
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
style_reader::style_reader(workbook &wb)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void style_reader::read_styles(zip_file &archive)
|
||||||
|
{
|
||||||
|
auto xml = archive.read("xl/styles.xml");
|
||||||
|
|
||||||
|
pugi::xml_document doc;
|
||||||
|
doc.load_string(xml.c_str());
|
||||||
|
|
||||||
|
auto root = doc.root();
|
||||||
|
auto stylesheet_node = root.child("styleSheet");
|
||||||
|
|
||||||
|
read_borders(stylesheet_node.child("borders"));
|
||||||
|
read_fills(stylesheet_node.child("fills"));
|
||||||
|
read_fonts(stylesheet_node.child("fonts"));
|
||||||
|
read_number_formats(stylesheet_node.child("numFmts"));
|
||||||
|
|
||||||
|
auto cell_xfs_node = stylesheet_node.child("cellXfs");
|
||||||
|
|
||||||
|
for(auto xf_node : cell_xfs_node.children("xf"))
|
||||||
|
{
|
||||||
|
styles_.push_back(read_style(stylesheet_node, xf_node));
|
||||||
|
styles_.back().id_ = styles_.size() - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
read_color_index();
|
||||||
|
read_dxfs();
|
||||||
|
read_cell_styles();
|
||||||
|
read_named_styles(root.child("namedStyles"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void style_reader::read_number_formats(pugi::xml_node num_fmts_node)
|
||||||
|
{
|
||||||
|
for(auto num_fmt_node : num_fmts_node.children("numFmt"))
|
||||||
|
{
|
||||||
|
number_format nf;
|
||||||
|
|
||||||
|
nf.set_format_string(num_fmt_node.attribute("formatCode").as_string());
|
||||||
|
nf.set_id(num_fmt_node.attribute("numFmtId").as_int());
|
||||||
|
|
||||||
|
number_formats_.push_back(nf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void style_reader::read_color_index()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void style_reader::read_dxfs()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void style_reader::read_fonts(pugi::xml_node fonts_node)
|
||||||
|
{
|
||||||
|
for(auto font_node : fonts_node)
|
||||||
|
{
|
||||||
|
font new_font;
|
||||||
|
|
||||||
|
new_font.set_size(font_node.child("sz").attribute("val").as_int());
|
||||||
|
new_font.set_name(font_node.child("name").attribute("val").as_string());
|
||||||
|
|
||||||
|
if(font_node.child("color").attribute("theme") != nullptr)
|
||||||
|
{
|
||||||
|
new_font.set_color(color(color::type::theme, font_node.child("color").attribute("theme").as_ullong()));
|
||||||
|
}
|
||||||
|
else if(font_node.child("color").attribute("indexed") != nullptr)
|
||||||
|
{
|
||||||
|
new_font.set_color(color(color::type::indexed, font_node.child("color").attribute("indexed").as_ullong()));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(font_node.child("family") != nullptr)
|
||||||
|
{
|
||||||
|
new_font.set_family(font_node.child("family").attribute("val").as_int());
|
||||||
|
}
|
||||||
|
|
||||||
|
if(font_node.child("scheme") != nullptr)
|
||||||
|
{
|
||||||
|
new_font.set_scheme(font_node.child("scheme").attribute("val").as_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
if(font_node.child("b") != nullptr)
|
||||||
|
{
|
||||||
|
new_font.set_bold(font_node.child("b").attribute("val").as_bool());
|
||||||
|
}
|
||||||
|
|
||||||
|
fonts_.push_back(new_font);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void style_reader::read_fills(pugi::xml_node fills_node)
|
||||||
|
{
|
||||||
|
auto pattern_fill_type_from_string = [](const std::string &fill_type)
|
||||||
|
{
|
||||||
|
if(fill_type == "none") return fill::pattern_type::none;
|
||||||
|
if(fill_type == "solid") return fill::pattern_type::solid;
|
||||||
|
if(fill_type == "gray125") return fill::pattern_type::gray125;
|
||||||
|
throw std::runtime_error("invalid fill type");
|
||||||
|
};
|
||||||
|
|
||||||
|
for(auto fill_node : fills_node)
|
||||||
|
{
|
||||||
|
fill new_fill;
|
||||||
|
|
||||||
|
if(fill_node.child("patternFill") != nullptr)
|
||||||
|
{
|
||||||
|
auto pattern_fill_node = fill_node.child("patternFill");
|
||||||
|
new_fill.set_type(fill::type::pattern);
|
||||||
|
std::string pattern_type_string = pattern_fill_node.attribute("patternType").as_string();
|
||||||
|
auto pattern_type = pattern_fill_type_from_string(pattern_type_string);
|
||||||
|
new_fill.set_pattern_type(pattern_type);
|
||||||
|
|
||||||
|
auto bg_color_node = pattern_fill_node.child("bgColor");
|
||||||
|
|
||||||
|
if(bg_color_node != nullptr)
|
||||||
|
{
|
||||||
|
if(bg_color_node.attribute("indexed") != nullptr)
|
||||||
|
{
|
||||||
|
new_fill.set_background_color(color(color::type::indexed, bg_color_node.attribute("indexed").as_ullong()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto fg_color_node = pattern_fill_node.child("fgColor");
|
||||||
|
|
||||||
|
if(fg_color_node != nullptr)
|
||||||
|
{
|
||||||
|
if(fg_color_node.attribute("indexed") != nullptr)
|
||||||
|
{
|
||||||
|
new_fill.set_foreground_color(color(color::type::indexed, fg_color_node.attribute("indexed").as_ullong()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fills_.push_back(new_fill);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void style_reader::read_borders(pugi::xml_node borders_node)
|
||||||
|
{
|
||||||
|
for(auto border_node : borders_node)
|
||||||
|
{
|
||||||
|
border new_border;
|
||||||
|
|
||||||
|
if(border_node.child("left") != nullptr)
|
||||||
|
{
|
||||||
|
new_border.left_assigned = true;
|
||||||
|
auto left_node = border_node.child("left");
|
||||||
|
|
||||||
|
if(left_node.attribute("style") != nullptr)
|
||||||
|
{
|
||||||
|
if(left_node.attribute("style").as_string() == std::string("thin"))
|
||||||
|
{
|
||||||
|
new_border.left.set_border_style(border_style::thin);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw std::runtime_error("unknown border style");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto color_node = left_node.child("color");
|
||||||
|
|
||||||
|
if(color_node != nullptr)
|
||||||
|
{
|
||||||
|
if(color_node.attribute("indexed") != nullptr)
|
||||||
|
{
|
||||||
|
new_border.left.set_color(side::color_type::indexed, color_node.attribute("indexed").as_int());
|
||||||
|
}
|
||||||
|
else if(color_node.attribute("theme") != nullptr)
|
||||||
|
{
|
||||||
|
new_border.left.set_color(side::color_type::theme, color_node.attribute("theme").as_int());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw std::runtime_error("invalid color type");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(border_node.child("right") != nullptr)
|
||||||
|
{
|
||||||
|
new_border.right_assigned = true;
|
||||||
|
auto right_node = border_node.child("right");
|
||||||
|
|
||||||
|
if(right_node.attribute("style") != nullptr)
|
||||||
|
{
|
||||||
|
if(right_node.attribute("style").as_string() == std::string("thin"))
|
||||||
|
{
|
||||||
|
new_border.right.set_border_style(border_style::thin);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw std::runtime_error("unknown border style");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto color_node = right_node.child("color");
|
||||||
|
|
||||||
|
if(color_node != nullptr)
|
||||||
|
{
|
||||||
|
if(color_node.attribute("indexed") != nullptr)
|
||||||
|
{
|
||||||
|
new_border.right.set_color(side::color_type::indexed, color_node.attribute("indexed").as_int());
|
||||||
|
}
|
||||||
|
else if(color_node.attribute("theme") != nullptr)
|
||||||
|
{
|
||||||
|
new_border.right.set_color(side::color_type::theme, color_node.attribute("theme").as_int());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw std::runtime_error("invalid color type");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(border_node.child("top") != nullptr)
|
||||||
|
{
|
||||||
|
new_border.top_assigned = true;
|
||||||
|
auto top_node = border_node.child("top");
|
||||||
|
|
||||||
|
if(top_node.attribute("style") != nullptr)
|
||||||
|
{
|
||||||
|
if(top_node.attribute("style").as_string() == std::string("thin"))
|
||||||
|
{
|
||||||
|
new_border.top.set_border_style(border_style::thin);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw std::runtime_error("unknown border style");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto color_node = top_node.child("color");
|
||||||
|
|
||||||
|
if(color_node != nullptr)
|
||||||
|
{
|
||||||
|
if(color_node.attribute("indexed") != nullptr)
|
||||||
|
{
|
||||||
|
new_border.top.set_color(side::color_type::indexed, color_node.attribute("indexed").as_int());
|
||||||
|
}
|
||||||
|
else if(color_node.attribute("theme") != nullptr)
|
||||||
|
{
|
||||||
|
new_border.top.set_color(side::color_type::theme, color_node.attribute("theme").as_int());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw std::runtime_error("invalid color type");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(border_node.child("bottom") != nullptr)
|
||||||
|
{
|
||||||
|
new_border.bottom_assigned = true;
|
||||||
|
auto bottom_node = border_node.child("bottom");
|
||||||
|
|
||||||
|
if(bottom_node.attribute("style") != nullptr)
|
||||||
|
{
|
||||||
|
if(bottom_node.attribute("style").as_string() == std::string("thin"))
|
||||||
|
{
|
||||||
|
new_border.bottom.set_border_style(border_style::thin);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw std::runtime_error("unknown border style");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto color_node = bottom_node.child("color");
|
||||||
|
|
||||||
|
if(color_node != nullptr)
|
||||||
|
{
|
||||||
|
if(color_node.attribute("indexed") != nullptr)
|
||||||
|
{
|
||||||
|
new_border.bottom.set_color(side::color_type::indexed, color_node.attribute("indexed").as_int());
|
||||||
|
}
|
||||||
|
else if(color_node.attribute("theme") != nullptr)
|
||||||
|
{
|
||||||
|
new_border.bottom.set_color(side::color_type::theme, color_node.attribute("theme").as_int());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw std::runtime_error("invalid color type");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(border_node.child("diagonal") != nullptr)
|
||||||
|
{
|
||||||
|
new_border.diagonal_assigned = true;
|
||||||
|
auto diagonal_node = border_node.child("diagonal");
|
||||||
|
|
||||||
|
if(diagonal_node.attribute("style") != nullptr)
|
||||||
|
{
|
||||||
|
if(diagonal_node.attribute("style").as_string() == std::string("thin"))
|
||||||
|
{
|
||||||
|
new_border.diagonal.set_border_style(border_style::thin);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw std::runtime_error("unknown border style");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto color_node = diagonal_node.child("color");
|
||||||
|
|
||||||
|
if(color_node != nullptr)
|
||||||
|
{
|
||||||
|
if(color_node.attribute("indexed") != nullptr)
|
||||||
|
{
|
||||||
|
new_border.diagonal.set_color(side::color_type::indexed, color_node.attribute("indexed").as_int());
|
||||||
|
}
|
||||||
|
else if(color_node.attribute("theme") != nullptr)
|
||||||
|
{
|
||||||
|
new_border.diagonal.set_color(side::color_type::theme, color_node.attribute("theme").as_int());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw std::runtime_error("invalid color type");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
borders_.push_back(new_border);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void style_reader::read_named_styles(pugi::xml_node named_styles_node)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void style_reader::read_style_names()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void style_reader::read_cell_styles()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void style_reader::read_xfs()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void style_reader::read_style_table()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace xlnt
|
|
@ -1,9 +1,9 @@
|
||||||
|
|
||||||
#include <xlnt/styles/border.hpp>
|
#include <xlnt/styles/side.hpp>
|
||||||
|
|
||||||
namespace xlnt {
|
namespace xlnt {
|
||||||
|
|
||||||
side::side(border_style style, color c) : style_(style), color_(c)
|
side::side()
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <regex>
|
#include <regex>
|
||||||
|
|
||||||
|
#include <xlnt/common/hash_combine.hpp>
|
||||||
#include <xlnt/styles/number_format.hpp>
|
#include <xlnt/styles/number_format.hpp>
|
||||||
|
|
||||||
namespace xlnt {
|
namespace {
|
||||||
|
|
||||||
const std::unordered_map<int, std::string> &number_format::builtin_formats()
|
const std::unordered_map<int, std::string> &builtin_formats()
|
||||||
{
|
{
|
||||||
static const std::unordered_map<int, std::string> formats =
|
static const std::unordered_map<int, std::string> formats =
|
||||||
{
|
{
|
||||||
|
@ -63,97 +64,236 @@ const std::unordered_map<int, std::string> &number_format::builtin_formats()
|
||||||
return formats;
|
return formats;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::unordered_map<number_format::format, std::string, number_format::format_hash> &number_format::format_strings()
|
} // namespace
|
||||||
{
|
|
||||||
static const std::unordered_map<number_format::format, std::string, number_format::format_hash> strings =
|
|
||||||
{
|
|
||||||
{format::general, builtin_formats().at(0)},
|
|
||||||
{format::text, builtin_formats().at(49)},
|
|
||||||
{format::number, builtin_formats().at(1)},
|
|
||||||
{format::number_00, builtin_formats().at(2)},
|
|
||||||
{format::number_comma_separated1, builtin_formats().at(4)},
|
|
||||||
{format::number_comma_separated2, "#,##0.00_-"},
|
|
||||||
{format::percentage, builtin_formats().at(9)},
|
|
||||||
{format::percentage_00, builtin_formats().at(10)},
|
|
||||||
{format::date_yyyymmdd2, "yyyy-mm-dd"},
|
|
||||||
{format::date_yyyymmdd, "yy-mm-dd"},
|
|
||||||
{format::date_ddmmyyyy, "dd/mm/yy"},
|
|
||||||
{format::date_dmyslash, "d/m/y"},
|
|
||||||
{format::date_dmyminus, "d-m-y"},
|
|
||||||
{format::date_dmminus, "d-m"},
|
|
||||||
{format::date_myminus, "m-y"},
|
|
||||||
{format::date_xlsx14, builtin_formats().at(14)},
|
|
||||||
{format::date_xlsx15, builtin_formats().at(15)},
|
|
||||||
{format::date_xlsx16, builtin_formats().at(16)},
|
|
||||||
{format::date_xlsx17, builtin_formats().at(17)},
|
|
||||||
{format::date_xlsx22, builtin_formats().at(22)},
|
|
||||||
{format::date_datetime, "yyyy-mm-dd h:mm:ss"},
|
|
||||||
{format::date_time1, builtin_formats().at(18)},
|
|
||||||
{format::date_time2, builtin_formats().at(19)},
|
|
||||||
{format::date_time3, builtin_formats().at(20)},
|
|
||||||
{format::date_time4, builtin_formats().at(21)},
|
|
||||||
{format::date_time5, builtin_formats().at(45)},
|
|
||||||
{format::date_time6, builtin_formats().at(21)},
|
|
||||||
{format::date_time7, "i:s.S"},
|
|
||||||
{format::date_time8, "h:mm:ss@"},
|
|
||||||
{format::date_timedelta, "[hh]:mm:ss"},
|
|
||||||
{format::date_yyyymmddslash, "yy/mm/dd@"},
|
|
||||||
{format::currency_usd_simple, "\"$\"#,##0.00_-"},
|
|
||||||
{format::currency_usd, "$#,##0_-"},
|
|
||||||
{format::currency_eur_simple, "[$EUR ]#,##0.00_-"}
|
|
||||||
};
|
|
||||||
|
|
||||||
return strings;
|
namespace xlnt {
|
||||||
|
|
||||||
|
const number_format number_format::general()
|
||||||
|
{
|
||||||
|
static const number_format format(builtin_formats().at(0), 0);
|
||||||
|
return format;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::unordered_map<std::string, int> &number_format::reversed_builtin_formats()
|
const number_format number_format::text()
|
||||||
{
|
{
|
||||||
static std::unordered_map<std::string, int> formats;
|
static const number_format format(builtin_formats().at(49), 49);
|
||||||
static bool initialised = false;
|
return format;
|
||||||
|
|
||||||
if(!initialised)
|
|
||||||
{
|
|
||||||
for(auto format_pair : builtin_formats())
|
|
||||||
{
|
|
||||||
formats[format_pair.second] = format_pair.first;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
initialised = true;
|
const number_format number_format::number()
|
||||||
|
{
|
||||||
|
static const number_format format(builtin_formats().at(1), 1);
|
||||||
|
return format;
|
||||||
}
|
}
|
||||||
|
|
||||||
return formats;
|
const number_format number_format::number_00()
|
||||||
|
{
|
||||||
|
static const number_format format(builtin_formats().at(2), 2);
|
||||||
|
return format;
|
||||||
}
|
}
|
||||||
|
|
||||||
number_format::number_format() : number_format(format::general)
|
const number_format number_format::number_comma_separated1()
|
||||||
|
{
|
||||||
|
static const number_format format(builtin_formats().at(4), 4);
|
||||||
|
return format;
|
||||||
|
}
|
||||||
|
|
||||||
|
const number_format number_format::number_comma_separated2()
|
||||||
|
{
|
||||||
|
static const number_format format("#,##0.00_-");
|
||||||
|
return format;
|
||||||
|
}
|
||||||
|
|
||||||
|
const number_format number_format::percentage()
|
||||||
|
{
|
||||||
|
static const number_format format(builtin_formats().at(9), 9);
|
||||||
|
return format;
|
||||||
|
}
|
||||||
|
|
||||||
|
const number_format number_format::percentage_00()
|
||||||
|
{
|
||||||
|
static const number_format format(builtin_formats().at(10), 10);
|
||||||
|
return format;
|
||||||
|
}
|
||||||
|
|
||||||
|
const number_format number_format::date_yyyymmdd2()
|
||||||
|
{
|
||||||
|
static const number_format format("yyyy-mm-dd");
|
||||||
|
return format;
|
||||||
|
}
|
||||||
|
|
||||||
|
const number_format number_format::date_yyyymmdd()
|
||||||
|
{
|
||||||
|
static const number_format format("yy-mm-dd");
|
||||||
|
return format;
|
||||||
|
}
|
||||||
|
|
||||||
|
const number_format number_format::date_ddmmyyyy()
|
||||||
|
{
|
||||||
|
static const number_format format("dd/mm/yy");
|
||||||
|
return format;
|
||||||
|
}
|
||||||
|
|
||||||
|
const number_format number_format::date_dmyslash()
|
||||||
|
{
|
||||||
|
static const number_format format("d/m/y");
|
||||||
|
return format;
|
||||||
|
}
|
||||||
|
|
||||||
|
const number_format number_format::date_dmyminus()
|
||||||
|
{
|
||||||
|
static const number_format format("d-m-y");
|
||||||
|
return format;
|
||||||
|
}
|
||||||
|
|
||||||
|
const number_format number_format::date_dmminus()
|
||||||
|
{
|
||||||
|
static const number_format format("d-m");
|
||||||
|
return format;
|
||||||
|
}
|
||||||
|
|
||||||
|
const number_format number_format::date_myminus()
|
||||||
|
{
|
||||||
|
static const number_format format("m-y");
|
||||||
|
return format;
|
||||||
|
}
|
||||||
|
|
||||||
|
const number_format number_format::date_xlsx14()
|
||||||
|
{
|
||||||
|
static const number_format format(builtin_formats().at(14), 14);
|
||||||
|
return format;
|
||||||
|
}
|
||||||
|
|
||||||
|
const number_format number_format::date_xlsx15()
|
||||||
|
{
|
||||||
|
static const number_format format(builtin_formats().at(15), 15);
|
||||||
|
return format;
|
||||||
|
}
|
||||||
|
|
||||||
|
const number_format number_format::date_xlsx16()
|
||||||
|
{
|
||||||
|
static const number_format format(builtin_formats().at(16), 16);
|
||||||
|
return format;
|
||||||
|
}
|
||||||
|
|
||||||
|
const number_format number_format::date_xlsx17()
|
||||||
|
{
|
||||||
|
static const number_format format(builtin_formats().at(17), 17);
|
||||||
|
return format;
|
||||||
|
}
|
||||||
|
|
||||||
|
const number_format number_format::date_xlsx22()
|
||||||
|
{
|
||||||
|
static const number_format format(builtin_formats().at(22), 22);
|
||||||
|
return format;
|
||||||
|
}
|
||||||
|
|
||||||
|
const number_format number_format::date_datetime()
|
||||||
|
{
|
||||||
|
static const number_format format("yyyy-mm-dd h:mm:ss");
|
||||||
|
return format;
|
||||||
|
}
|
||||||
|
|
||||||
|
const number_format number_format::date_time1()
|
||||||
|
{
|
||||||
|
static const number_format format(builtin_formats().at(18), 18);
|
||||||
|
return format;
|
||||||
|
}
|
||||||
|
|
||||||
|
const number_format number_format::date_time2()
|
||||||
|
{
|
||||||
|
static const number_format format(builtin_formats().at(19), 19);
|
||||||
|
return format;
|
||||||
|
}
|
||||||
|
|
||||||
|
const number_format number_format::date_time3()
|
||||||
|
{
|
||||||
|
static const number_format format(builtin_formats().at(20), 20);
|
||||||
|
return format;
|
||||||
|
}
|
||||||
|
|
||||||
|
const number_format number_format::date_time4()
|
||||||
|
{
|
||||||
|
static const number_format format(builtin_formats().at(21), 21);
|
||||||
|
return format;
|
||||||
|
}
|
||||||
|
|
||||||
|
const number_format number_format::date_time5()
|
||||||
|
{
|
||||||
|
static const number_format format(builtin_formats().at(45), 45);
|
||||||
|
return format;
|
||||||
|
}
|
||||||
|
|
||||||
|
const number_format number_format::date_time6()
|
||||||
|
{
|
||||||
|
static const number_format format(builtin_formats().at(21), 21);
|
||||||
|
return format;
|
||||||
|
}
|
||||||
|
|
||||||
|
const number_format number_format::date_time7()
|
||||||
|
{
|
||||||
|
static const number_format format("i:s.S");
|
||||||
|
return format;
|
||||||
|
}
|
||||||
|
|
||||||
|
const number_format number_format::date_time8()
|
||||||
|
{
|
||||||
|
static const number_format format("h:mm:ss@");
|
||||||
|
return format;
|
||||||
|
}
|
||||||
|
|
||||||
|
const number_format number_format::date_timedelta()
|
||||||
|
{
|
||||||
|
static const number_format format("[hh]:mm:ss");
|
||||||
|
return format;
|
||||||
|
}
|
||||||
|
|
||||||
|
const number_format number_format::date_yyyymmddslash()
|
||||||
|
{
|
||||||
|
static const number_format format("yy/mm/dd@");
|
||||||
|
return format;
|
||||||
|
}
|
||||||
|
|
||||||
|
const number_format number_format::currency_usd_simple()
|
||||||
|
{
|
||||||
|
static const number_format format("\"$\"#,##0.00_-");
|
||||||
|
return format;
|
||||||
|
}
|
||||||
|
|
||||||
|
const number_format number_format::currency_usd()
|
||||||
|
{
|
||||||
|
static const number_format format("$#,##0_-");
|
||||||
|
return format;
|
||||||
|
}
|
||||||
|
|
||||||
|
const number_format number_format::currency_eur_simple()
|
||||||
|
{
|
||||||
|
static const number_format format("[$EUR ]#,##0.00_-");
|
||||||
|
return format;
|
||||||
|
}
|
||||||
|
|
||||||
|
number_format::number_format() : number_format(general())
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
number_format::number_format(format code) : format_code_(code), format_index_(0)
|
number_format::number_format(int id) : number_format(from_builtin_id(id))
|
||||||
{
|
{
|
||||||
set_format_code(code);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
number_format::number_format(const std::string &format_string) : number_format(format::general)
|
number_format::number_format(const std::string &format_string, int id)
|
||||||
{
|
{
|
||||||
set_format_string(format_string);
|
set_format_string(format_string, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
number_format::format number_format::lookup_format(int code)
|
number_format number_format::from_builtin_id(int builtin_id)
|
||||||
{
|
{
|
||||||
if(builtin_formats().find(code) == builtin_formats().end())
|
if(builtin_formats().find(builtin_id) == builtin_formats().end())
|
||||||
{
|
{
|
||||||
return format::unknown;
|
throw std::runtime_error("unknown id: " + std::to_string(builtin_id));
|
||||||
}
|
}
|
||||||
|
|
||||||
auto format_string = builtin_formats().at(code);
|
auto format_string = builtin_formats().at(builtin_id);
|
||||||
auto match = std::find_if(format_strings().begin(), format_strings().end(), [&](const std::pair<format, std::string> &p) { return p.second == format_string; });
|
return number_format(format_string, builtin_id);
|
||||||
|
|
||||||
if(match == format_strings().end())
|
|
||||||
{
|
|
||||||
return format::unknown;
|
|
||||||
}
|
|
||||||
|
|
||||||
return match->first;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string number_format::get_format_string() const
|
std::string number_format::get_format_string() const
|
||||||
|
@ -161,53 +301,30 @@ std::string number_format::get_format_string() const
|
||||||
return format_string_;
|
return format_string_;
|
||||||
}
|
}
|
||||||
|
|
||||||
number_format::format number_format::get_format_code() const
|
|
||||||
{
|
|
||||||
return format_code_;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::size_t number_format::hash() const
|
std::size_t number_format::hash() const
|
||||||
{
|
{
|
||||||
std::hash<std::string> hasher;
|
std::size_t seed = static_cast<std::size_t>(id_);
|
||||||
return hasher(format_string_);
|
hash_combine(seed, format_string_);
|
||||||
|
|
||||||
|
return seed;
|
||||||
}
|
}
|
||||||
|
|
||||||
void number_format::set_format_string(const std::string &format_string)
|
void number_format::set_format_string(const std::string &format_string, int id)
|
||||||
{
|
{
|
||||||
format_string_ = format_string;
|
format_string_ = format_string;
|
||||||
format_index_ = -1;
|
id_ = id;
|
||||||
format_code_ = format::unknown;
|
|
||||||
|
|
||||||
const auto &reversed = reversed_builtin_formats();
|
if(id_ == -1)
|
||||||
|
|
||||||
if(reversed.find(format_string) != reversed.end())
|
|
||||||
{
|
{
|
||||||
format_index_ = reversed.at(format_string);
|
for(const auto &pair : builtin_formats())
|
||||||
|
|
||||||
for(const auto &pair : format_strings())
|
|
||||||
{
|
{
|
||||||
if(pair.second == format_string)
|
if(pair.second == format_string)
|
||||||
{
|
{
|
||||||
format_code_ = pair.first;
|
id_ = pair.first;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void number_format::set_format_code(xlnt::number_format::format format_code)
|
|
||||||
{
|
|
||||||
format_code_ = format_code;
|
|
||||||
format_string_ = format_strings().at(format_code);
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
format_index_ = reversed_builtin_formats().at(format_string_);
|
|
||||||
}
|
|
||||||
catch(std::out_of_range)
|
|
||||||
{
|
|
||||||
format_index_ = -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace xlnt
|
} // namespace xlnt
|
||||||
|
|
|
@ -7,7 +7,7 @@ protection::protection() : protection(type::unprotected)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protection::protection(type t) : locked_(t), hidden_(type::inherit)
|
protection::protection(type t) : locked_(t), hidden_(type::unprotected)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,28 +18,91 @@ void hash_combine(std::size_t& seed, const T& v)
|
||||||
|
|
||||||
namespace xlnt {
|
namespace xlnt {
|
||||||
|
|
||||||
style::style()
|
const color color::black = color(color::type::indexed, 0);
|
||||||
|
const color color::white = color(color::type::indexed, 0);
|
||||||
|
|
||||||
|
style::style() :
|
||||||
|
id_(0),
|
||||||
|
alignment_apply_(false),
|
||||||
|
border_apply_(false),
|
||||||
|
border_id_(0),
|
||||||
|
fill_apply_(false),
|
||||||
|
fill_id_(0),
|
||||||
|
font_apply_(false),
|
||||||
|
font_id_(0),
|
||||||
|
number_format_apply_(false),
|
||||||
|
number_format_id_(0),
|
||||||
|
protection_apply_(false),
|
||||||
|
pivot_button_(false),
|
||||||
|
quote_prefix_(false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
style::style(const style &other) :
|
||||||
|
id_(other.id_),
|
||||||
|
alignment_(other.alignment_),
|
||||||
|
alignment_apply_(other.alignment_apply_),
|
||||||
|
border_(other.border_),
|
||||||
|
border_apply_(other.border_apply_),
|
||||||
|
border_id_(other.border_id_),
|
||||||
|
fill_(other.fill_),
|
||||||
|
fill_apply_(other.fill_apply_),
|
||||||
|
fill_id_(other.fill_id_),
|
||||||
|
font_(other.font_),
|
||||||
|
font_apply_(other.font_apply_),
|
||||||
|
font_id_(other.font_id_),
|
||||||
|
number_format_(other.number_format_),
|
||||||
|
number_format_apply_(other.number_format_apply_),
|
||||||
|
number_format_id_(other.number_format_id_),
|
||||||
|
protection_(other.protection_),
|
||||||
|
protection_apply_(other.protection_apply_),
|
||||||
|
pivot_button_(other.pivot_button_),
|
||||||
|
quote_prefix_(other.quote_prefix_)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
style &style::operator=(const style &other)
|
||||||
|
{
|
||||||
|
id_ = other.id_;
|
||||||
|
alignment_ = other.alignment_;
|
||||||
|
alignment_apply_ = other.alignment_apply_;
|
||||||
|
border_ = other.border_;
|
||||||
|
border_apply_ = other.border_apply_;
|
||||||
|
border_id_ = other.border_id_;
|
||||||
|
fill_ = other.fill_;
|
||||||
|
fill_apply_ = other.fill_apply_;
|
||||||
|
fill_id_ = other.fill_id_;
|
||||||
|
font_ = other.font_;
|
||||||
|
font_apply_ = other.font_apply_;
|
||||||
|
font_id_ = other.font_id_;
|
||||||
|
number_format_ = other.number_format_;
|
||||||
|
number_format_apply_ = other.number_format_apply_;
|
||||||
|
number_format_id_ = other.number_format_id_;
|
||||||
|
protection_ = other.protection_;
|
||||||
|
protection_apply_ = other.protection_apply_;
|
||||||
|
pivot_button_ = other.pivot_button_;
|
||||||
|
quote_prefix_ = other.quote_prefix_;
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
std::size_t style::hash() const
|
std::size_t style::hash() const
|
||||||
{
|
{
|
||||||
/*
|
std::size_t seed = 0;
|
||||||
std::size_t seed = 100;
|
if(alignment_apply_) hash_combine(seed, alignment_apply_);
|
||||||
std::hash<std::string> string_hash;
|
hash_combine(seed, alignment_.hash());
|
||||||
auto font_ = get_font();
|
hash_combine(seed, border_apply_);
|
||||||
hash_combine(seed, string_hash(font_.name_));
|
hash_combine(seed, border_id_);
|
||||||
hash_combine(seed, font_.size_);
|
hash_combine(seed, font_apply_);
|
||||||
hash_combine(seed, static_cast<std::size_t>(font_.underline_));
|
hash_combine(seed, font_id_);
|
||||||
std::size_t bools = font_.bold_;
|
hash_combine(seed, fill_apply_);
|
||||||
bools = bools << 1 & font_.italic_;
|
hash_combine(seed, fill_id_);
|
||||||
bools = bools << 1 & font_.strikethrough_;
|
hash_combine(seed, number_format_apply_);
|
||||||
bools = bools << 1 & font_.superscript_;
|
hash_combine(seed, number_format_id_);
|
||||||
bools = bools << 1 & font_.subscript_;
|
hash_combine(seed, protection_apply_);
|
||||||
hash_combine(seed, bools);
|
if(protection_apply_) hash_combine(seed, get_protection().hash());
|
||||||
*/
|
// hash_combine(seed, pivot_button_);
|
||||||
std::size_t seed = 100;
|
// hash_combine(seed, quote_prefix_);
|
||||||
hash_combine(seed, number_format_.hash());
|
|
||||||
|
|
||||||
return seed;
|
return seed;
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,9 +12,7 @@
|
||||||
#include <xlnt/common/relationship.hpp>
|
#include <xlnt/common/relationship.hpp>
|
||||||
#include <xlnt/common/zip_file.hpp>
|
#include <xlnt/common/zip_file.hpp>
|
||||||
#include <xlnt/drawing/drawing.hpp>
|
#include <xlnt/drawing/drawing.hpp>
|
||||||
#include <xlnt/reader/shared_strings_reader.hpp>
|
#include <xlnt/reader/excel_reader.hpp>
|
||||||
#include <xlnt/reader/workbook_reader.hpp>
|
|
||||||
#include <xlnt/reader/worksheet_reader.hpp>
|
|
||||||
#include <xlnt/styles/alignment.hpp>
|
#include <xlnt/styles/alignment.hpp>
|
||||||
#include <xlnt/styles/border.hpp>
|
#include <xlnt/styles/border.hpp>
|
||||||
#include <xlnt/styles/fill.hpp>
|
#include <xlnt/styles/fill.hpp>
|
||||||
|
@ -26,10 +24,7 @@
|
||||||
#include <xlnt/workbook/workbook.hpp>
|
#include <xlnt/workbook/workbook.hpp>
|
||||||
#include <xlnt/worksheet/range.hpp>
|
#include <xlnt/worksheet/range.hpp>
|
||||||
#include <xlnt/worksheet/worksheet.hpp>
|
#include <xlnt/worksheet/worksheet.hpp>
|
||||||
#include <xlnt/writer/style_writer.hpp>
|
#include <xlnt/writer/excel_writer.hpp>
|
||||||
#include <xlnt/writer/manifest_writer.hpp>
|
|
||||||
#include <xlnt/writer/worksheet_writer.hpp>
|
|
||||||
#include <xlnt/writer/workbook_writer.hpp>
|
|
||||||
|
|
||||||
#include "detail/cell_impl.hpp"
|
#include "detail/cell_impl.hpp"
|
||||||
#include "detail/include_pugixml.hpp"
|
#include "detail/include_pugixml.hpp"
|
||||||
|
@ -70,7 +65,7 @@ void hash_combine(std::size_t& seed, const T& v)
|
||||||
namespace xlnt {
|
namespace xlnt {
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
|
||||||
workbook_impl::workbook_impl() : active_sheet_index_(0), guess_types_(false), data_only_(false)
|
workbook_impl::workbook_impl() : active_sheet_index_(0), guess_types_(false), data_only_(false), next_custom_format_id_(164)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -277,121 +272,23 @@ range workbook::get_named_range(const std::string &name)
|
||||||
throw std::runtime_error("named range not found");
|
throw std::runtime_error("named range not found");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool workbook::load(const std::istream &stream)
|
bool workbook::load(std::istream &stream)
|
||||||
{
|
{
|
||||||
std::string temp_file = create_temporary_filename();
|
*this = excel_reader::load_workbook(stream);
|
||||||
|
|
||||||
std::ofstream tmp;
|
|
||||||
|
|
||||||
tmp.open(temp_file, std::ios::out | std::ios::binary);
|
|
||||||
tmp << stream.rdbuf();
|
|
||||||
tmp.close();
|
|
||||||
|
|
||||||
load(temp_file);
|
|
||||||
|
|
||||||
std::remove(temp_file.c_str());
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool workbook::load(const std::vector<unsigned char> &data)
|
bool workbook::load(const std::vector<unsigned char> &data)
|
||||||
{
|
{
|
||||||
xlnt::zip_file archive;
|
*this = excel_reader::load_workbook(data);
|
||||||
archive.load(data);
|
|
||||||
return load(archive);
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool workbook::load(const std::string &filename)
|
bool workbook::load(const std::string &filename)
|
||||||
{
|
{
|
||||||
zip_file f;
|
*this = excel_reader::load_workbook(filename);
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
f.load(filename);
|
|
||||||
}
|
|
||||||
catch(std::exception e)
|
|
||||||
{
|
|
||||||
throw invalid_file_exception(filename);
|
|
||||||
}
|
|
||||||
|
|
||||||
return load(f);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool workbook::load(xlnt::zip_file &archive)
|
|
||||||
{
|
|
||||||
auto content_types = read_content_types(archive);
|
|
||||||
auto type = determine_document_type(content_types);
|
|
||||||
|
|
||||||
if(type != "excel")
|
|
||||||
{
|
|
||||||
throw invalid_file_exception("");
|
|
||||||
}
|
|
||||||
|
|
||||||
clear();
|
|
||||||
|
|
||||||
auto workbook_relationships = read_relationships(archive, "xl/workbook.xml");
|
|
||||||
|
|
||||||
for(auto relationship : workbook_relationships)
|
|
||||||
{
|
|
||||||
create_relationship(relationship.get_id(), relationship.get_target_uri(), relationship.get_type());
|
|
||||||
}
|
|
||||||
|
|
||||||
pugi::xml_document doc;
|
|
||||||
doc.load(archive.read("xl/workbook.xml").c_str());
|
|
||||||
|
|
||||||
auto root_node = doc.child("workbook");
|
|
||||||
|
|
||||||
auto workbook_pr_node = root_node.child("workbookPr");
|
|
||||||
get_properties().excel_base_date = (workbook_pr_node.attribute("date1904") != nullptr && workbook_pr_node.attribute("date1904").as_int() != 0) ? calendar::mac_1904 : calendar::windows_1900;
|
|
||||||
|
|
||||||
auto sheets_node = root_node.child("sheets");
|
|
||||||
|
|
||||||
std::vector<std::string> shared_strings;
|
|
||||||
|
|
||||||
if(archive.has_file("xl/sharedStrings.xml"))
|
|
||||||
{
|
|
||||||
shared_strings = read_shared_strings(archive.read("xl/sharedStrings.xml"));
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<int> number_format_ids;
|
|
||||||
std::unordered_map<int, std::string> custom_number_formats;
|
|
||||||
|
|
||||||
if(archive.has_file("xl/styles.xml"))
|
|
||||||
{
|
|
||||||
pugi::xml_document styles_doc;
|
|
||||||
styles_doc.load(archive.read("xl/styles.xml").c_str());
|
|
||||||
auto stylesheet_node = styles_doc.child("styleSheet");
|
|
||||||
auto cell_xfs_node = stylesheet_node.child("cellXfs");
|
|
||||||
|
|
||||||
for(auto xf_node : cell_xfs_node.children("xf"))
|
|
||||||
{
|
|
||||||
number_format_ids.push_back(xf_node.attribute("numFmtId").as_int());
|
|
||||||
}
|
|
||||||
|
|
||||||
auto num_fmts_node = stylesheet_node.child("numFmts");
|
|
||||||
|
|
||||||
for(auto num_fmt_node : num_fmts_node.children("numFmt"))
|
|
||||||
{
|
|
||||||
custom_number_formats[num_fmt_node.attribute("numFmtId").as_int()] = num_fmt_node.attribute("formatCode").as_string();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for(auto sheet_node : sheets_node.children("sheet"))
|
|
||||||
{
|
|
||||||
std::string rel_id = sheet_node.attribute("r:id").as_string();
|
|
||||||
auto rel = std::find_if(d_->relationships_.begin(), d_->relationships_.end(),
|
|
||||||
[&](relationship &r) { return r.get_id() == rel_id; });
|
|
||||||
|
|
||||||
if (rel == d_->relationships_.end())
|
|
||||||
{
|
|
||||||
throw std::runtime_error("relationship not found");
|
|
||||||
}
|
|
||||||
|
|
||||||
auto ws = create_sheet(sheet_node.attribute("name").as_string(), *rel);
|
|
||||||
auto sheet_filename = rel->get_target_uri();
|
|
||||||
|
|
||||||
read_worksheet(ws, archive.read(sheet_filename).c_str(), shared_strings, number_format_ids, custom_number_formats);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -671,34 +568,24 @@ void workbook::set_data_only(bool data_only)
|
||||||
d_->data_only_ = data_only;
|
d_->data_only_ = data_only;
|
||||||
}
|
}
|
||||||
|
|
||||||
void workbook::add_border(xlnt::border /*b*/)
|
void workbook::add_border(const xlnt::border &border_)
|
||||||
{
|
{
|
||||||
|
d_->borders_.push_back(border_);
|
||||||
}
|
}
|
||||||
|
|
||||||
void workbook::add_alignment(xlnt::alignment /*a*/)
|
void workbook::add_fill(const fill &fill_)
|
||||||
{
|
{
|
||||||
|
d_->fills_.push_back(fill_);
|
||||||
}
|
}
|
||||||
|
|
||||||
void workbook::add_protection(xlnt::protection /*p*/)
|
void workbook::add_font(const font &font_)
|
||||||
{
|
{
|
||||||
|
d_->fonts_.push_back(font_);
|
||||||
}
|
}
|
||||||
|
|
||||||
void workbook::add_number_format(const std::string &/*format*/)
|
void workbook::add_number_format(const number_format &number_format_)
|
||||||
{
|
{
|
||||||
|
d_->number_formats_.push_back(number_format_);
|
||||||
}
|
|
||||||
|
|
||||||
void workbook::add_fill(xlnt::fill &/*f*/)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void workbook::add_font(xlnt::font /*f*/)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void workbook::set_code_name(const std::string &/*code_name*/)
|
void workbook::set_code_name(const std::string &/*code_name*/)
|
||||||
|
@ -731,19 +618,42 @@ std::vector<named_range> workbook::get_named_ranges() const
|
||||||
return named_ranges;
|
return named_ranges;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::size_t workbook::add_style(xlnt::style style_)
|
std::size_t workbook::add_style(const xlnt::style &style_)
|
||||||
{
|
{
|
||||||
return 1;
|
for(std::size_t i = 0; i < d_->styles_.size(); i++)
|
||||||
|
{
|
||||||
|
if(d_->styles_[i] == style_)
|
||||||
|
{
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
d_->styles_.push_back(style_);
|
||||||
|
|
||||||
|
return d_->styles_.size() - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
const number_format &workbook::get_number_format(std::size_t style_id) const
|
const number_format &workbook::get_number_format(std::size_t style_id) const
|
||||||
{
|
{
|
||||||
return d_->number_formats_[d_->styles_[style_id].number_format_index_];
|
auto number_format_id = d_->styles_[style_id].number_format_id_;
|
||||||
|
|
||||||
|
for(const auto &number_format_ : d_->number_formats_)
|
||||||
|
{
|
||||||
|
if(number_format_.get_id() == number_format_id)
|
||||||
|
{
|
||||||
|
return number_format_;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto nf = number_format::from_builtin_id(static_cast<int>(number_format_id));
|
||||||
|
d_->number_formats_.push_back(nf);
|
||||||
|
|
||||||
|
return d_->number_formats_.back();
|
||||||
}
|
}
|
||||||
|
|
||||||
const font &workbook::get_font(std::size_t style_id) const
|
const font &workbook::get_font(std::size_t style_id) const
|
||||||
{
|
{
|
||||||
return d_->fonts_[d_->styles_[style_id].font_index_];
|
return d_->fonts_[d_->styles_[style_id].font_id_];
|
||||||
}
|
}
|
||||||
|
|
||||||
std::size_t workbook::set_font(const font &font_, std::size_t style_id)
|
std::size_t workbook::set_font(const font &font_, std::size_t style_id)
|
||||||
|
@ -763,14 +673,14 @@ std::size_t workbook::set_font(const font &font_, std::size_t style_id)
|
||||||
|
|
||||||
auto existing_style = d_->styles_[style_id];
|
auto existing_style = d_->styles_[style_id];
|
||||||
|
|
||||||
if(font_index == existing_style.font_index_)
|
if(font_index == existing_style.font_id_)
|
||||||
{
|
{
|
||||||
// no change
|
// no change
|
||||||
return style_id;
|
return style_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto new_style = existing_style;
|
auto new_style = existing_style;
|
||||||
new_style.font_index_ = font_index;
|
new_style.font_id_ = font_index;
|
||||||
|
|
||||||
auto style_match = std::find(d_->styles_.begin(), d_->styles_.end(), new_style);
|
auto style_match = std::find(d_->styles_.begin(), d_->styles_.end(), new_style);
|
||||||
|
|
||||||
|
@ -786,7 +696,7 @@ std::size_t workbook::set_font(const font &font_, std::size_t style_id)
|
||||||
|
|
||||||
const fill &workbook::get_fill(std::size_t style_id) const
|
const fill &workbook::get_fill(std::size_t style_id) const
|
||||||
{
|
{
|
||||||
return d_->fills_[d_->styles_[style_id].fill_index_];
|
return d_->fills_[d_->styles_[style_id].fill_id_];
|
||||||
}
|
}
|
||||||
|
|
||||||
std::size_t workbook::set_fill(const fill &fill_, std::size_t style_id)
|
std::size_t workbook::set_fill(const fill &fill_, std::size_t style_id)
|
||||||
|
@ -796,7 +706,7 @@ std::size_t workbook::set_fill(const fill &fill_, std::size_t style_id)
|
||||||
|
|
||||||
const border &workbook::get_border(std::size_t style_id) const
|
const border &workbook::get_border(std::size_t style_id) const
|
||||||
{
|
{
|
||||||
return d_->borders_[d_->styles_[style_id].border_index_];
|
return d_->borders_[d_->styles_[style_id].border_id_];
|
||||||
}
|
}
|
||||||
|
|
||||||
std::size_t workbook::set_border(const border &border_, std::size_t style_id)
|
std::size_t workbook::set_border(const border &border_, std::size_t style_id)
|
||||||
|
@ -806,7 +716,7 @@ std::size_t workbook::set_border(const border &border_, std::size_t style_id)
|
||||||
|
|
||||||
const alignment &workbook::get_alignment(std::size_t style_id) const
|
const alignment &workbook::get_alignment(std::size_t style_id) const
|
||||||
{
|
{
|
||||||
return d_->alignments_[d_->styles_[style_id].alignment_index_];
|
return d_->styles_[style_id].alignment_;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::size_t workbook::set_alignment(const alignment &alignment_, std::size_t style_id)
|
std::size_t workbook::set_alignment(const alignment &alignment_, std::size_t style_id)
|
||||||
|
@ -816,7 +726,7 @@ std::size_t workbook::set_alignment(const alignment &alignment_, std::size_t sty
|
||||||
|
|
||||||
const protection &workbook::get_protection(std::size_t style_id) const
|
const protection &workbook::get_protection(std::size_t style_id) const
|
||||||
{
|
{
|
||||||
return d_->protections_[d_->styles_[style_id].number_format_index_];
|
return d_->styles_[style_id].protection_;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::size_t workbook::set_protection(const protection &protection_, std::size_t style_id)
|
std::size_t workbook::set_protection(const protection &protection_, std::size_t style_id)
|
||||||
|
@ -837,54 +747,84 @@ bool workbook::get_quote_prefix(std::size_t style_id) const
|
||||||
std::size_t workbook::set_number_format(const xlnt::number_format &format, std::size_t style_id)
|
std::size_t workbook::set_number_format(const xlnt::number_format &format, std::size_t style_id)
|
||||||
{
|
{
|
||||||
auto match = std::find(d_->number_formats_.begin(), d_->number_formats_.end(), format);
|
auto match = std::find(d_->number_formats_.begin(), d_->number_formats_.end(), format);
|
||||||
auto format_index = 0;
|
std::size_t format_id = 0;
|
||||||
|
|
||||||
if(match == d_->number_formats_.end())
|
if(match == d_->number_formats_.end())
|
||||||
{
|
{
|
||||||
d_->number_formats_.push_back(format);
|
d_->number_formats_.push_back(format);
|
||||||
format_index = d_->number_formats_.size() - 1;
|
|
||||||
|
if(format.get_id() == -1)
|
||||||
|
{
|
||||||
|
d_->number_formats_.back().set_id(d_->next_custom_format_id_++);
|
||||||
|
}
|
||||||
|
|
||||||
|
format_id = d_->number_formats_.back().get_id();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
format_index = match - d_->number_formats_.begin();
|
format_id = match->get_id();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(d_->styles_.empty())
|
if(d_->styles_.empty())
|
||||||
{
|
{
|
||||||
style new_style;
|
style new_style;
|
||||||
new_style.style_index_ = 0;
|
|
||||||
new_style.alignment_index_ = 0;
|
new_style.id_ = 0;
|
||||||
new_style.border_index_ = 0;
|
new_style.border_id_ = 0;
|
||||||
new_style.fill_index_ = 0;
|
new_style.fill_id_ = 0;
|
||||||
new_style.font_index_ = 0;
|
new_style.font_id_ = 0;
|
||||||
new_style.number_format_index_ = format_index;
|
new_style.number_format_id_ = format_id;
|
||||||
new_style.protection_index_ = 0;
|
new_style.number_format_apply_ = true;
|
||||||
|
|
||||||
|
if(d_->borders_.empty())
|
||||||
|
{
|
||||||
|
d_->borders_.push_back(new_style.get_border());
|
||||||
|
}
|
||||||
|
|
||||||
|
if(d_->fills_.empty())
|
||||||
|
{
|
||||||
|
d_->fills_.push_back(new_style.get_fill());
|
||||||
|
}
|
||||||
|
|
||||||
|
if(d_->fonts_.empty())
|
||||||
|
{
|
||||||
|
d_->fonts_.push_back(new_style.get_font());
|
||||||
|
}
|
||||||
|
|
||||||
d_->styles_.push_back(new_style);
|
d_->styles_.push_back(new_style);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If the style is unchanged, just return it.
|
||||||
auto existing_style = d_->styles_[style_id];
|
auto existing_style = d_->styles_[style_id];
|
||||||
|
existing_style.number_format_apply_ = true;
|
||||||
|
|
||||||
if(format_index == existing_style.number_format_index_)
|
if(format_id == existing_style.number_format_id_)
|
||||||
{
|
{
|
||||||
// no change
|
// no change
|
||||||
return style_id;
|
return style_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Make a new style with this format.
|
||||||
auto new_style = existing_style;
|
auto new_style = existing_style;
|
||||||
new_style.number_format_index_ = format_index;
|
|
||||||
|
new_style.number_format_id_ = format_id;
|
||||||
new_style.number_format_ = format;
|
new_style.number_format_ = format;
|
||||||
|
|
||||||
|
// Check if the new style is already applied to a different cell. If so, reuse it.
|
||||||
auto style_match = std::find(d_->styles_.begin(), d_->styles_.end(), new_style);
|
auto style_match = std::find(d_->styles_.begin(), d_->styles_.end(), new_style);
|
||||||
|
|
||||||
if(style_match != d_->styles_.end())
|
if(style_match != d_->styles_.end())
|
||||||
{
|
{
|
||||||
return style_match - d_->styles_.begin();
|
return style_match->get_id();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// No match found, so add it.
|
||||||
|
new_style.id_ = d_->styles_.size();
|
||||||
d_->styles_.push_back(new_style);
|
d_->styles_.push_back(new_style);
|
||||||
|
|
||||||
return d_->styles_.size() - 1;
|
return new_style.id_;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<style> workbook::get_styles() const
|
std::vector<style> workbook::get_styles() const
|
||||||
|
@ -902,4 +842,14 @@ std::vector<font> workbook::get_fonts() const
|
||||||
return d_->fonts_;
|
return d_->fonts_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<border> workbook::get_borders() const
|
||||||
|
{
|
||||||
|
return d_->borders_;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<fill> workbook::get_fills() const
|
||||||
|
{
|
||||||
|
return d_->fills_;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace xlnt
|
} // namespace xlnt
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#include <xlnt/cell/cell.hpp>
|
#include <xlnt/cell/cell.hpp>
|
||||||
#include <xlnt/cell/cell_reference.hpp>
|
#include <xlnt/cell/cell_reference.hpp>
|
||||||
|
#include <xlnt/common/zip_file.hpp>
|
||||||
#include <xlnt/reader/worksheet_reader.hpp>
|
#include <xlnt/reader/worksheet_reader.hpp>
|
||||||
#include <xlnt/styles/number_format.hpp>
|
#include <xlnt/styles/number_format.hpp>
|
||||||
#include <xlnt/workbook/workbook.hpp>
|
#include <xlnt/workbook/workbook.hpp>
|
||||||
|
@ -10,8 +11,17 @@
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
void read_worksheet_common(xlnt::worksheet ws, const pugi::xml_node &root_node, const std::vector<std::string> &string_table, const std::vector<int> &number_format_ids, const std::unordered_map<int, std::string> &custom_number_formats)
|
} // namespace
|
||||||
|
|
||||||
|
namespace xlnt {
|
||||||
|
|
||||||
|
void read_worksheet(worksheet ws, zip_file &archive, const relationship &rel, const std::vector<std::string> &string_table)
|
||||||
{
|
{
|
||||||
|
pugi::xml_document doc;
|
||||||
|
doc.load(archive.read(rel.get_target_uri()).c_str());
|
||||||
|
|
||||||
|
auto root_node = doc.child("worksheet");
|
||||||
|
|
||||||
auto dimension_node = root_node.child("dimension");
|
auto dimension_node = root_node.child("dimension");
|
||||||
std::string dimension = dimension_node.attribute("ref").as_string();
|
std::string dimension = dimension_node.attribute("ref").as_string();
|
||||||
auto full_range = xlnt::range_reference(dimension);
|
auto full_range = xlnt::range_reference(dimension);
|
||||||
|
@ -62,85 +72,59 @@ void read_worksheet_common(xlnt::worksheet ws, const pugi::xml_node &root_node,
|
||||||
if(cell_node != nullptr)
|
if(cell_node != nullptr)
|
||||||
{
|
{
|
||||||
bool has_value = cell_node.child("v") != nullptr;
|
bool has_value = cell_node.child("v") != nullptr;
|
||||||
std::string value_string = cell_node.child("v").text().as_string();
|
std::string value_string = has_value ? cell_node.child("v").text().as_string() : "";
|
||||||
|
|
||||||
bool has_type = cell_node.attribute("t") != nullptr;
|
bool has_type = cell_node.attribute("t") != nullptr;
|
||||||
std::string type = cell_node.attribute("t").as_string();
|
std::string type = has_type ? cell_node.attribute("t").as_string() : "";
|
||||||
|
|
||||||
bool has_style = cell_node.attribute("s") != nullptr;
|
bool has_style = cell_node.attribute("s") != nullptr;
|
||||||
std::string style = cell_node.attribute("s").as_string();
|
int style_id = has_style ? cell_node.attribute("s").as_int() : 0;
|
||||||
|
|
||||||
bool has_formula = cell_node.child("f") != nullptr;
|
bool has_formula = cell_node.child("f") != nullptr;
|
||||||
bool shared_formula = has_formula && cell_node.child("f").attribute("t") != nullptr && std::string(cell_node.child("f").attribute("t").as_string()) == "shared";
|
bool has_shared_formula = has_formula && cell_node.child("f").attribute("t") != nullptr && std::string(cell_node.child("f").attribute("t").as_string()) == "shared";
|
||||||
|
|
||||||
if(has_formula && !shared_formula && !ws.get_parent().get_data_only())
|
auto cell = ws.get_cell(address);
|
||||||
|
|
||||||
|
if(has_formula && !has_shared_formula && !ws.get_parent().get_data_only())
|
||||||
{
|
{
|
||||||
std::string formula = cell_node.child("f").text().as_string();
|
std::string formula = cell_node.child("f").text().as_string();
|
||||||
ws.get_cell(address).set_formula(formula);
|
cell.set_formula(formula);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(has_type && type == "inlineStr") // inline string
|
if(has_type && type == "inlineStr") // inline string
|
||||||
{
|
{
|
||||||
std::string inline_string = cell_node.child("is").child("t").text().as_string();
|
std::string inline_string = cell_node.child("is").child("t").text().as_string();
|
||||||
ws.get_cell(address).set_value(inline_string);
|
cell.set_value(inline_string);
|
||||||
}
|
}
|
||||||
else if(has_type && type == "s" && !has_formula) // shared string
|
else if(has_type && type == "s" && !has_formula) // shared string
|
||||||
{
|
{
|
||||||
auto shared_string_index = std::stoll(value_string);
|
auto shared_string_index = std::stoull(value_string);
|
||||||
auto shared_string = string_table.at(static_cast<std::size_t>(shared_string_index));
|
auto shared_string = string_table.at(shared_string_index);
|
||||||
ws.get_cell(address).set_value(shared_string);
|
cell.set_value(shared_string);
|
||||||
}
|
}
|
||||||
else if(has_type && type == "b") // boolean
|
else if(has_type && type == "b") // boolean
|
||||||
{
|
{
|
||||||
ws.get_cell(address).set_value(value_string != "0");
|
cell.set_value(value_string != "0");
|
||||||
}
|
}
|
||||||
else if(has_type && type == "str")
|
else if(has_type && type == "str")
|
||||||
{
|
{
|
||||||
ws.get_cell(address).set_value(value_string);
|
cell.set_value(value_string);
|
||||||
}
|
}
|
||||||
else if(has_value)
|
else if(has_value)
|
||||||
{
|
{
|
||||||
try
|
if(!value_string.empty() && value_string[0] == '#')
|
||||||
{
|
{
|
||||||
ws.get_cell(address).set_value(std::stold(value_string));
|
cell.set_error(value_string);
|
||||||
}
|
}
|
||||||
catch(std::invalid_argument)
|
else
|
||||||
{
|
{
|
||||||
ws.get_cell(address).set_value(value_string);
|
cell.set_value(std::stold(value_string));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(has_style)
|
if(has_style)
|
||||||
{
|
{
|
||||||
auto style_index = static_cast<std::size_t>(std::stoll(style));
|
cell.set_style_id(style_id);
|
||||||
|
|
||||||
if(number_format_ids.size() > style_index)
|
|
||||||
{
|
|
||||||
auto number_format_id = number_format_ids.at(style_index);
|
|
||||||
auto format = xlnt::number_format::lookup_format(number_format_id);
|
|
||||||
|
|
||||||
if(format == xlnt::number_format::format::unknown)
|
|
||||||
{
|
|
||||||
auto match = custom_number_formats.find(number_format_id);
|
|
||||||
|
|
||||||
if(match != custom_number_formats.end())
|
|
||||||
{
|
|
||||||
xlnt::number_format nf(match->second);
|
|
||||||
auto cell = ws.get_cell(address);
|
|
||||||
cell.set_number_format(nf);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
xlnt::number_format nf(format);
|
|
||||||
auto cell = ws.get_cell(address);
|
|
||||||
cell.set_number_format(nf);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ws.get_cell(address).set_number_format(xlnt::number_format(xlnt::number_format::format::general));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -155,32 +139,4 @@ void read_worksheet_common(xlnt::worksheet ws, const pugi::xml_node &root_node,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
namespace xlnt {
|
|
||||||
|
|
||||||
void read_worksheet(worksheet ws, const std::string &xml_string, const std::vector<std::string> &string_table, const std::vector<int> &number_format_ids, const std::unordered_map<int, std::string> &custom_number_formats)
|
|
||||||
{
|
|
||||||
pugi::xml_document doc;
|
|
||||||
doc.load(xml_string.c_str());
|
|
||||||
read_worksheet_common(ws, doc.child("worksheet"), string_table, number_format_ids, custom_number_formats);
|
|
||||||
}
|
|
||||||
|
|
||||||
void read_worksheet(worksheet ws, std::istream &stream, const std::vector<std::string> &string_table, const std::vector<int> &number_format_ids, const std::unordered_map<int, std::string> &custom_number_formats)
|
|
||||||
{
|
|
||||||
pugi::xml_document doc;
|
|
||||||
doc.load(stream);
|
|
||||||
read_worksheet_common(ws, doc.child("worksheet"), string_table, number_format_ids, custom_number_formats);
|
|
||||||
}
|
|
||||||
|
|
||||||
worksheet read_worksheet(std::istream &handle, xlnt::workbook &wb, const std::string &title, const std::vector<std::string> &string_table, const std::unordered_map<int, std::string> &custom_number_formats)
|
|
||||||
{
|
|
||||||
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, {}, custom_number_formats);
|
|
||||||
return ws;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace xlnt
|
} // namespace xlnt
|
||||||
|
|
145
source/writer/excel_writer.cpp
Normal file
145
source/writer/excel_writer.cpp
Normal file
|
@ -0,0 +1,145 @@
|
||||||
|
#include <unordered_set>
|
||||||
|
|
||||||
|
#include <xlnt/cell/cell.hpp>
|
||||||
|
#include <xlnt/cell/cell_reference.hpp>
|
||||||
|
#include <xlnt/common/zip_file.hpp>
|
||||||
|
#include <xlnt/workbook/workbook.hpp>
|
||||||
|
#include <xlnt/worksheet/range.hpp>
|
||||||
|
#include <xlnt/worksheet/range_reference.hpp>
|
||||||
|
#include <xlnt/worksheet/worksheet.hpp>
|
||||||
|
#include <xlnt/writer/excel_writer.hpp>
|
||||||
|
#include <xlnt/writer/manifest_writer.hpp>
|
||||||
|
#include <xlnt/writer/workbook_writer.hpp>
|
||||||
|
#include <xlnt/writer/worksheet_writer.hpp>
|
||||||
|
|
||||||
|
#include "detail/constants.hpp"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
std::vector<std::string> extract_all_strings(xlnt::workbook &wb)
|
||||||
|
{
|
||||||
|
std::unordered_set<std::string> strings;
|
||||||
|
|
||||||
|
for(auto ws : wb)
|
||||||
|
{
|
||||||
|
for(auto row : ws.rows())
|
||||||
|
{
|
||||||
|
for(auto cell : row)
|
||||||
|
{
|
||||||
|
if(cell.get_data_type() == xlnt::cell::type::string)
|
||||||
|
{
|
||||||
|
strings.insert(cell.get_value<std::string>());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::vector<std::string>(strings.begin(), strings.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
namespace xlnt {
|
||||||
|
|
||||||
|
excel_writer::excel_writer(workbook &wb) : wb_(wb)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void excel_writer::save(const std::string &filename, bool as_template)
|
||||||
|
{
|
||||||
|
zip_file archive;
|
||||||
|
write_data(archive, as_template);
|
||||||
|
archive.save(filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
void excel_writer::write_data(zip_file &archive, bool as_template)
|
||||||
|
{
|
||||||
|
archive.writestr(constants::ArcRootRels, write_root_rels(wb_));
|
||||||
|
archive.writestr(constants::ArcWorkbookRels, write_workbook_rels(wb_));
|
||||||
|
archive.writestr(constants::ArcApp, write_properties_app(wb_));
|
||||||
|
archive.writestr(constants::ArcCore, write_properties_core(wb_.get_properties()));
|
||||||
|
|
||||||
|
if(wb_.has_loaded_theme())
|
||||||
|
{
|
||||||
|
archive.writestr(constants::ArcTheme, wb_.get_loaded_theme());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
archive.writestr(constants::ArcTheme, write_theme());
|
||||||
|
}
|
||||||
|
|
||||||
|
archive.writestr(constants::ArcWorkbook, write_workbook(wb_));
|
||||||
|
|
||||||
|
auto shared_strings = extract_all_strings(wb_);
|
||||||
|
|
||||||
|
write_charts(archive);
|
||||||
|
write_images(archive);
|
||||||
|
write_shared_strings(archive, shared_strings);
|
||||||
|
write_worksheets(archive, shared_strings);
|
||||||
|
write_chartsheets(archive);
|
||||||
|
write_external_links(archive);
|
||||||
|
|
||||||
|
style_writer style_writer_(wb_);
|
||||||
|
archive.writestr(constants::ArcStyles, style_writer_.write_table());
|
||||||
|
|
||||||
|
auto manifest = write_content_types(wb_, as_template);
|
||||||
|
archive.writestr(constants::ArcContentTypes, manifest);
|
||||||
|
}
|
||||||
|
|
||||||
|
void excel_writer::write_shared_strings(xlnt::zip_file &archive, const std::vector<std::string> &shared_strings)
|
||||||
|
{
|
||||||
|
archive.writestr(constants::ArcSharedString, ::xlnt::write_shared_strings(shared_strings));
|
||||||
|
}
|
||||||
|
|
||||||
|
void excel_writer::write_images(zip_file &/*archive*/)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void excel_writer::write_charts(zip_file &/*archive*/)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void excel_writer::write_chartsheets(zip_file &/*archive*/)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void excel_writer::write_worksheets(zip_file &archive, const std::vector<std::string> &shared_strings)
|
||||||
|
{
|
||||||
|
for(auto relationship : wb_.get_relationships())
|
||||||
|
{
|
||||||
|
if(relationship.get_type() == relationship::type::worksheet)
|
||||||
|
{
|
||||||
|
auto sheet_index = workbook::index_from_ws_filename(relationship.get_target_uri());
|
||||||
|
auto ws = wb_.get_sheet_by_index(sheet_index);
|
||||||
|
archive.writestr(relationship.get_target_uri(), write_worksheet(ws, shared_strings));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void excel_writer::write_external_links(zip_file &/*archive*/)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool save_workbook(workbook &wb, const std::string &filename, bool as_template)
|
||||||
|
{
|
||||||
|
excel_writer writer(wb);
|
||||||
|
writer.save(filename, as_template);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::uint8_t> save_virtual_workbook(xlnt::workbook &wb, bool as_template)
|
||||||
|
{
|
||||||
|
zip_file archive;
|
||||||
|
excel_writer writer(wb);
|
||||||
|
writer.write_data(archive, as_template);
|
||||||
|
std::vector<std::uint8_t> buffer;
|
||||||
|
archive.save(buffer);
|
||||||
|
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace xlnt
|
|
@ -33,21 +33,10 @@ std::string style_writer::write_table() const
|
||||||
auto num_fmts = wb_.get_number_formats();
|
auto num_fmts = wb_.get_number_formats();
|
||||||
num_fmts_node.append_attribute("count").set_value(static_cast<int>(num_fmts.size()));
|
num_fmts_node.append_attribute("count").set_value(static_cast<int>(num_fmts.size()));
|
||||||
|
|
||||||
int custom_index = 164;
|
|
||||||
|
|
||||||
for(auto &num_fmt : num_fmts)
|
for(auto &num_fmt : num_fmts)
|
||||||
{
|
{
|
||||||
auto num_fmt_node = num_fmts_node.append_child("numFmt");
|
auto num_fmt_node = num_fmts_node.append_child("numFmt");
|
||||||
|
num_fmt_node.append_attribute("numFmtId").set_value(num_fmt.get_id());
|
||||||
if(num_fmt.get_format_code() == number_format::format::unknown)
|
|
||||||
{
|
|
||||||
num_fmt_node.append_attribute("numFmtId").set_value(custom_index++);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
num_fmt_node.append_attribute("numFmtId").set_value(num_fmt.get_format_index());
|
|
||||||
}
|
|
||||||
|
|
||||||
num_fmt_node.append_attribute("formatCode").set_value(num_fmt.get_format_string().c_str());
|
num_fmt_node.append_attribute("formatCode").set_value(num_fmt.get_format_string().c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,16 +52,35 @@ std::string style_writer::write_table() const
|
||||||
for(auto &f : fonts)
|
for(auto &f : fonts)
|
||||||
{
|
{
|
||||||
auto font_node = fonts_node.append_child("font");
|
auto font_node = fonts_node.append_child("font");
|
||||||
|
|
||||||
auto size_node = font_node.append_child("sz");
|
auto size_node = font_node.append_child("sz");
|
||||||
size_node.append_attribute("val").set_value(f.get_size());
|
size_node.append_attribute("val").set_value(f.get_size());
|
||||||
|
|
||||||
auto color_node = font_node.append_child("color");
|
auto color_node = font_node.append_child("color");
|
||||||
color_node.append_attribute("theme").set_value(1);
|
|
||||||
|
if(f.get_color().get_type() == color::type::indexed)
|
||||||
|
{
|
||||||
|
color_node.append_attribute("indexed").set_value(static_cast<unsigned int>(f.get_color().get_index()));
|
||||||
|
}
|
||||||
|
else if(f.get_color().get_type() == color::type::theme)
|
||||||
|
{
|
||||||
|
color_node.append_attribute("theme").set_value(static_cast<unsigned int>(f.get_color().get_theme()));
|
||||||
|
}
|
||||||
|
|
||||||
auto name_node = font_node.append_child("name");
|
auto name_node = font_node.append_child("name");
|
||||||
name_node.append_attribute("val").set_value(f.get_name().c_str());
|
name_node.append_attribute("val").set_value(f.get_name().c_str());
|
||||||
|
|
||||||
|
if(f.has_family())
|
||||||
|
{
|
||||||
auto family_node = font_node.append_child("family");
|
auto family_node = font_node.append_child("family");
|
||||||
family_node.append_attribute("val").set_value(2);
|
family_node.append_attribute("val").set_value(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(f.has_scheme())
|
||||||
|
{
|
||||||
auto scheme_node = font_node.append_child("scheme");
|
auto scheme_node = font_node.append_child("scheme");
|
||||||
scheme_node.append_attribute("val").set_value("minor");
|
scheme_node.append_attribute("val").set_value("minor");
|
||||||
|
}
|
||||||
|
|
||||||
if(f.is_bold())
|
if(f.is_bold())
|
||||||
{
|
{
|
||||||
|
@ -82,53 +90,323 @@ std::string style_writer::write_table() const
|
||||||
}
|
}
|
||||||
|
|
||||||
auto fills_node = style_sheet_node.append_child("fills");
|
auto fills_node = style_sheet_node.append_child("fills");
|
||||||
fills_node.append_attribute("count").set_value(2);
|
const auto &fills = wb_.get_fills();
|
||||||
fills_node.append_child("fill").append_child("patternFill").append_attribute("patternType").set_value("none");
|
fills_node.append_attribute("count").set_value(static_cast<unsigned int>(fills.size()));
|
||||||
fills_node.append_child("fill").append_child("patternFill").append_attribute("patternType").set_value("gray125");
|
|
||||||
|
for(auto &fill_ : fills)
|
||||||
|
{
|
||||||
|
auto fill_node = fills_node.append_child("fill");
|
||||||
|
|
||||||
|
if(fill_.get_type() == fill::type::pattern)
|
||||||
|
{
|
||||||
|
auto pattern_fill_node = fill_node.append_child("patternFill");
|
||||||
|
auto type_string = fill_.get_pattern_type_string();
|
||||||
|
pattern_fill_node.append_attribute("patternType").set_value(type_string.c_str());
|
||||||
|
|
||||||
|
if(fill_.has_foreground_color())
|
||||||
|
{
|
||||||
|
auto fg_color_node = pattern_fill_node.append_child("fgColor");
|
||||||
|
|
||||||
|
switch(fill_.get_foreground_color().get_type())
|
||||||
|
{
|
||||||
|
case color::type::auto_: fg_color_node.append_attribute("auto").set_value(fill_.get_foreground_color().get_auto()); break;
|
||||||
|
case color::type::theme: fg_color_node.append_attribute("theme").set_value(fill_.get_foreground_color().get_theme()); break;
|
||||||
|
case color::type::indexed: fg_color_node.append_attribute("indexed").set_value(fill_.get_foreground_color().get_index()); break;
|
||||||
|
default: throw std::runtime_error("bad type");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(fill_.has_background_color())
|
||||||
|
{
|
||||||
|
auto bg_color_node = pattern_fill_node.append_child("bgColor");
|
||||||
|
|
||||||
|
switch(fill_.get_background_color().get_type())
|
||||||
|
{
|
||||||
|
case color::type::auto_: bg_color_node.append_attribute("auto").set_value(fill_.get_background_color().get_auto()); break;
|
||||||
|
case color::type::theme: bg_color_node.append_attribute("theme").set_value(fill_.get_background_color().get_theme()); break;
|
||||||
|
case color::type::indexed: bg_color_node.append_attribute("indexed").set_value(fill_.get_background_color().get_index()); break;
|
||||||
|
default: throw std::runtime_error("bad type");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
auto borders_node = style_sheet_node.append_child("borders");
|
auto borders_node = style_sheet_node.append_child("borders");
|
||||||
borders_node.append_attribute("count").set_value(1);
|
const auto &borders = wb_.get_borders();
|
||||||
|
borders_node.append_attribute("count").set_value(static_cast<unsigned int>(borders.size()));
|
||||||
|
|
||||||
|
for(const auto &border_ : borders)
|
||||||
|
{
|
||||||
auto border_node = borders_node.append_child("border");
|
auto border_node = borders_node.append_child("border");
|
||||||
border_node.append_child("left");
|
|
||||||
border_node.append_child("right");
|
if(border_.left_assigned)
|
||||||
border_node.append_child("top");
|
{
|
||||||
border_node.append_child("bottom");
|
auto left_node = border_node.append_child("left");
|
||||||
border_node.append_child("diagonal");
|
|
||||||
|
if(border_.left.is_style_assigned())
|
||||||
|
{
|
||||||
|
auto style_attribute = left_node.append_attribute("style");
|
||||||
|
|
||||||
|
switch(border_.left.get_style())
|
||||||
|
{
|
||||||
|
case border_style::none: style_attribute.set_value("none"); break;
|
||||||
|
case border_style::thin: style_attribute.set_value("thin"); break;
|
||||||
|
default: throw std::runtime_error("invalid style");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(border_.left.is_color_assigned())
|
||||||
|
{
|
||||||
|
auto color_node = left_node.append_child("color");
|
||||||
|
|
||||||
|
if(border_.left.get_color_type() == side::color_type::indexed)
|
||||||
|
{
|
||||||
|
color_node.append_attribute("indexed").set_value((int)border_.left.get_color());
|
||||||
|
}
|
||||||
|
else if(border_.diagonal.get_color_type() == side::color_type::theme)
|
||||||
|
{
|
||||||
|
color_node.append_attribute("indexed").set_value((int)border_.left.get_color());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw std::runtime_error("invalid color type");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(border_.right_assigned)
|
||||||
|
{
|
||||||
|
auto right_node = border_node.append_child("right");
|
||||||
|
|
||||||
|
if(border_.right.is_style_assigned())
|
||||||
|
{
|
||||||
|
auto style_attribute = right_node.append_attribute("style");
|
||||||
|
|
||||||
|
switch(border_.right.get_style())
|
||||||
|
{
|
||||||
|
case border_style::none: style_attribute.set_value("none"); break;
|
||||||
|
case border_style::thin: style_attribute.set_value("thin"); break;
|
||||||
|
default: throw std::runtime_error("invalid style");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(border_.right.is_color_assigned())
|
||||||
|
{
|
||||||
|
auto color_node = right_node.append_child("color");
|
||||||
|
|
||||||
|
if(border_.right.get_color_type() == side::color_type::indexed)
|
||||||
|
{
|
||||||
|
color_node.append_attribute("indexed").set_value((int)border_.right.get_color());
|
||||||
|
}
|
||||||
|
else if(border_.diagonal.get_color_type() == side::color_type::theme)
|
||||||
|
{
|
||||||
|
color_node.append_attribute("indexed").set_value((int)border_.right.get_color());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw std::runtime_error("invalid color type");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(border_.top_assigned)
|
||||||
|
{
|
||||||
|
auto top_node = border_node.append_child("top");
|
||||||
|
|
||||||
|
if(border_.top.is_style_assigned())
|
||||||
|
{
|
||||||
|
auto style_attribute = top_node.append_attribute("style");
|
||||||
|
|
||||||
|
switch(border_.top.get_style())
|
||||||
|
{
|
||||||
|
case border_style::none: style_attribute.set_value("none"); break;
|
||||||
|
case border_style::thin: style_attribute.set_value("thin"); break;
|
||||||
|
default: throw std::runtime_error("invalid style");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(border_.top.is_color_assigned())
|
||||||
|
{
|
||||||
|
auto color_node = top_node.append_child("color");
|
||||||
|
if(border_.top.get_color_type() == side::color_type::indexed)
|
||||||
|
{
|
||||||
|
color_node.append_attribute("indexed").set_value((int)border_.top.get_color());
|
||||||
|
}
|
||||||
|
else if(border_.diagonal.get_color_type() == side::color_type::theme)
|
||||||
|
{
|
||||||
|
color_node.append_attribute("indexed").set_value((int)border_.top.get_color());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw std::runtime_error("invalid color type");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(border_.bottom_assigned)
|
||||||
|
{
|
||||||
|
auto bottom_node = border_node.append_child("bottom");
|
||||||
|
|
||||||
|
if(border_.bottom.is_style_assigned())
|
||||||
|
{
|
||||||
|
auto style_attribute = bottom_node.append_attribute("style");
|
||||||
|
|
||||||
|
switch(border_.bottom.get_style())
|
||||||
|
{
|
||||||
|
case border_style::none: style_attribute.set_value("none"); break;
|
||||||
|
case border_style::thin: style_attribute.set_value("thin"); break;
|
||||||
|
default: throw std::runtime_error("invalid style");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(border_.bottom.is_color_assigned())
|
||||||
|
{
|
||||||
|
auto color_node = bottom_node.append_child("color");
|
||||||
|
|
||||||
|
if(border_.bottom.get_color_type() == side::color_type::indexed)
|
||||||
|
{
|
||||||
|
color_node.append_attribute("indexed").set_value((int)border_.bottom.get_color());
|
||||||
|
}
|
||||||
|
else if(border_.diagonal.get_color_type() == side::color_type::theme)
|
||||||
|
{
|
||||||
|
color_node.append_attribute("indexed").set_value((int)border_.bottom.get_color());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw std::runtime_error("invalid color type");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(border_.diagonal_assigned)
|
||||||
|
{
|
||||||
|
auto diagonal_node = border_node.append_child("diagonal");
|
||||||
|
|
||||||
|
if(border_.diagonal.is_style_assigned())
|
||||||
|
{
|
||||||
|
auto style_attribute = diagonal_node.append_attribute("style");
|
||||||
|
|
||||||
|
switch(border_.diagonal.get_style())
|
||||||
|
{
|
||||||
|
case border_style::none: style_attribute.set_value("none"); break;
|
||||||
|
case border_style::thin: style_attribute.set_value("thin"); break;
|
||||||
|
default: throw std::runtime_error("invalid style");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(border_.diagonal.is_color_assigned())
|
||||||
|
{
|
||||||
|
auto color_node = diagonal_node.append_child("color");
|
||||||
|
|
||||||
|
if(border_.diagonal.get_color_type() == side::color_type::indexed)
|
||||||
|
{
|
||||||
|
color_node.append_attribute("indexed").set_value((int)border_.diagonal.get_color());
|
||||||
|
}
|
||||||
|
else if(border_.diagonal.get_color_type() == side::color_type::theme)
|
||||||
|
{
|
||||||
|
color_node.append_attribute("indexed").set_value((int)border_.diagonal.get_color());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw std::runtime_error("invalid color type");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
auto cell_style_xfs_node = style_sheet_node.append_child("cellStyleXfs");
|
auto cell_style_xfs_node = style_sheet_node.append_child("cellStyleXfs");
|
||||||
cell_style_xfs_node.append_attribute("count").set_value(1);
|
cell_style_xfs_node.append_attribute("count").set_value(1);
|
||||||
auto xf_node = cell_style_xfs_node.append_child("xf");
|
auto style_xf_node = cell_style_xfs_node.append_child("xf");
|
||||||
xf_node.append_attribute("numFmtId").set_value(0);
|
style_xf_node.append_attribute("numFmtId").set_value(0);
|
||||||
xf_node.append_attribute("fontId").set_value(0);
|
style_xf_node.append_attribute("fontId").set_value(0);
|
||||||
xf_node.append_attribute("fillId").set_value(0);
|
style_xf_node.append_attribute("fillId").set_value(0);
|
||||||
xf_node.append_attribute("borderId").set_value(0);
|
style_xf_node.append_attribute("borderId").set_value(0);
|
||||||
|
|
||||||
auto cell_xfs_node = style_sheet_node.append_child("cellXfs");
|
auto cell_xfs_node = style_sheet_node.append_child("cellXfs");
|
||||||
const auto &styles = wb_.get_styles();
|
const auto &styles = wb_.get_styles();
|
||||||
cell_xfs_node.append_attribute("count").set_value(static_cast<int>(styles.size()));
|
cell_xfs_node.append_attribute("count").set_value(static_cast<int>(styles.size()));
|
||||||
|
|
||||||
custom_index = 164;
|
|
||||||
|
|
||||||
for(auto &style : styles)
|
for(auto &style : styles)
|
||||||
{
|
{
|
||||||
xf_node = cell_xfs_node.append_child("xf");
|
auto xf_node = cell_xfs_node.append_child("xf");
|
||||||
if(style.get_number_format().get_format_code() == number_format::format::unknown)
|
xf_node.append_attribute("numFmtId").set_value(style.get_number_format().get_id());
|
||||||
{
|
xf_node.append_attribute("fontId").set_value((int)style.get_font_id());
|
||||||
xf_node.append_attribute("numFmtId").set_value(custom_index++);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
xf_node.append_attribute("numFmtId").set_value(style.get_number_format().get_format_index());
|
|
||||||
}
|
|
||||||
xf_node.append_attribute("applyNumberFormat").set_value(1);
|
|
||||||
xf_node.append_attribute("fontId").set_value((int)style.get_font_index());
|
|
||||||
xf_node.append_attribute("fillId").set_value((int)style.get_fill_index());
|
|
||||||
xf_node.append_attribute("borderId").set_value((int)style.get_border_index());
|
|
||||||
|
|
||||||
|
if(style.fill_apply_)
|
||||||
|
{
|
||||||
|
xf_node.append_attribute("fillId").set_value((int)style.get_fill_id());
|
||||||
|
}
|
||||||
|
|
||||||
|
if(style.border_apply_)
|
||||||
|
{
|
||||||
|
xf_node.append_attribute("borderId").set_value((int)style.get_border_id());
|
||||||
|
}
|
||||||
|
|
||||||
|
xf_node.append_attribute("applyNumberFormat").set_value(style.number_format_apply_ ? 1 : 0);
|
||||||
|
xf_node.append_attribute("applyFont").set_value(style.font_apply_ ? 1 : 0);
|
||||||
|
xf_node.append_attribute("applyFill").set_value(style.fill_apply_ ? 1 : 0);
|
||||||
|
xf_node.append_attribute("applyBorder").set_value(style.border_apply_ ? 1 : 0);
|
||||||
|
xf_node.append_attribute("applyAlignment").set_value(style.alignment_apply_ ? 1 : 0);
|
||||||
|
xf_node.append_attribute("applyProtection").set_value(style.protection_apply_ ? 1 : 0);
|
||||||
|
|
||||||
|
if(style.alignment_apply_)
|
||||||
|
{
|
||||||
auto alignment_node = xf_node.append_child("alignment");
|
auto alignment_node = xf_node.append_child("alignment");
|
||||||
|
|
||||||
|
if(style.alignment_.has_vertical())
|
||||||
|
{
|
||||||
|
switch(style.alignment_.get_vertical())
|
||||||
|
{
|
||||||
|
case alignment::vertical_alignment::bottom:
|
||||||
|
alignment_node.append_attribute("vertical").set_value("bottom");
|
||||||
|
break;
|
||||||
|
case alignment::vertical_alignment::center:
|
||||||
|
alignment_node.append_attribute("vertical").set_value("center");
|
||||||
|
break;
|
||||||
|
case alignment::vertical_alignment::justify:
|
||||||
|
alignment_node.append_attribute("vertical").set_value("justify");
|
||||||
|
break;
|
||||||
|
case alignment::vertical_alignment::top:
|
||||||
alignment_node.append_attribute("vertical").set_value("top");
|
alignment_node.append_attribute("vertical").set_value("top");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw std::runtime_error("invalid alignment");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(style.alignment_.has_horizontal())
|
||||||
|
{
|
||||||
|
switch(style.alignment_.get_horizontal())
|
||||||
|
{
|
||||||
|
case alignment::horizontal_alignment::center:
|
||||||
|
alignment_node.append_attribute("horizontal").set_value("center");
|
||||||
|
break;
|
||||||
|
case alignment::horizontal_alignment::center_continuous:
|
||||||
|
alignment_node.append_attribute("horizontal").set_value("center_continuous");
|
||||||
|
break;
|
||||||
|
case alignment::horizontal_alignment::general:
|
||||||
|
alignment_node.append_attribute("horizontal").set_value("general");
|
||||||
|
break;
|
||||||
|
case alignment::horizontal_alignment::justify:
|
||||||
|
alignment_node.append_attribute("horizontal").set_value("justify");
|
||||||
|
break;
|
||||||
|
case alignment::horizontal_alignment::left:
|
||||||
|
alignment_node.append_attribute("horizontal").set_value("left");
|
||||||
|
break;
|
||||||
|
case alignment::horizontal_alignment::right:
|
||||||
|
alignment_node.append_attribute("horizontal").set_value("right");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw std::runtime_error("invalid alignment");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(style.alignment_.get_wrap_text())
|
||||||
|
{
|
||||||
alignment_node.append_attribute("wrapText").set_value(1);
|
alignment_node.append_attribute("wrapText").set_value(1);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
auto cell_styles_node = style_sheet_node.append_child("cellStyles");
|
auto cell_styles_node = style_sheet_node.append_child("cellStyles");
|
||||||
cell_styles_node.append_attribute("count").set_value(1);
|
cell_styles_node.append_attribute("count").set_value(1);
|
||||||
|
@ -144,6 +422,30 @@ std::string style_writer::write_table() const
|
||||||
table_styles_node.append_attribute("defaultTableStyle").set_value("TableStyleMedium2");
|
table_styles_node.append_attribute("defaultTableStyle").set_value("TableStyleMedium2");
|
||||||
table_styles_node.append_attribute("defaultPivotStyle").set_value("PivotStyleMedium9");
|
table_styles_node.append_attribute("defaultPivotStyle").set_value("PivotStyleMedium9");
|
||||||
|
|
||||||
|
auto colors_node = style_sheet_node.append_child("colors");
|
||||||
|
auto indexed_colors_node = colors_node.append_child("indexedColors");
|
||||||
|
|
||||||
|
const std::vector<std::string> colors =
|
||||||
|
{
|
||||||
|
"ff000000",
|
||||||
|
"ffffffff",
|
||||||
|
"ffff0000",
|
||||||
|
"ff00ff00",
|
||||||
|
"ff0000ff",
|
||||||
|
"ffffff00",
|
||||||
|
"ffff00ff",
|
||||||
|
"ff00ffff",
|
||||||
|
"ff000000",
|
||||||
|
"ffaaaaaa",
|
||||||
|
"ffbdc0bf",
|
||||||
|
"ffdbdbdb"
|
||||||
|
};
|
||||||
|
|
||||||
|
for(auto &color : colors)
|
||||||
|
{
|
||||||
|
indexed_colors_node.append_child("rgbColor").append_attribute("rgb").set_value(color.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
auto ext_list_node = style_sheet_node.append_child("extLst");
|
auto ext_list_node = style_sheet_node.append_child("extLst");
|
||||||
auto ext_node = ext_list_node.append_child("ext");
|
auto ext_node = ext_list_node.append_child("ext");
|
||||||
ext_node.append_attribute("uri").set_value("{EB79DEF2-80B8-43e5-95BD-54CBDDF9020C}");
|
ext_node.append_attribute("uri").set_value("{EB79DEF2-80B8-43e5-95BD-54CBDDF9020C}");
|
||||||
|
|
|
@ -41,121 +41,6 @@ std::string datetime_to_w3cdtf(const xlnt::datetime &dt)
|
||||||
|
|
||||||
namespace xlnt {
|
namespace xlnt {
|
||||||
|
|
||||||
excel_writer::excel_writer(workbook &wb) : wb_(wb), style_writer_(wb_)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void excel_writer::save(const std::string &filename, bool as_template)
|
|
||||||
{
|
|
||||||
zip_file archive;
|
|
||||||
write_data(archive, as_template);
|
|
||||||
archive.save(filename);
|
|
||||||
}
|
|
||||||
|
|
||||||
void excel_writer::write_data(zip_file &archive, bool as_template)
|
|
||||||
{
|
|
||||||
archive.writestr(constants::ArcRootRels, write_root_rels(wb_));
|
|
||||||
archive.writestr(constants::ArcWorkbookRels, write_workbook_rels(wb_));
|
|
||||||
archive.writestr(constants::ArcApp, write_properties_app(wb_));
|
|
||||||
archive.writestr(constants::ArcCore, write_properties_core(wb_.get_properties()));
|
|
||||||
|
|
||||||
if(wb_.has_loaded_theme())
|
|
||||||
{
|
|
||||||
archive.writestr(constants::ArcTheme, wb_.get_loaded_theme());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
archive.writestr(constants::ArcTheme, write_theme());
|
|
||||||
}
|
|
||||||
|
|
||||||
archive.writestr(constants::ArcWorkbook, write_workbook(wb_));
|
|
||||||
|
|
||||||
/*
|
|
||||||
if(wb_.has_vba_archive())
|
|
||||||
{
|
|
||||||
auto &vba_archive = wb_.get_vba_archive();
|
|
||||||
|
|
||||||
for(auto name : vba_archive.namelist())
|
|
||||||
{
|
|
||||||
for(auto s : constants::ArcVba)
|
|
||||||
{
|
|
||||||
if(match(s, name))
|
|
||||||
{
|
|
||||||
archive.writestr(name, vba_archive.read(name));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
write_charts(archive);
|
|
||||||
write_images(archive);
|
|
||||||
write_string_table(archive);
|
|
||||||
write_worksheets(archive);
|
|
||||||
write_chartsheets(archive);
|
|
||||||
write_external_links(archive);
|
|
||||||
|
|
||||||
archive.writestr(constants::ArcStyles, style_writer_.write_table());
|
|
||||||
auto manifest = write_content_types(wb_, as_template);
|
|
||||||
archive.writestr(constants::ArcContentTypes, manifest);
|
|
||||||
}
|
|
||||||
|
|
||||||
void excel_writer::write_string_table(zip_file &archive)
|
|
||||||
{
|
|
||||||
std::set<std::string> shared_strings_set;
|
|
||||||
|
|
||||||
for(auto ws : wb_)
|
|
||||||
{
|
|
||||||
for(auto row : ws.rows())
|
|
||||||
{
|
|
||||||
for(auto cell : row)
|
|
||||||
{
|
|
||||||
if(cell.get_data_type() == cell::type::string)
|
|
||||||
{
|
|
||||||
shared_strings_set.insert(cell.get_value<std::string>());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
shared_strings_.assign(shared_strings_set.begin(), shared_strings_set.end());
|
|
||||||
archive.writestr(constants::ArcSharedString, write_shared_strings(shared_strings_));
|
|
||||||
}
|
|
||||||
|
|
||||||
void excel_writer::write_images(zip_file &/*archive*/)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void excel_writer::write_charts(zip_file &/*archive*/)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void excel_writer::write_chartsheets(zip_file &/*archive*/)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void excel_writer::write_worksheets(zip_file &archive)
|
|
||||||
{
|
|
||||||
for(auto relationship : wb_.get_relationships())
|
|
||||||
{
|
|
||||||
if(relationship.get_type() == relationship::type::worksheet)
|
|
||||||
{
|
|
||||||
auto sheet_index = workbook::index_from_ws_filename(relationship.get_target_uri());
|
|
||||||
auto ws = wb_.get_sheet_by_index(sheet_index);
|
|
||||||
archive.writestr(relationship.get_target_uri(), write_worksheet(ws, shared_strings_));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void excel_writer::write_external_links(zip_file &/*archive*/)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string write_shared_strings(const std::vector<std::string> &string_table)
|
std::string write_shared_strings(const std::vector<std::string> &string_table)
|
||||||
{
|
{
|
||||||
pugi::xml_document doc;
|
pugi::xml_document doc;
|
||||||
|
@ -713,22 +598,4 @@ std::string write_defined_names(const xlnt::workbook &wb)
|
||||||
return stream.str();
|
return stream.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool save_workbook(workbook &wb, const std::string &filename, bool as_template)
|
|
||||||
{
|
|
||||||
excel_writer writer(wb);
|
|
||||||
writer.save(filename, as_template);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<std::uint8_t> save_virtual_workbook(xlnt::workbook &wb, bool as_template)
|
|
||||||
{
|
|
||||||
zip_file archive;
|
|
||||||
excel_writer writer(wb);
|
|
||||||
writer.write_data(archive, as_template);
|
|
||||||
std::vector<std::uint8_t> buffer;
|
|
||||||
archive.save(buffer);
|
|
||||||
|
|
||||||
return buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace xlnt
|
} // namespace xlnt
|
||||||
|
|
|
@ -264,11 +264,14 @@ std::string write_worksheet(worksheet ws, const std::vector<std::string> &string
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//if(cell.has_style())
|
||||||
|
{
|
||||||
auto style_id = cell.get_style_id();
|
auto style_id = cell.get_style_id();
|
||||||
cell_node.append_attribute("s").set_value((int)style_id);
|
cell_node.append_attribute("s").set_value((int)style_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(ws.has_auto_filter())
|
if(ws.has_auto_filter())
|
||||||
{
|
{
|
||||||
|
|
|
@ -9,18 +9,19 @@
|
||||||
#include <xlnt/cell/comment.hpp>
|
#include <xlnt/cell/comment.hpp>
|
||||||
#include <xlnt/common/datetime.hpp>
|
#include <xlnt/common/datetime.hpp>
|
||||||
#include <xlnt/common/exceptions.hpp>
|
#include <xlnt/common/exceptions.hpp>
|
||||||
#include <xlnt/reader/workbook_reader.hpp>
|
|
||||||
#include <xlnt/styles/alignment.hpp>
|
#include <xlnt/styles/alignment.hpp>
|
||||||
#include <xlnt/styles/border.hpp>
|
#include <xlnt/styles/border.hpp>
|
||||||
#include <xlnt/styles/font.hpp>
|
#include <xlnt/styles/font.hpp>
|
||||||
#include <xlnt/styles/fill.hpp>
|
#include <xlnt/styles/fill.hpp>
|
||||||
#include <xlnt/styles/pattern_fill.hpp>
|
|
||||||
#include <xlnt/styles/number_format.hpp>
|
#include <xlnt/styles/number_format.hpp>
|
||||||
#include <xlnt/styles/protection.hpp>
|
#include <xlnt/styles/protection.hpp>
|
||||||
#include <xlnt/worksheet/range.hpp>
|
#include <xlnt/worksheet/range.hpp>
|
||||||
#include <xlnt/worksheet/worksheet.hpp>
|
#include <xlnt/worksheet/worksheet.hpp>
|
||||||
#include <xlnt/workbook/workbook.hpp>
|
#include <xlnt/workbook/workbook.hpp>
|
||||||
|
|
||||||
|
#include <xlnt/writer/excel_writer.hpp>
|
||||||
|
#include <xlnt/reader/excel_reader.hpp>
|
||||||
|
|
||||||
class test_cell : public CxxTest::TestSuite
|
class test_cell : public CxxTest::TestSuite
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
@ -32,6 +33,13 @@ public:
|
||||||
wb_guess_types.set_guess_types(true);
|
wb_guess_types.set_guess_types(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void test_debug()
|
||||||
|
{
|
||||||
|
xlnt::workbook wb;
|
||||||
|
wb.load("/Users/thomas/Development/xlnt/samples/sample1.xlsx");
|
||||||
|
wb.save("/Users/thomas/Development/xlnt/bin/sample1-out.xlsx");
|
||||||
|
}
|
||||||
|
|
||||||
void test_infer_numeric()
|
void test_infer_numeric()
|
||||||
{
|
{
|
||||||
auto ws = wb_guess_types.create_sheet();
|
auto ws = wb_guess_types.create_sheet();
|
||||||
|
@ -394,14 +402,14 @@ public:
|
||||||
|
|
||||||
void _test_fill()
|
void _test_fill()
|
||||||
{
|
{
|
||||||
xlnt::pattern_fill fill;
|
xlnt::fill f;
|
||||||
fill.set_pattern_type("solid");
|
f.set_type(xlnt::fill::type::solid);
|
||||||
fill.set_foreground_color("FF0000");
|
// f.set_foreground_color("FF0000");
|
||||||
auto ws = wb.create_sheet();
|
auto ws = wb.create_sheet();
|
||||||
ws.get_parent().add_fill(fill);
|
ws.get_parent().add_fill(f);
|
||||||
|
|
||||||
xlnt::cell cell(ws, "A1");
|
xlnt::cell cell(ws, "A1");
|
||||||
TS_ASSERT(cell.get_fill() == fill);
|
TS_ASSERT(cell.get_fill() == f);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _test_border()
|
void _test_border()
|
||||||
|
@ -417,7 +425,7 @@ public:
|
||||||
void _test_number_format()
|
void _test_number_format()
|
||||||
{
|
{
|
||||||
auto ws = wb.create_sheet();
|
auto ws = wb.create_sheet();
|
||||||
ws.get_parent().add_number_format("dd--hh--mm");
|
ws.get_parent().add_number_format(xlnt::number_format("dd--hh--mm"));
|
||||||
|
|
||||||
xlnt::cell cell(ws, "A1");
|
xlnt::cell cell(ws, "A1");
|
||||||
cell.set_number_format(xlnt::number_format("dd--hh--mm"));
|
cell.set_number_format(xlnt::number_format("dd--hh--mm"));
|
||||||
|
@ -439,7 +447,7 @@ public:
|
||||||
void _test_protection()
|
void _test_protection()
|
||||||
{
|
{
|
||||||
xlnt::protection prot;
|
xlnt::protection prot;
|
||||||
prot.set_locked(false);
|
prot.set_locked(xlnt::protection::type::protected_);
|
||||||
|
|
||||||
auto ws = wb.create_sheet();
|
auto ws = wb.create_sheet();
|
||||||
ws.get_parent().add_protection(prot);
|
ws.get_parent().add_protection(prot);
|
||||||
|
|
|
@ -14,28 +14,11 @@
|
||||||
class test_read : public CxxTest::TestSuite
|
class test_read : public CxxTest::TestSuite
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
void test_read_standalone_worksheet()
|
|
||||||
{
|
|
||||||
auto path = PathHelper::GetDataDirectory("/reader/sheet2.xml");
|
|
||||||
xlnt::workbook wb;
|
|
||||||
xlnt::worksheet ws(wb);
|
|
||||||
{
|
|
||||||
std::ifstream handle(path);
|
|
||||||
ws = xlnt::read_worksheet(handle, wb, "Sheet 2", {"hello"}, {});
|
|
||||||
}
|
|
||||||
TS_ASSERT_DIFFERS(ws, nullptr);
|
|
||||||
if(!(ws == nullptr))
|
|
||||||
{
|
|
||||||
TS_ASSERT_EQUALS(ws.get_cell("G5").get_value<std::string>(), "hello");
|
|
||||||
TS_ASSERT_EQUALS(ws.get_cell("D30").get_value<int>(), 30);
|
|
||||||
TS_ASSERT_EQUALS(ws.get_cell("K9").get_value<double>(), 0.09);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
xlnt::workbook standard_workbook()
|
xlnt::workbook standard_workbook()
|
||||||
{
|
{
|
||||||
auto path = PathHelper::GetDataDirectory("/genuine/empty.xlsx");
|
auto path = PathHelper::GetDataDirectory("/genuine/empty.xlsx");
|
||||||
return xlnt::load_workbook(path);
|
return xlnt::excel_reader::load_workbook(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_read_standard_workbook()
|
void test_read_standard_workbook()
|
||||||
|
@ -47,7 +30,7 @@ public:
|
||||||
{
|
{
|
||||||
auto path = PathHelper::GetDataDirectory("/genuine/empty.xlsx");
|
auto path = PathHelper::GetDataDirectory("/genuine/empty.xlsx");
|
||||||
std::ifstream fo(path, std::ios::binary);
|
std::ifstream fo(path, std::ios::binary);
|
||||||
auto wb = xlnt::load_workbook(path);
|
auto wb = xlnt::excel_reader::load_workbook(path);
|
||||||
TS_ASSERT_DIFFERS(standard_workbook(), nullptr);
|
TS_ASSERT_DIFFERS(standard_workbook(), nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,58 +48,58 @@ public:
|
||||||
void test_read_nostring_workbook()
|
void test_read_nostring_workbook()
|
||||||
{
|
{
|
||||||
auto path = PathHelper::GetDataDirectory("/genuine/empty-no-string.xlsx");
|
auto path = PathHelper::GetDataDirectory("/genuine/empty-no-string.xlsx");
|
||||||
auto wb = xlnt::load_workbook(path);
|
auto wb = xlnt::excel_reader::load_workbook(path);
|
||||||
TS_ASSERT_DIFFERS(standard_workbook(), nullptr);
|
TS_ASSERT_DIFFERS(standard_workbook(), nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_read_empty_file()
|
void test_read_empty_file()
|
||||||
{
|
{
|
||||||
auto path = PathHelper::GetDataDirectory("/reader/null_file.xlsx");
|
auto path = PathHelper::GetDataDirectory("/reader/null_file.xlsx");
|
||||||
TS_ASSERT_THROWS(xlnt::load_workbook(path), xlnt::invalid_file_exception);
|
TS_ASSERT_THROWS(xlnt::excel_reader::load_workbook(path), xlnt::invalid_file_exception);
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_read_empty_archive()
|
void test_read_empty_archive()
|
||||||
{
|
{
|
||||||
auto path = PathHelper::GetDataDirectory("/reader/null_archive.xlsx");
|
auto path = PathHelper::GetDataDirectory("/reader/null_archive.xlsx");
|
||||||
TS_ASSERT_THROWS(xlnt::load_workbook(path), xlnt::invalid_file_exception);
|
TS_ASSERT_THROWS(xlnt::excel_reader::load_workbook(path), xlnt::invalid_file_exception);
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_read_workbook_with_no_properties()
|
void test_read_workbook_with_no_properties()
|
||||||
{
|
{
|
||||||
auto path = PathHelper::GetDataDirectory("/genuine/empty_with_no_properties.xlsx");
|
auto path = PathHelper::GetDataDirectory("/genuine/empty_with_no_properties.xlsx");
|
||||||
xlnt::load_workbook(path);
|
xlnt::excel_reader::load_workbook(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
xlnt::workbook workbook_with_styles()
|
xlnt::workbook workbook_with_styles()
|
||||||
{
|
{
|
||||||
auto path = PathHelper::GetDataDirectory("/genuine/empty-with-styles.xlsx");
|
auto path = PathHelper::GetDataDirectory("/genuine/empty-with-styles.xlsx");
|
||||||
return xlnt::load_workbook(path);
|
return xlnt::excel_reader::load_workbook(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_read_workbook_with_styles_general()
|
void test_read_workbook_with_styles_general()
|
||||||
{
|
{
|
||||||
auto wb = workbook_with_styles();
|
auto wb = workbook_with_styles();
|
||||||
auto ws = wb["Sheet1"];
|
auto ws = wb["Sheet1"];
|
||||||
auto code = ws.get_cell("A1").get_number_format().get_format_code();
|
auto format = ws.get_cell("A1").get_number_format();
|
||||||
auto expected = xlnt::number_format::format::general;
|
auto expected = xlnt::number_format::general();
|
||||||
TS_ASSERT_EQUALS(code, expected);
|
TS_ASSERT_EQUALS(format, expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_read_workbook_with_styles_date()
|
void test_read_workbook_with_styles_date()
|
||||||
{
|
{
|
||||||
auto wb = workbook_with_styles();
|
auto wb = workbook_with_styles();
|
||||||
auto ws = wb["Sheet1"];
|
auto ws = wb["Sheet1"];
|
||||||
auto code = ws.get_cell("A2").get_number_format().get_format_code();
|
auto format = ws.get_cell("A2").get_number_format();
|
||||||
auto expected = xlnt::number_format::format::date_xlsx14;
|
auto expected = xlnt::number_format::date_xlsx14();
|
||||||
TS_ASSERT_EQUALS(code, expected);
|
TS_ASSERT_EQUALS(format, expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_read_workbook_with_styles_number()
|
void test_read_workbook_with_styles_number()
|
||||||
{
|
{
|
||||||
auto wb = workbook_with_styles();
|
auto wb = workbook_with_styles();
|
||||||
auto ws = wb["Sheet1"];
|
auto ws = wb["Sheet1"];
|
||||||
auto code = ws.get_cell("A3").get_number_format().get_format_code();
|
auto code = ws.get_cell("A3").get_number_format();
|
||||||
auto expected = xlnt::number_format::format::number_00;
|
auto expected = xlnt::number_format::number_00();
|
||||||
TS_ASSERT_EQUALS(code, expected);
|
TS_ASSERT_EQUALS(code, expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -124,8 +107,8 @@ public:
|
||||||
{
|
{
|
||||||
auto wb = workbook_with_styles();
|
auto wb = workbook_with_styles();
|
||||||
auto ws = wb["Sheet1"];
|
auto ws = wb["Sheet1"];
|
||||||
auto code = ws.get_cell("A4").get_number_format().get_format_code();
|
auto code = ws.get_cell("A4").get_number_format();
|
||||||
auto expected = xlnt::number_format::format::date_time3;
|
auto expected = xlnt::number_format::date_time3();
|
||||||
TS_ASSERT_EQUALS(code, expected);
|
TS_ASSERT_EQUALS(code, expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -133,21 +116,21 @@ public:
|
||||||
{
|
{
|
||||||
auto wb = workbook_with_styles();
|
auto wb = workbook_with_styles();
|
||||||
auto ws = wb["Sheet1"];
|
auto ws = wb["Sheet1"];
|
||||||
auto code = ws.get_cell("A5").get_number_format().get_format_code();
|
auto code = ws.get_cell("A5").get_number_format();
|
||||||
auto expected = xlnt::number_format::format::percentage_00;
|
auto expected = xlnt::number_format::percentage_00();
|
||||||
TS_ASSERT_EQUALS(code, expected);
|
TS_ASSERT_EQUALS(code, expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
xlnt::workbook date_mac_1904()
|
xlnt::workbook date_mac_1904()
|
||||||
{
|
{
|
||||||
auto path = PathHelper::GetDataDirectory("/reader/date_1904.xlsx");
|
auto path = PathHelper::GetDataDirectory("/reader/date_1904.xlsx");
|
||||||
return xlnt::load_workbook(path);
|
return xlnt::excel_reader::load_workbook(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
xlnt::workbook date_std_1900()
|
xlnt::workbook date_std_1900()
|
||||||
{
|
{
|
||||||
auto path = PathHelper::GetDataDirectory("/reader/date_1900.xlsx");
|
auto path = PathHelper::GetDataDirectory("/reader/date_1900.xlsx");
|
||||||
return xlnt::load_workbook(path);
|
return xlnt::excel_reader::load_workbook(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_read_win_base_date()
|
void test_read_win_base_date()
|
||||||
|
@ -166,14 +149,14 @@ public:
|
||||||
{
|
{
|
||||||
auto wb = date_std_1900();
|
auto wb = date_std_1900();
|
||||||
auto ws = wb["Sheet1"];
|
auto ws = wb["Sheet1"];
|
||||||
TS_ASSERT_EQUALS(ws.get_cell("A1").get_number_format().get_format_code(), xlnt::number_format::format::date_xlsx14);
|
TS_ASSERT_EQUALS(ws.get_cell("A1").get_number_format(), xlnt::number_format::date_xlsx14());
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_read_date_style_mac()
|
void test_read_date_style_mac()
|
||||||
{
|
{
|
||||||
auto wb = date_mac_1904();
|
auto wb = date_mac_1904();
|
||||||
auto ws = wb["Sheet1"];
|
auto ws = wb["Sheet1"];
|
||||||
TS_ASSERT_EQUALS(ws.get_cell("A1").get_number_format().get_format_code(), xlnt::number_format::format::date_xlsx14);
|
TS_ASSERT_EQUALS(ws.get_cell("A1").get_number_format(), xlnt::number_format::date_xlsx14());
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_read_compare_mac_win_dates()
|
void test_read_compare_mac_win_dates()
|
||||||
|
@ -190,40 +173,23 @@ public:
|
||||||
|
|
||||||
void test_repair_central_directory()
|
void test_repair_central_directory()
|
||||||
{
|
{
|
||||||
std::string data_a = "foobarbaz" + xlnt::CentralDirectorySignature();
|
std::string data_a = "foobarbaz" + xlnt::excel_reader::CentralDirectorySignature();
|
||||||
std::string data_b = "bazbarfoo12345678901234567890";
|
std::string data_b = "bazbarfoo12345678901234567890";
|
||||||
|
|
||||||
auto f = xlnt::repair_central_directory(data_a + data_b);
|
auto f = xlnt::excel_reader::repair_central_directory(data_a + data_b);
|
||||||
TS_ASSERT_EQUALS(f, data_a + data_b.substr(0, 18));
|
TS_ASSERT_EQUALS(f, data_a + data_b.substr(0, 18));
|
||||||
|
|
||||||
f = xlnt::repair_central_directory(data_b);
|
f = xlnt::excel_reader::repair_central_directory(data_b);
|
||||||
TS_ASSERT_EQUALS(f, data_b);
|
TS_ASSERT_EQUALS(f, data_b);
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_read_no_theme()
|
void test_read_no_theme()
|
||||||
{
|
{
|
||||||
auto path = PathHelper::GetDataDirectory("/genuine/libreoffice_nrt.xlsx");
|
auto path = PathHelper::GetDataDirectory("/genuine/libreoffice_nrt.xlsx");
|
||||||
auto wb = xlnt::load_workbook(path);
|
auto wb = xlnt::excel_reader::load_workbook(path);
|
||||||
TS_ASSERT_DIFFERS(wb, nullptr);
|
TS_ASSERT_DIFFERS(wb, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_read_cell_formulae()
|
|
||||||
{
|
|
||||||
xlnt::workbook wb;
|
|
||||||
auto ws = wb.get_active_sheet();
|
|
||||||
auto path = PathHelper::GetDataDirectory("/reader/worksheet_formula.xml");
|
|
||||||
std::ifstream ws_stream(path);
|
|
||||||
xlnt::read_worksheet(ws, ws_stream, { "string", "string2" }, {}, {});
|
|
||||||
|
|
||||||
auto b1 = ws.get_cell("B1");
|
|
||||||
TS_ASSERT(b1.has_formula());
|
|
||||||
TS_ASSERT_EQUALS(b1.get_formula(), "CONCATENATE(A1,A2)");
|
|
||||||
|
|
||||||
auto a6 = ws.get_cell("A6");
|
|
||||||
TS_ASSERT(a6.has_formula());
|
|
||||||
TS_ASSERT_EQUALS(a6.get_formula(), "SUM(A4:A5)");
|
|
||||||
}
|
|
||||||
|
|
||||||
void _test_read_complex_formulae()
|
void _test_read_complex_formulae()
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
|
@ -284,7 +250,7 @@ public:
|
||||||
void test_data_only()
|
void test_data_only()
|
||||||
{
|
{
|
||||||
auto path = PathHelper::GetDataDirectory("/reader/formulae.xlsx");
|
auto path = PathHelper::GetDataDirectory("/reader/formulae.xlsx");
|
||||||
auto wb = xlnt::load_workbook(path, false, true);
|
auto wb = xlnt::excel_reader::load_workbook(path, false, true);
|
||||||
auto ws = wb.get_active_sheet();
|
auto ws = wb.get_active_sheet();
|
||||||
|
|
||||||
TS_ASSERT(ws.get_formula_attributes().empty());
|
TS_ASSERT(ws.get_formula_attributes().empty());
|
||||||
|
@ -448,7 +414,7 @@ public:
|
||||||
{
|
{
|
||||||
std::tie(guess, dtype) = expected;
|
std::tie(guess, dtype) = expected;
|
||||||
auto path = PathHelper::GetDataDirectory("/genuine/guess_types.xlsx");
|
auto path = PathHelper::GetDataDirectory("/genuine/guess_types.xlsx");
|
||||||
auto wb = xlnt::load_workbook(path, guess);
|
auto wb = xlnt::excel_reader::load_workbook(path, guess);
|
||||||
auto ws = wb.get_active_sheet();
|
auto ws = wb.get_active_sheet();
|
||||||
TS_ASSERT(ws.get_cell("D2").get_data_type() == dtype);
|
TS_ASSERT(ws.get_cell("D2").get_data_type() == dtype);
|
||||||
}
|
}
|
||||||
|
@ -457,7 +423,7 @@ public:
|
||||||
void test_read_autofilter()
|
void test_read_autofilter()
|
||||||
{
|
{
|
||||||
auto path = PathHelper::GetDataDirectory("/reader/bug275.xlsx");
|
auto path = PathHelper::GetDataDirectory("/reader/bug275.xlsx");
|
||||||
auto wb = xlnt::load_workbook(path);
|
auto wb = xlnt::excel_reader::load_workbook(path);
|
||||||
auto ws = wb.get_active_sheet();
|
auto ws = wb.get_active_sheet();
|
||||||
TS_ASSERT_EQUALS(ws.get_auto_filter().to_string(), "A1:B6");
|
TS_ASSERT_EQUALS(ws.get_auto_filter().to_string(), "A1:B6");
|
||||||
}
|
}
|
||||||
|
@ -465,18 +431,18 @@ public:
|
||||||
void test_bad_formats_xlsb()
|
void test_bad_formats_xlsb()
|
||||||
{
|
{
|
||||||
auto path = PathHelper::GetDataDirectory("/genuine/a.xlsb");
|
auto path = PathHelper::GetDataDirectory("/genuine/a.xlsb");
|
||||||
TS_ASSERT_THROWS(xlnt::load_workbook(path), xlnt::invalid_file_exception);
|
TS_ASSERT_THROWS(xlnt::excel_reader::load_workbook(path), xlnt::invalid_file_exception);
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_bad_formats_xls()
|
void test_bad_formats_xls()
|
||||||
{
|
{
|
||||||
auto path = PathHelper::GetDataDirectory("/genuine/a.xls");
|
auto path = PathHelper::GetDataDirectory("/genuine/a.xls");
|
||||||
TS_ASSERT_THROWS(xlnt::load_workbook(path), xlnt::invalid_file_exception);
|
TS_ASSERT_THROWS(xlnt::excel_reader::load_workbook(path), xlnt::invalid_file_exception);
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_bad_formats_no()
|
void test_bad_formats_no()
|
||||||
{
|
{
|
||||||
auto path = PathHelper::GetDataDirectory("/genuine/a.no-format");
|
auto path = PathHelper::GetDataDirectory("/genuine/a.no-format");
|
||||||
TS_ASSERT_THROWS(xlnt::load_workbook(path), xlnt::invalid_file_exception);
|
TS_ASSERT_THROWS(xlnt::excel_reader::load_workbook(path), xlnt::invalid_file_exception);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -11,7 +11,7 @@ public:
|
||||||
void test_write_number_formats()
|
void test_write_number_formats()
|
||||||
{
|
{
|
||||||
xlnt::workbook wb;
|
xlnt::workbook wb;
|
||||||
wb.add_number_format("YYYY");
|
wb.add_number_format(xlnt::number_format("YYYY"));
|
||||||
xlnt::style_writer writer(wb);
|
xlnt::style_writer writer(wb);
|
||||||
auto xml = writer.write_number_formats();
|
auto xml = writer.write_number_formats();
|
||||||
std::string expected =
|
std::string expected =
|
||||||
|
|
|
@ -16,7 +16,7 @@ public:
|
||||||
xlnt::workbook wbk;
|
xlnt::workbook wbk;
|
||||||
wbk.get_active_sheet().get_cell("A2").set_value("xlnt");
|
wbk.get_active_sheet().get_cell("A2").set_value("xlnt");
|
||||||
wbk.get_active_sheet().get_cell("B5").set_value(88);
|
wbk.get_active_sheet().get_cell("B5").set_value(88);
|
||||||
wbk.get_active_sheet().get_cell("B5").set_number_format(xlnt::number_format(xlnt::number_format::format::percentage_00));
|
wbk.get_active_sheet().get_cell("B5").set_number_format(xlnt::number_format::percentage_00());
|
||||||
wbk.save(temp_file.GetFilename());
|
wbk.save(temp_file.GetFilename());
|
||||||
|
|
||||||
if(PathHelper::FileExists(temp_file.GetFilename()))
|
if(PathHelper::FileExists(temp_file.GetFilename()))
|
||||||
|
|
|
@ -68,7 +68,7 @@ public:
|
||||||
{
|
{
|
||||||
xlnt::workbook old_wb;
|
xlnt::workbook old_wb;
|
||||||
auto saved_wb = xlnt::save_virtual_workbook(old_wb);
|
auto saved_wb = xlnt::save_virtual_workbook(old_wb);
|
||||||
auto new_wb = xlnt::load_workbook(saved_wb);
|
auto new_wb = xlnt::excel_reader::load_workbook(saved_wb);
|
||||||
TS_ASSERT(new_wb != nullptr);
|
TS_ASSERT(new_wb != nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user