work on writer

pull/16/head
Thomas Fussell 2015-10-14 18:05:13 -04:00
parent 44ebfd96a2
commit e3bb0be98e
51 changed files with 1495 additions and 1401 deletions

View File

@ -54,8 +54,8 @@ struct date
/// </summary>
static date from_number(int days_since_base_year, calendar base_date);
date(int year, int month, int day)
: year(year), month(month), day(day)
date(int year_, int month_, int day_)
: year(year_), month(month_), day(day_)
{
}
@ -93,8 +93,8 @@ struct time
/// </summary>
static time from_number(long double number);
explicit time(int hour = 0, int minute = 0, int second = 0, int microsecond = 0)
: hour(hour), minute(minute), second(second), microsecond(microsecond)
explicit time(int hour_ = 0, int minute_ = 0, int second_ = 0, int microsecond_ = 0)
: hour(hour_), minute(minute_), second(second_), microsecond(microsecond_)
{
}
explicit time(const std::string &time_string);
@ -128,8 +128,8 @@ struct datetime
/// </summary>
static datetime from_number(long double number, calendar base_date);
datetime(int year, int month, int day, int hour = 0, int minute = 0, int second = 0, int microsecond = 0)
: year(year), month(month), day(day), hour(hour), minute(minute), second(second), microsecond(microsecond)
datetime(int year_, int month_, int day_, int hour_ = 0, int minute_ = 0, int second_ = 0, int microsecond_ = 0)
: year(year_), month(month_), day(day_), hour(hour_), minute(minute_), second(second_), microsecond(microsecond_)
{
}
@ -152,7 +152,12 @@ struct datetime
/// </summary>
struct timedelta
{
timedelta(int days, int hours, int minutes = 0, int seconds = 0, int microseconds = 0) : days(days), hours(hours), minutes(minutes), seconds(seconds), microseconds(microseconds)
timedelta(int days_, int hours_, int minutes_ = 0, int seconds_ = 0, int microseconds_ = 0)
: days(days_),
hours(hours_),
minutes(minutes_),
seconds(seconds_),
microseconds(microseconds_)
{
}

View File

@ -25,6 +25,8 @@
#include <stdexcept>
#include <string>
#include "../common/types.hpp"
namespace xlnt {
/// <summary>
@ -33,7 +35,7 @@ namespace xlnt {
class cell_coordinates_exception : public std::runtime_error
{
public:
cell_coordinates_exception(int row, int column);
cell_coordinates_exception(row_t row, column_t column);
cell_coordinates_exception(const std::string &coord_string);
};

View File

@ -15,8 +15,7 @@ namespace xlnt {
struct zip_info
{
std::string filename;
struct
struct date_time_t
{
int year;
int month;
@ -24,7 +23,12 @@ struct zip_info
int hours;
int minutes;
int seconds;
} date_time;
};
zip_info();
date_time_t date_time;
std::string filename;
std::string comment;
std::string extra;
uint16_t create_system;
@ -117,4 +121,4 @@ private:
std::string filename_;
};
} // namespace xlnt
} // namespace xlnt

View File

@ -23,11 +23,12 @@
// @author: see AUTHORS file
#pragma once
#include <vector>
namespace xlnt {
class workbook;
class workbook_reader
{
};
xlnt::workbook load_workbook(const std::vector<std::uint8_t> &bytes);
} // namespace xlnt

View File

@ -28,8 +28,9 @@ namespace xlnt {
/// <summary>
/// Alignment options for use in styles.
/// </summary>
struct alignment
class alignment
{
public:
enum class horizontal_alignment
{
general,
@ -55,7 +56,12 @@ struct alignment
bool operator==(const alignment &other) const
{
return horizontal_ == other.horizontal_;
return horizontal_ == other.horizontal_
&& vertical_ == other.vertical_
&& text_rotation_ == other.text_rotation_
&& wrap_text_ == other.wrap_text_
&& shrink_to_fit_ == other.shrink_to_fit_
&& indent_ == other.indent_;
}
private:

View File

@ -98,7 +98,10 @@ public:
bool operator==(const border &other) const
{
return start.value == other.start.value;
return start.value == other.start.value
&& outline == other.outline
&& diagonal_up == other.diagonal_up
&& diagonal_down == other.diagonal_down;
}
};

View File

@ -25,8 +25,9 @@
namespace xlnt {
struct color
class color
{
public:
static const color black;
static const color white;
static const color red;
@ -38,12 +39,17 @@ struct color
static const color yellow;
static const color darkyellow;
color(int index)
color(int index) : index_(index)
{
this->index = index;
}
int index;
bool operator==(const color &other) const
{
return index_ == other.index_;
}
private:
int index_;
};
} // namespace xlnt

View File

@ -45,7 +45,15 @@ public:
bool operator==(const font &other) const
{
return name_ == other.name_;
return name_ == other.name_
&& size_ == other.size_
&& bold_ == other.bold_
&& italic_ == other.italic_
&& superscript_ == other.superscript_
&& subscript_ == other.subscript_
&& underline_ == other.underline_
&& strikethrough_ == other.strikethrough_
&& color_ == other.color_;
}
private:

View File

@ -36,7 +36,7 @@ namespace xlnt {
class style
{
public:
style(bool static_ = false) : static_(static_) {}
style(bool is_static = false) : static_(is_static) {}
style(const style &rhs);
style copy() const;

View File

@ -4,7 +4,8 @@
#include <vector>
namespace xlnt {
class range_reference;
class worksheet;
std::vector<std::pair<std::string, std::string>> split_named_range(const std::string &named_range_string);
@ -12,7 +13,20 @@ std::vector<std::pair<std::string, std::string>> split_named_range(const std::st
class named_range
{
public:
named_range(const std::string &name, const std::vector<std::pair<worksheet, std::string>> &targets);
using target = std::pair<worksheet, range_reference>;
named_range();
named_range(const named_range &other);
named_range(const std::string &name, const std::vector<target> &targets);
std::string get_name() const { return name_; }
const std::vector<target> &get_targets() const { return targets_; }
named_range &operator=(const named_range &other);
private:
std::string name_;
std::vector<target> targets_;
};
}
}

View File

@ -33,20 +33,21 @@
namespace xlnt {
class alignment;
class border;
class color;
class document_properties;
class drawing;
class fill;
class font;
class named_range;
class pattern_fill;
class protection;
class range;
class range_reference;
class relationship;
class worksheet;
class alignment;
class border;
class fill;
class pattern_fill;
class font;
class protection;
class color;
class named_range;
class zip_file;
enum class encoding;
@ -68,7 +69,6 @@ struct content_type
class workbook
{
public:
class iterator
{
public:
@ -102,6 +102,8 @@ public:
const workbook &wb_;
std::size_t index_;
};
static std::size_t index_from_ws_filename(const std::string &filename);
//constructors
workbook();
@ -162,6 +164,7 @@ public:
const document_properties &get_properties() const;
//named ranges
std::vector<named_range> get_named_ranges() const;
void create_named_range(const std::string &name, worksheet worksheet, const range_reference &reference);
bool has_named_range(const std::string &name) const;
range get_named_range(const std::string &name);
@ -173,6 +176,7 @@ public:
bool load(const std::vector<unsigned char> &data);
bool load(const std::string &filename);
bool load(const std::istream &stream);
bool load(zip_file &archive);
bool operator==(const workbook &rhs) const;
@ -204,14 +208,10 @@ public:
void set_code_name(const std::string &code_name);
void add_named_range(const named_range &n);
bool has_loaded_theme();
std::string get_loaded_theme();
private:
static std::size_t index_from_ws_filename(const std::string &ws_filename);
friend class worksheet;
std::shared_ptr<detail::workbook_impl> d_;
};

View File

@ -49,7 +49,7 @@ public:
cell_reference &get_top_left() { return top_left_; }
cell_reference &get_bottom_right() { return bottom_right_; }
range_reference make_offset(column_t column_offset, row_t row_offset) const;
range_reference make_offset(int column_offset, int row_offset) const;
std::string to_string() const;

View File

@ -6,6 +6,6 @@ namespace xlnt {
class workbook;
std::string write_content_types(const workbook &wb, bool as_template);
std::string write_content_types(const workbook &wb, bool as_template = false);
};

View File

@ -50,12 +50,19 @@ public:
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_properties_core(const document_properties &prop);
std::string write_worksheet_rels(worksheet ws);
std::string write_theme();
std::string write_properties_app(const workbook &wb);
std::string write_root_rels(const workbook &wb);
std::string write_workbook(const workbook &wb);
std::string write_workbook_rels(const 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);

View File

@ -1,2 +1,15 @@
#pragma once
#include <string>
#include <unordered_map>
#include <vector>
namespace xlnt {
class worksheet;
std::string write_worksheet(worksheet ws,
const std::vector<std::string> &string_table = {},
const std::unordered_map<std::size_t, std::string> &style_id_by_hash = {});
} // namespace xlnt

View File

@ -1,56 +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 <string>
#include <unordered_map>
#include <utility>
#include <vector>
namespace xlnt {
class relationship;
class workbook;
class worksheet;
class document_properties;
class writer
{
public:
static std::string write_content_types(const workbook &wb);
static std::string write_properties_core(const document_properties &prop);
static std::string write_theme();
static std::string write_shared_strings(const std::vector<std::string> &string_table);
static std::string write_worksheet(worksheet ws,
const std::vector<std::string> &string_table = {},
const std::unordered_map<std::size_t, std::string> &style_table = {});
static std::string write_worksheet_rels(worksheet ws);
};
} // namespace xlnt

View File

@ -3,9 +3,9 @@
namespace xlnt {
side::side(border_style style, color c) : style_(style), color_(c)
{
}
side::side(border_style style, color c) : style_(style), color_(c)
{
} // namespace xlnt
}
} // namespace xlnt

View File

@ -194,6 +194,15 @@ void cell::set_value(char const *c)
template<>
void cell::set_value(cell c)
{
d_->type_ = c.d_->type_;
d_->value_numeric_ = c.d_->value_numeric_;
d_->value_string_ = c.d_->value_string_;
d_->is_date_ = c.d_->is_date_;
d_->hyperlink_ = c.d_->hyperlink_;
d_->has_hyperlink_ = c.d_->has_hyperlink_;
d_->formula_ = c.d_->formula_;
set_style(c.get_style());
set_comment(c.get_comment());
}
template<>
@ -439,7 +448,7 @@ std::pair<int, int> cell::get_anchor() const
int left_anchor = 0;
auto default_width = points_to_pixels(DefaultColumnWidth, 96.0);
for(int column_index = 1; column_index <= (int)left_columns; column_index++)
for(column_t column_index = 1; column_index <= left_columns; column_index++)
{
if(column_dimensions.find(column_index) != column_dimensions.end())
{
@ -462,9 +471,9 @@ std::pair<int, int> cell::get_anchor() const
for(int row_index = 1; row_index <= (int)top_rows; row_index++)
{
if(row_dimensions.find(row_index) != row_dimensions.end())
if(row_dimensions.find(static_cast<row_t>(row_index)) != row_dimensions.end())
{
auto rdh = row_dimensions.at(row_index);
auto rdh = row_dimensions.at(static_cast<row_t>(row_index));
if(rdh > 0)
{
@ -639,7 +648,7 @@ datetime cell::get_value() const
template<>
date cell::get_value() const
{
return date::from_number(d_->value_numeric_, xlnt::calendar::windows_1900);
return date::from_number(static_cast<int>(d_->value_numeric_), xlnt::calendar::windows_1900);
}
template<>

View File

@ -37,22 +37,22 @@ cell_reference::cell_reference(const char *reference_string) : cell_reference(st
}
cell_reference::cell_reference(const std::string &column, row_t row, bool absolute)
: column_(column_index_from_string(column)),
row_(row),
absolute_(absolute)
: column_(column_index_from_string(column)),
row_(row),
absolute_(absolute)
{
if(row == 0 || row_ >= constants::MaxRow || column_ >= constants::MaxColumn)
if(row == 0 || row_ >= constants::MaxRow || column_ == 0 || column_ >= constants::MaxColumn)
{
throw cell_coordinates_exception(column_, row_);
}
}
cell_reference::cell_reference(column_t column_index, row_t row_index, bool absolute)
: column_(column_index),
row_(row_index),
absolute_(absolute)
cell_reference::cell_reference(column_t column_index, row_t row, bool absolute)
: column_(column_index),
row_(row),
absolute_(absolute)
{
if(row_ >= constants::MaxRow || column_ >= constants::MaxColumn)
if(row_ == 0 || row_ >= constants::MaxRow || column_ == 0 || column_ >= constants::MaxColumn)
{
throw cell_coordinates_exception(column_, row_);
}
@ -69,6 +69,7 @@ std::string cell_reference::to_string() const
{
return std::string("$") + column_string_from_index(column_) + "$" + std::to_string(row_);
}
return column_string_from_index(column_) + std::to_string(row_);
}
@ -153,7 +154,8 @@ std::pair<std::string, row_t> cell_reference::split_reference(const std::string
cell_reference cell_reference::make_offset(int column_offset, int row_offset) const
{
return cell_reference(column_ + column_offset, row_ + row_offset);
return cell_reference(static_cast<column_t>(static_cast<int>(column_) + column_offset),
static_cast<row_t>(static_cast<int>(row_) + row_offset));
}
bool cell_reference::operator==(const cell_reference &comparand) const
@ -175,12 +177,12 @@ column_t cell_reference::column_index_from_string(const std::string &column_stri
for(int i = static_cast<int>(column_string.length()) - 1; i >= 0; i--)
{
if(!std::isalpha(column_string[i], std::locale::classic()))
if(!std::isalpha(column_string[static_cast<std::size_t>(i)], std::locale::classic()))
{
throw column_string_index_exception();
throw column_string_index_exception();
}
column_index += (std::toupper(column_string[i], std::locale::classic()) - 'A' + 1) * place;
column_index += static_cast<column_t>((std::toupper(column_string[static_cast<std::size_t>(i)], std::locale::classic()) - 'A' + 1) * place);
place *= 26;
}
@ -201,7 +203,7 @@ std::string cell_reference::column_string_from_index(column_t column_index)
throw column_string_index_exception();
}
auto temp = column_index;
int temp = static_cast<int>(column_index);
std::string column_letter = "";
while(temp > 0)

View File

@ -1,5 +1,5 @@
#include <xlnt/cell/comment.hpp>
#include <xlnt/cell/cell.hpp>
#include <xlnt/cell/comment.hpp>
#include "detail/comment_impl.hpp"
@ -12,6 +12,8 @@ comment::comment(detail::comment_impl *d) : d_(d)
comment::comment(cell parent, const std::string &text, const std::string &author) : d_(nullptr)
{
d_ = parent.get_comment().d_;
d_->text_ = text;
d_->author_ = author;
}
comment::comment() : d_(nullptr)
@ -31,10 +33,10 @@ std::string comment::get_text() const
{
return d_->text_;
}
bool comment::operator==(const xlnt::comment &other) const
{
return d_ == other.d_;
}
bool comment::operator==(const xlnt::comment &other) const
{
return d_ == other.d_;
}
} // namespace xlnt

View File

@ -123,7 +123,7 @@ time::time(const std::string &time_string) : hour(0), minute(0), second(0), micr
long double time::to_number() const
{
std::size_t microseconds = microsecond;
std::size_t microseconds = static_cast<std::size_t>(microsecond);
microseconds += second * 1e6;
microseconds += minute * 1e6 * 60;
microseconds += hour * 1e6 * 60 * 60;
@ -163,7 +163,7 @@ long double datetime::to_number(calendar base_date) const
+ time(hour, minute, second, microsecond).to_number();
}
std::string datetime::to_string(xlnt::calendar base_date) const
std::string datetime::to_string(xlnt::calendar /*base_date*/) const
{
return std::to_string(year) + "/" + std::to_string(month) + "/" + std::to_string(day) + " " +std::to_string(hour) + ":" + std::to_string(minute) + ":" + std::to_string(second) + ":" + std::to_string(microsecond);
}

View File

@ -6,22 +6,50 @@
namespace xlnt {
namespace detail {
cell_impl::cell_impl() : parent_(nullptr), type_(cell::type::null),
column_(1), row_(1), style_(nullptr), is_merged_(false),
is_date_(false), has_hyperlink_(false), xf_index_(0), comment_(nullptr)
cell::type type_;
worksheet_impl *parent_;
column_t column_;
row_t row_;
std::string value_string_;
long double value_numeric_;
std::string formula_;
bool has_hyperlink_;
relationship hyperlink_;
bool is_merged_;
bool is_date_;
std::size_t xf_index_;
std::unique_ptr<style> style_;
std::unique_ptr<comment_impl> comment_;
cell_impl::cell_impl() : cell_impl(1, 1)
{
}
cell_impl::cell_impl(column_t column, row_t row)
: parent_(nullptr), type_(cell::type::null), column_(column), row_(row),
style_(nullptr), is_merged_(false), is_date_(false),
has_hyperlink_(false), xf_index_(0), comment_(nullptr)
{
}
cell_impl::cell_impl(column_t column, row_t row) : cell_impl(nullptr, column, row)
{
}
cell_impl::cell_impl(worksheet_impl *parent, column_t column, row_t row)
: parent_(parent), type_(cell::type::null), column_(column), row_(row), style_(nullptr),
is_merged_(false), is_date_(false), has_hyperlink_(false), xf_index_(0), comment_(nullptr)
: type_(cell::type::null),
parent_(parent),
column_(column),
row_(row),
value_numeric_(0),
has_hyperlink_(false),
is_merged_(false),
is_date_(false),
xf_index_(0),
style_(nullptr),
comment_(nullptr)
{
}

View File

@ -28,11 +28,11 @@ std::string check_string(std::string s)
s = s.substr(0, 32767); // max string length in Excel
}
for (unsigned char c : s)
for (char c : s)
{
if (c <= 8 || c == 11 || c == 12 || (c >= 14 && c <= 31))
if (c>= 0 && (c <= 8 || c == 11 || c == 12 || (c >= 14 && c <= 31)))
{
throw xlnt::illegal_character_error(static_cast<char>(c));
throw xlnt::illegal_character_error(c);
}
}
@ -200,7 +200,6 @@ struct cell_impl
}
}
cell::type type_;
worksheet_impl *parent_;

View File

@ -1,6 +1,5 @@
#include "comment_impl.hpp"
namespace xlnt {
namespace detail {
@ -22,4 +21,4 @@ comment_impl &comment_impl::operator=(const xlnt::detail::comment_impl &rhs)
}
} // namespace detail
} // namespace xlnt
} // namespace xlnt

View File

@ -9,7 +9,18 @@ namespace detail {
struct workbook_impl
{
workbook_impl();
workbook_impl(const workbook_impl &other)
: active_sheet_index_(other.active_sheet_index_),
worksheets_(other.worksheets_),
relationships_(other.relationships_),
drawings_(other.drawings_),
properties_(other.properties_),
guess_types_(other.guess_types_),
data_only_(other.data_only_)
{
}
workbook_impl &operator=(const workbook_impl &other)
{
active_sheet_index_ = other.active_sheet_index_;
@ -22,24 +33,11 @@ struct workbook_impl
properties_ = other.properties_;
guess_types_ = other.guess_types_;
data_only_ = other.data_only_;
return *this;
}
workbook_impl(const workbook_impl &other)
: active_sheet_index_(other.active_sheet_index_),
worksheets_(other.worksheets_),
relationships_(other.relationships_),
drawings_(other.drawings_),
properties_(other.properties_),
guess_types_(other.guess_types_),
data_only_(other.data_only_)
{
}
//bool guess_types_;
//bool data_only_;
int active_sheet_index_;
std::size_t active_sheet_index_;
std::vector<worksheet_impl> worksheets_;
std::vector<relationship> relationships_;
std::vector<drawing> drawings_;

View File

@ -61,7 +61,7 @@ struct worksheet_impl
range_reference auto_filter_;
margins page_margins_;
std::vector<range_reference> merged_cells_;
std::unordered_map<std::string, range_reference> named_ranges_;
std::unordered_map<std::string, named_range> named_ranges_;
std::size_t comment_count_;
header_footer header_footer_;
std::unordered_map<column_t, double> column_dimensions_;

View File

@ -10,4 +10,4 @@ document_properties::document_properties()
}
} // namespace xlnt
} // namespace xlnt

View File

@ -38,7 +38,7 @@ invalid_file_exception::invalid_file_exception(const std::string &filename)
}
cell_coordinates_exception::cell_coordinates_exception(int row, int column)
cell_coordinates_exception::cell_coordinates_exception(row_t row, column_t column)
: std::runtime_error(std::string("bad cell coordinates: (") + std::to_string(row) + "," + std::to_string(column) + ")")
{

View File

@ -1,10 +1,40 @@
#include <sstream>
#include <xlnt/workbook/workbook.hpp>
#include <xlnt/writer/manifest_writer.hpp>
#include "constants.hpp"
#include "detail/include_pugixml.hpp"
namespace xlnt {
std::string write_content_types(const workbook &wb, bool as_template)
std::string write_content_types(const workbook &wb, bool /*as_template*/)
{
return "";
pugi::xml_document doc;
auto root_node = doc.append_child("Types");
root_node.append_attribute("xmlns").set_value(constants::Namespaces.at("content-types").c_str());
for(auto type : wb.get_content_types())
{
pugi::xml_node type_node;
if (type.is_default)
{
type_node = root_node.append_child("Default");
type_node.append_attribute("Extension").set_value(type.extension.c_str());
}
else
{
type_node = root_node.append_child("Override");
type_node.append_attribute("PartName").set_value(type.part_name.c_str());
}
type_node.append_attribute("ContentType").set_value(type.type.c_str());
}
std::stringstream ss;
doc.save(ss);
return ss.str();
}
} // namespace xlnt
} // namespace xlnt

View File

@ -65,9 +65,27 @@ std::vector<std::pair<std::string, std::string>> split_named_range(const std::st
return final;
}
named_range::named_range(const std::string &name, const std::vector<std::pair<worksheet, std::string>> &targets)
named_range::named_range()
{
}
} // namespace xlnt
named_range::named_range(const named_range &other)
{
*this = other;
}
named_range::named_range(const std::string &name, const std::vector<named_range::target> &targets)
: name_(name),
targets_(targets)
{
}
named_range &named_range::operator=(const named_range &other)
{
name_ = other.name_;
targets_ = other.targets_;
return *this;
}
} // namespace xlnt

View File

@ -144,17 +144,19 @@ cell_vector range::get_vector(std::size_t vector_index)
{
if(order_ == major_order::row)
{
range_reference reference(ref_.get_top_left().get_column_index(),
ref_.get_top_left().get_row() + (int)vector_index,
ref_.get_bottom_right().get_column_index(),
ref_.get_top_left().get_row() + (int)vector_index);
return cell_vector(ws_, reference, order_);
range_reference reference(ref_.get_top_left().get_column_index(),
static_cast<row_t>(static_cast<std::size_t>(ref_.get_top_left().get_row()) + vector_index),
ref_.get_bottom_right().get_column_index(),
static_cast<row_t>(static_cast<std::size_t>(ref_.get_top_left().get_row()) + vector_index));
return cell_vector(ws_, reference, order_);
}
range_reference reference(ref_.get_top_left().get_column_index() + (int)vector_index,
range_reference reference(static_cast<column_t>(static_cast<std::size_t>(ref_.get_top_left().get_column_index()) + vector_index),
ref_.get_top_left().get_row(),
ref_.get_top_left().get_column_index() + (int)vector_index,
static_cast<column_t>(static_cast<std::size_t>(ref_.get_top_left().get_column_index()) + vector_index),
ref_.get_bottom_right().get_row());
return cell_vector(ws_, reference, order_);
}

View File

@ -52,7 +52,7 @@ range_reference::range_reference(column_t column_index_start, row_t row_index_st
}
range_reference range_reference::make_offset(column_t column_offset, row_t row_offset) const
range_reference range_reference::make_offset(int column_offset, int row_offset) const
{
return range_reference(top_left_.make_offset(column_offset, row_offset), bottom_right_.make_offset(column_offset, row_offset));
}

View File

@ -1,38 +1,187 @@
#include <algorithm>
#include <pugixml.hpp>
#include <xlnt/reader/reader.hpp>
#include <xlnt/cell/cell.hpp>
#include <xlnt/common/datetime.hpp>
#include <xlnt/worksheet/range_reference.hpp>
#include <xlnt/workbook/workbook.hpp>
#include <xlnt/worksheet/worksheet.hpp>
#include <xlnt/workbook/document_properties.hpp>
#include <xlnt/common/exceptions.hpp>
#include <xlnt/common/relationship.hpp>
#include <xlnt/common/zip_file.hpp>
#include <xlnt/common/exceptions.hpp>
#include <xlnt/reader/reader.hpp>
#include <xlnt/workbook/document_properties.hpp>
#include <xlnt/workbook/workbook.hpp>
#include <xlnt/worksheet/range_reference.hpp>
#include <xlnt/worksheet/worksheet.hpp>
namespace xlnt {
const std::string reader::CentralDirectorySignature = "\x50\x4b\x05\x06";
namespace {
std::string::size_type find_string_in_string(const std::string &string, const std::string &substring)
{
std::string::size_type possible_match_index = string.find(substring.at(0));
while(possible_match_index != std::string::npos)
{
if(string.substr(possible_match_index, substring.size()) == substring)
{
return possible_match_index;
}
possible_match_index = string.find(substring.at(0), possible_match_index + 1);
}
return possible_match_index;
}
xlnt::datetime w3cdtf_to_datetime(const std::string &string)
{
xlnt::datetime result(1900, 1, 1);
auto separator_index = string.find('-');
result.year = std::stoi(string.substr(0, separator_index));
result.month = std::stoi(string.substr(separator_index + 1, string.find('-', separator_index + 1)));
separator_index = string.find('-', separator_index + 1);
result.day = std::stoi(string.substr(separator_index + 1, string.find('T', separator_index + 1)));
separator_index = string.find('T', separator_index + 1);
result.hour = std::stoi(string.substr(separator_index + 1, string.find(':', separator_index + 1)));
separator_index = string.find(':', separator_index + 1);
result.minute = std::stoi(string.substr(separator_index + 1, string.find(':', separator_index + 1)));
separator_index = string.find(':', separator_index + 1);
result.second = std::stoi(string.substr(separator_index + 1, string.find('Z', separator_index + 1)));
return result;
}
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)
{
auto dimension_node = root_node.child("dimension");
std::string dimension = dimension_node.attribute("ref").as_string();
auto full_range = xlnt::range_reference(dimension);
auto sheet_data_node = root_node.child("sheetData");
auto merge_cells_node = root_node.child("mergeCells");
if(merge_cells_node != nullptr)
{
int count = merge_cells_node.attribute("count").as_int();
for(auto merge_cell_node : merge_cells_node.children("mergeCell"))
{
ws.merge_cells(merge_cell_node.attribute("ref").as_string());
count--;
}
if(count != 0)
{
throw std::runtime_error("mismatch between count and actual number of merged cells");
}
}
for(auto row_node : sheet_data_node.children("row"))
{
int row_index = row_node.attribute("r").as_int();
std::string span_string = row_node.attribute("spans").as_string();
auto colon_index = span_string.find(':');
column_t min_column = 0;
column_t max_column = 0;
if(colon_index != std::string::npos)
{
min_column = static_cast<column_t>(std::stoll(span_string.substr(0, colon_index)));
max_column = static_cast<column_t>(std::stoll(span_string.substr(colon_index + 1)));
}
else
{
min_column = static_cast<column_t>(full_range.get_top_left().get_column_index() + 1);
max_column = static_cast<column_t>(full_range.get_bottom_right().get_column_index() + 1);
}
for(column_t i = min_column; i < max_column + 1; i++)
{
std::string address = xlnt::cell_reference::column_string_from_index(i) + std::to_string(row_index);
auto cell_node = row_node.find_child_by_attribute("c", "r", address.c_str());
if(cell_node != nullptr)
{
bool has_value = cell_node.child("v") != nullptr;
std::string value_string = cell_node.child("v").text().as_string();
bool has_type = cell_node.attribute("t") != nullptr;
std::string type = cell_node.attribute("t").as_string();
bool has_style = cell_node.attribute("s") != nullptr;
std::string style = cell_node.attribute("s").as_string();
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";
if(has_formula && !shared_formula && !ws.get_parent().get_data_only())
{
std::string formula = cell_node.child("f").text().as_string();
ws.get_cell(address).set_formula(formula);
}
if(has_type && type == "inlineStr") // inline string
{
std::string inline_string = cell_node.child("is").child("t").text().as_string();
ws.get_cell(address).set_value(inline_string);
}
else if(has_type && type == "s" && !has_formula) // shared string
{
auto shared_string_index = std::stoll(value_string);
auto shared_string = string_table.at(static_cast<std::size_t>(shared_string_index));
ws.get_cell(address).set_value(shared_string);
}
else if(has_type && type == "b") // boolean
{
ws.get_cell(address).set_value(value_string != "0");
}
else if(has_type && type == "str")
{
ws.get_cell(address).set_value(value_string);
}
else if(has_value)
{
try
{
ws.get_cell(address).set_value(std::stold(value_string));
}
catch(std::invalid_argument)
{
ws.get_cell(address).set_value(value_string);
}
}
if(has_style)
{
auto number_format_id = number_format_ids.at(static_cast<std::size_t>(std::stoll(style)));
auto format = xlnt::number_format::lookup_format(number_format_id);
ws.get_cell(address).get_style().get_number_format().set_format_code(format);
if(format == xlnt::number_format::format::date_xlsx14)
{
auto base_date = ws.get_parent().get_properties().excel_base_date;
auto converted = xlnt::date::from_number(std::stoi(value_string), base_date);
ws.get_cell(address).set_value(converted.to_number(xlnt::calendar::windows_1900));
}
}
}
}
}
auto auto_filter_node = root_node.child("autoFilter");
if(auto_filter_node != nullptr)
{
xlnt::range_reference ref(auto_filter_node.attribute("ref").as_string());
ws.auto_filter(ref);
}
}
}
namespace xlnt {
const std::string reader::CentralDirectorySignature = "\x50\x4b\x05\x06";
std::string reader::repair_central_directory(const std::string &original)
{
auto pos = find_string_in_string(original, CentralDirectorySignature);
@ -85,23 +234,6 @@ std::vector<std::pair<std::string, std::string>> reader::read_sheets(zip_file &a
return sheets;
}
datetime w3cdtf_to_datetime(const std::string &string)
{
datetime result(1900, 1, 1);
auto separator_index = string.find('-');
result.year = std::stoi(string.substr(0, separator_index));
result.month = std::stoi(string.substr(separator_index + 1, string.find('-', separator_index + 1)));
separator_index = string.find('-', separator_index + 1);
result.day = std::stoi(string.substr(separator_index + 1, string.find('T', separator_index + 1)));
separator_index = string.find('T', separator_index + 1);
result.hour = std::stoi(string.substr(separator_index + 1, string.find(':', separator_index + 1)));
separator_index = string.find(':', separator_index + 1);
result.minute = std::stoi(string.substr(separator_index + 1, string.find(':', separator_index + 1)));
separator_index = string.find(':', separator_index + 1);
result.second = std::stoi(string.substr(separator_index + 1, string.find('Z', separator_index + 1)));
return result;
}
document_properties reader::read_properties_core(const std::string &xml_string)
{
document_properties props;
@ -235,133 +367,6 @@ std::string reader::determine_document_type(const std::vector<std::pair<std::str
return "unsupported";
}
void read_worksheet_common(worksheet ws, const pugi::xml_node &root_node, const std::vector<std::string> &string_table, const std::vector<int> &number_format_ids)
{
auto dimension_node = root_node.child("dimension");
std::string dimension = dimension_node.attribute("ref").as_string();
auto full_range = xlnt::range_reference(dimension);
auto sheet_data_node = root_node.child("sheetData");
auto merge_cells_node = root_node.child("mergeCells");
if(merge_cells_node != nullptr)
{
int count = merge_cells_node.attribute("count").as_int();
for(auto merge_cell_node : merge_cells_node.children("mergeCell"))
{
ws.merge_cells(merge_cell_node.attribute("ref").as_string());
count--;
}
if(count != 0)
{
throw std::runtime_error("mismatch between count and actual number of merged cells");
}
}
for(auto row_node : sheet_data_node.children("row"))
{
int row_index = row_node.attribute("r").as_int();
std::string span_string = row_node.attribute("spans").as_string();
auto colon_index = span_string.find(':');
int min_column = 0;
int max_column = 0;
if(colon_index != std::string::npos)
{
min_column = std::stoi(span_string.substr(0, colon_index));
max_column = std::stoi(span_string.substr(colon_index + 1));
}
else
{
min_column = full_range.get_top_left().get_column_index() + 1;
max_column = full_range.get_bottom_right().get_column_index() + 1;
}
for(int i = min_column; i < max_column + 1; i++)
{
std::string address = xlnt::cell_reference::column_string_from_index(i) + std::to_string(row_index);
auto cell_node = row_node.find_child_by_attribute("c", "r", address.c_str());
if(cell_node != nullptr)
{
bool has_value = cell_node.child("v") != nullptr;
std::string value_string = cell_node.child("v").text().as_string();
bool has_type = cell_node.attribute("t") != nullptr;
std::string type = cell_node.attribute("t").as_string();
bool has_style = cell_node.attribute("s") != nullptr;
std::string style = cell_node.attribute("s").as_string();
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";
if(has_formula && !shared_formula && !ws.get_parent().get_data_only())
{
std::string formula = cell_node.child("f").text().as_string();
ws.get_cell(address).set_formula(formula);
}
if(has_type && type == "inlineStr") // inline string
{
std::string inline_string = cell_node.child("is").child("t").text().as_string();
ws.get_cell(address).set_value(inline_string);
}
else if(has_type && type == "s" && !has_formula) // shared string
{
auto shared_string_index = std::stoi(value_string);
auto shared_string = string_table.at(shared_string_index);
ws.get_cell(address).set_value(shared_string);
}
else if(has_type && type == "b") // boolean
{
ws.get_cell(address).set_value(value_string != "0");
}
else if(has_type && type == "str")
{
ws.get_cell(address).set_value(value_string);
}
else if(has_value)
{
try
{
ws.get_cell(address).set_value(std::stold(value_string));
}
catch(std::invalid_argument)
{
ws.get_cell(address).set_value(value_string);
}
}
if(has_style)
{
auto number_format_id = number_format_ids.at(std::stoi(style));
auto format = number_format::lookup_format(number_format_id);
ws.get_cell(address).get_style().get_number_format().set_format_code(format);
if(format == number_format::format::date_xlsx14)
{
auto base_date = ws.get_parent().get_properties().excel_base_date;
auto converted = date::from_number(std::stoi(value_string), base_date);
ws.get_cell(address).set_value(converted.to_number(calendar::windows_1900));
}
}
}
}
}
auto auto_filter_node = root_node.child("autoFilter");
if(auto_filter_node != nullptr)
{
range_reference ref(auto_filter_node.attribute("ref").as_string());
ws.auto_filter(ref);
}
}
void reader::fast_parse(worksheet ws, std::istream &xml_source, const std::vector<std::string> &shared_string, const std::vector<style> &/*style_table*/, std::size_t /*color_index*/)
{
pugi::xml_document doc;

View File

@ -42,4 +42,4 @@ std::string write_relationships(const std::vector<relationship> &relationships,
return ss.str();
}
}
}

View File

@ -14,10 +14,13 @@
#include <xlnt/drawing/drawing.hpp>
#include <xlnt/reader/reader.hpp>
#include <xlnt/workbook/document_properties.hpp>
#include <xlnt/workbook/named_range.hpp>
#include <xlnt/workbook/workbook.hpp>
#include <xlnt/worksheet/range.hpp>
#include <xlnt/worksheet/worksheet.hpp>
#include <xlnt/writer/style_writer.hpp>
#include <xlnt/writer/manifest_writer.hpp>
#include <xlnt/writer/worksheet_writer.hpp>
#include <xlnt/writer/workbook_writer.hpp>
#include <xlnt/writer/writer.hpp>
@ -280,23 +283,9 @@ bool workbook::load(const std::istream &stream)
bool workbook::load(const std::vector<unsigned char> &data)
{
std::string temp_file = create_temporary_filename();
std::ofstream tmp;
tmp.open(temp_file, std::ios::out | std::ios::binary);
for(auto c : data)
{
tmp.put(c);
}
tmp.close();
load(temp_file);
std::remove(temp_file.c_str());
return true;
xlnt::zip_file archive;
archive.load(data);
return load(archive);
}
bool workbook::load(const std::string &filename)
@ -311,18 +300,23 @@ bool workbook::load(const std::string &filename)
{
throw invalid_file_exception(filename);
}
auto content_types = reader::read_content_types(f);
return load(f);
}
bool workbook::load(xlnt::zip_file &archive)
{
auto content_types = reader::read_content_types(archive);
auto type = reader::determine_document_type(content_types);
if(type != "excel")
{
throw invalid_file_exception(filename);
throw invalid_file_exception("");
}
clear();
auto workbook_relationships = reader::read_relationships(f, "xl/workbook.xml");
auto workbook_relationships = reader::read_relationships(archive, "xl/workbook.xml");
for(auto relationship : workbook_relationships)
{
@ -330,7 +324,7 @@ bool workbook::load(const std::string &filename)
}
pugi::xml_document doc;
doc.load(f.read("xl/workbook.xml").c_str());
doc.load(archive.read("xl/workbook.xml").c_str());
auto root_node = doc.child("workbook");
@ -341,17 +335,17 @@ bool workbook::load(const std::string &filename)
std::vector<std::string> shared_strings;
if(f.has_file("xl/sharedStrings.xml"))
if(archive.has_file("xl/sharedStrings.xml"))
{
shared_strings = xlnt::reader::read_shared_string(f.read("xl/sharedStrings.xml"));
shared_strings = xlnt::reader::read_shared_string(archive.read("xl/sharedStrings.xml"));
}
std::vector<int> number_format_ids;
if(f.has_file("xl/styles.xml"))
if(archive.has_file("xl/styles.xml"))
{
pugi::xml_document styles_doc;
styles_doc.load(f.read("xl/styles.xml").c_str());
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");
@ -365,7 +359,7 @@ bool workbook::load(const std::string &filename)
{
std::string rel_id = sheet_node.attribute("r:id").as_string();
auto rel = std::find_if(d_->relationships_.begin(), d_->relationships_.end(),
[&](relationship &rel) { return rel.get_id() == rel_id; });
[&](relationship &r) { return r.get_id() == rel_id; });
if (rel == d_->relationships_.end())
{
@ -375,7 +369,7 @@ bool workbook::load(const std::string &filename)
auto ws = create_sheet(sheet_node.attribute("name").as_string(), *rel);
auto sheet_filename = rel->get_target_uri();
xlnt::reader::read_worksheet(ws, f.read(sheet_filename).c_str(), shared_strings, number_format_ids);
xlnt::reader::read_worksheet(ws, archive.read(sheet_filename).c_str(), shared_strings, number_format_ids);
}
return true;
@ -435,6 +429,21 @@ worksheet workbook::create_sheet(std::size_t index)
return worksheet(&d_->worksheets_[index]);
}
//TODO: There should be a better way to do this...
std::size_t workbook::index_from_ws_filename(const std::string &ws_filename)
{
std::string sheet_index_string(ws_filename);
sheet_index_string = sheet_index_string.substr(0, sheet_index_string.find('.'));
sheet_index_string = sheet_index_string.substr(sheet_index_string.find_last_of('/'));
auto iter = sheet_index_string.end();
iter--;
while (isdigit(*iter)) iter--;
auto first_digit = static_cast<std::size_t>(iter - sheet_index_string.begin());
sheet_index_string = sheet_index_string.substr(first_digit + 1);
auto sheet_index = static_cast<std::size_t>(std::stoll(sheet_index_string) - 1);
return sheet_index;
}
worksheet workbook::create_sheet(const std::string &title, const relationship &rel)
{
d_->worksheets_.push_back(detail::worksheet_impl(this, title));
@ -542,72 +551,13 @@ void workbook::clear()
bool workbook::save(std::vector<unsigned char> &data)
{
auto temp_file = create_temporary_filename();
save(temp_file);
std::ifstream tmp;
tmp.open(temp_file, std::ios::in | std::ios::binary);
auto char_data = std::vector<char>((std::istreambuf_iterator<char>(tmp)),
std::istreambuf_iterator<char>());
data = std::vector<unsigned char>(char_data.begin(), char_data.end());
tmp.close();
std::remove(temp_file.c_str());
data = save_virtual_workbook(*this);
return true;
}
bool workbook::save(const std::string &filename)
{
zip_file f;
f.writestr("[Content_Types].xml", writer::write_content_types(*this));
f.writestr("docProps/app.xml", write_properties_app(*this));
f.writestr("docProps/core.xml", writer::write_properties_core(get_properties()));
std::set<std::string> shared_strings_set;
for(auto ws : *this)
{
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>());
}
}
}
}
std::vector<std::string> shared_strings(shared_strings_set.begin(), shared_strings_set.end());
f.writestr("xl/sharedStrings.xml", writer::write_shared_strings(shared_strings));
f.writestr("xl/theme/theme1.xml", writer::write_theme());
f.writestr("xl/styles.xml", style_writer(*this).write_table());
f.writestr("_rels/.rels", write_root_rels(*this));
f.writestr("xl/_rels/workbook.xml.rels", write_workbook_rels(*this));
f.writestr("xl/workbook.xml", write_workbook(*this));
for(auto relationship : d_->relationships_)
{
if(relationship.get_type() == relationship::type::worksheet)
{
auto sheet_index = index_from_ws_filename(relationship.get_target_uri());
auto ws = get_sheet_by_index(sheet_index);
f.writestr(relationship.get_target_uri(), writer::write_worksheet(ws, shared_strings));
}
}
f.save(filename);
return true;
return save_workbook(*this, filename);
}
bool workbook::operator==(std::nullptr_t) const
@ -699,57 +649,38 @@ void workbook::set_data_only(bool data_only)
{
d_->data_only_ = data_only;
}
std::size_t workbook::index_from_ws_filename(const std::string &ws_filename)
{
std::string sheet_index_string(ws_filename);
sheet_index_string = sheet_index_string.substr(0, sheet_index_string.find('.'));
sheet_index_string = sheet_index_string.substr(sheet_index_string.find_last_of('/'));
auto iter = sheet_index_string.end();
iter--;
while (isdigit(*iter)) iter--;
auto first_digit = iter - sheet_index_string.begin();
sheet_index_string = sheet_index_string.substr(first_digit + 1);
auto sheet_index = std::stoi(sheet_index_string) - 1;
return sheet_index;
}
void workbook::add_border(xlnt::border b)
void workbook::add_border(xlnt::border /*b*/)
{
}
void workbook::add_alignment(xlnt::alignment a)
void workbook::add_alignment(xlnt::alignment /*a*/)
{
}
void workbook::add_protection(xlnt::protection p)
void workbook::add_protection(xlnt::protection /*p*/)
{
}
void workbook::add_number_format(const std::string &format)
void workbook::add_number_format(const std::string &/*format*/)
{
}
void workbook::add_fill(xlnt::fill &f)
void workbook::add_fill(xlnt::fill &/*f*/)
{
}
void workbook::add_font(xlnt::font f)
void workbook::add_font(xlnt::font /*f*/)
{
}
void workbook::set_code_name(const std::string &code_name)
{
}
void workbook::add_named_range(const xlnt::named_range &n)
void workbook::set_code_name(const std::string &/*code_name*/)
{
}
@ -763,4 +694,19 @@ std::size_t workbook::index_from_ws_filename(const std::string &ws_filename)
{
return "";
}
std::vector<named_range> workbook::get_named_ranges() const
{
std::vector<named_range> named_ranges;
for(auto ws : *this)
{
for(auto &ws_named_range : ws.d_->named_ranges_)
{
named_ranges.push_back(ws_named_range.second);
}
}
return named_ranges;
}
}

View File

@ -0,0 +1,13 @@
#include <xlnt/reader/workbook_reader.hpp>
#include <xlnt/workbook/workbook.hpp>
namespace xlnt {
xlnt::workbook load_workbook(const std::vector<std::uint8_t> &bytes)
{
xlnt::workbook wb;
wb.load(bytes);
return wb;
}
}

View File

@ -1,25 +1,40 @@
#include <set>
#include <sstream>
#include <xlnt/cell/cell.hpp>
#include <xlnt/common/exceptions.hpp>
#include <xlnt/common/relationship.hpp>
#include <xlnt/common/zip_file.hpp>
#include <xlnt/workbook/document_properties.hpp>
#include <xlnt/workbook/named_range.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/manifest_writer.hpp>
#include <xlnt/writer/relationship_writer.hpp>
#include <xlnt/writer/theme_writer.hpp>
#include <xlnt/writer/worksheet_writer.hpp>
#include <xlnt/writer/workbook_writer.hpp>
#include "constants.hpp"
#include "detail/include_pugixml.hpp"
namespace {
std::string to_xml(xlnt::document_properties &props)
std::string fill(const std::string &string, std::size_t length = 2)
{
return "";
if(string.size() >= length)
{
return string;
}
return std::string(length - string.size(), '0') + string;
}
std::string datetime_to_w3cdtf(const xlnt::datetime &dt)
{
return std::to_string(dt.year) + "-" + fill(std::to_string(dt.month)) + "-" + fill(std::to_string(dt.day)) + "T" + fill(std::to_string(dt.hour)) + ":" + fill(std::to_string(dt.minute)) + ":" + fill(std::to_string(dt.second)) + "Z";
}
} // namespace
@ -42,7 +57,7 @@ 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, to_xml(wb_.get_properties()));
archive.writestr(constants::ArcCore, write_properties_core(wb_.get_properties()));
if(wb_.has_loaded_theme())
{
@ -72,14 +87,15 @@ void excel_writer::write_data(zip_file &archive, bool as_template)
}
}
}
*/
*/
write_charts(archive);
write_images(archive);
write_worksheets(archive);
write_chartsheets(archive);
write_string_table(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);
@ -87,32 +103,452 @@ void excel_writer::write_data(zip_file &archive, bool as_template)
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_images(zip_file &/*archive*/)
{
}
void excel_writer::write_charts(zip_file &archive)
void excel_writer::write_charts(zip_file &/*archive*/)
{
}
void excel_writer::write_chartsheets(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*/)
{
}
void excel_writer::write_external_links(zip_file &archive)
std::string write_shared_strings(const std::vector<std::string> &string_table)
{
pugi::xml_document doc;
auto root_node = doc.append_child("sst");
root_node.append_attribute("xmlns").set_value("http://schemas.openxmlformats.org/spreadsheetml/2006/main");
root_node.append_attribute("uniqueCount").set_value((int)string_table.size());
for(auto string : string_table)
{
root_node.append_child("si").append_child("t").text().set(string.c_str());
}
std::stringstream ss;
doc.save(ss);
return ss.str();
}
std::string write_properties_core(const document_properties &prop)
{
pugi::xml_document doc;
auto root_node = doc.append_child("cp:coreProperties");
root_node.append_attribute("xmlns:cp").set_value("http://schemas.openxmlformats.org/package/2006/metadata/core-properties");
root_node.append_attribute("xmlns:dc").set_value("http://purl.org/dc/elements/1.1/");
root_node.append_attribute("xmlns:dcmitype").set_value("http://purl.org/dc/dcmitype/");
root_node.append_attribute("xmlns:dcterms").set_value("http://purl.org/dc/terms/");
root_node.append_attribute("xmlns:xsi").set_value("http://www.w3.org/2001/XMLSchema-instance");
root_node.append_child("dc:creator").text().set(prop.creator.c_str());
root_node.append_child("cp:lastModifiedBy").text().set(prop.last_modified_by.c_str());
root_node.append_child("dcterms:created").text().set(datetime_to_w3cdtf(prop.created).c_str());
root_node.child("dcterms:created").append_attribute("xsi:type").set_value("dcterms:W3CDTF");
root_node.append_child("dcterms:modified").text().set(datetime_to_w3cdtf(prop.modified).c_str());
root_node.child("dcterms:modified").append_attribute("xsi:type").set_value("dcterms:W3CDTF");
root_node.append_child("dc:title").text().set(prop.title.c_str());
root_node.append_child("dc:description");
root_node.append_child("dc:subject");
root_node.append_child("cp:keywords");
root_node.append_child("cp:category");
std::stringstream ss;
doc.save(ss);
return ss.str();
}
std::string write_worksheet_rels(worksheet ws)
{
return write_relationships(ws.get_relationships(), "");
}
std::string write_theme()
{
pugi::xml_document doc;
auto theme_node = doc.append_child("a:theme");
theme_node.append_attribute("xmlns:a").set_value(constants::Namespaces.at("drawingml").c_str());
theme_node.append_attribute("name").set_value("Office Theme");
auto theme_elements_node = theme_node.append_child("a:themeElements");
auto clr_scheme_node = theme_elements_node.append_child("a:clrScheme");
clr_scheme_node.append_attribute("name").set_value("Office");
struct scheme_element
{
std::string name;
std::string sub_element_name;
std::string val;
};
std::vector<scheme_element> scheme_elements =
{
{"a:dk1", "a:sysClr", "windowText"},
{"a:lt1", "a:sysClr", "window"},
{"a:dk2", "a:srgbClr", "1F497D"},
{"a:lt2", "a:srgbClr", "EEECE1"},
{"a:accent1", "a:srgbClr", "4F81BD"},
{"a:accent2", "a:srgbClr", "C0504D"},
{"a:accent3", "a:srgbClr", "9BBB59"},
{"a:accent4", "a:srgbClr", "8064A2"},
{"a:accent5", "a:srgbClr", "4BACC6"},
{"a:accent6", "a:srgbClr", "F79646"},
{"a:hlink", "a:srgbClr", "0000FF"},
{"a:folHlink", "a:srgbClr", "800080"},
};
for(auto element : scheme_elements)
{
auto element_node = clr_scheme_node.append_child(element.name.c_str());
element_node.append_child(element.sub_element_name.c_str()).append_attribute("val").set_value(element.val.c_str());
if(element.name == "a:dk1")
{
element_node.child(element.sub_element_name.c_str()).append_attribute("lastClr").set_value("000000");
}
else if(element.name == "a:lt1")
{
element_node.child(element.sub_element_name.c_str()).append_attribute("lastClr").set_value("FFFFFF");
}
}
struct font_scheme
{
bool typeface;
std::string script;
std::string major;
std::string minor;
};
std::vector<font_scheme> font_schemes =
{
{true, "a:latin", "Cambria", "Calibri"},
{true, "a:ea", "", ""},
{true, "a:cs", "", ""},
{false, "Jpan", "\xef\xbc\xad\xef\xbc\xb3 \xef\xbc\xb0\xe3\x82\xb4\xe3\x82\xb7\xe3\x83\x83\xe3\x82\xaf", "\xef\xbc\xad\xef\xbc\xb3 \xef\xbc\xb0\xe3\x82\xb4\xe3\x82\xb7\xe3\x83\x83\xe3\x82\xaf"},
{false, "Hang", "\xeb\xa7\x91\xec\x9d\x80 \xea\xb3\xa0\xeb\x94\x95", "\xeb\xa7\x91\xec\x9d\x80 \xea\xb3\xa0\xeb\x94\x95"},
{false, "Hans", "\xe5\xae\x8b\xe4\xbd\x93", "\xe5\xae\x8b\xe4\xbd\x93"},
{false, "Hant", "\xe6\x96\xb0\xe7\xb4\xb0\xe6\x98\x8e\xe9\xab\x94", "\xe6\x96\xb0\xe7\xb4\xb0\xe6\x98\x8e\xe9\xab\x94"},
{false, "Arab", "Times New Roman", "Arial"},
{false, "Hebr", "Times New Roman", "Arial"},
{false, "Thai", "Tahoma", "Tahoma"},
{false, "Ethi", "Nyala", "Nyala"},
{false, "Beng", "Vrinda", "Vrinda"},
{false, "Gujr", "Shruti", "Shruti"},
{false, "Khmr", "MoolBoran", "DaunPenh"},
{false, "Knda", "Tunga", "Tunga"},
{false, "Guru", "Raavi", "Raavi"},
{false, "Cans", "Euphemia", "Euphemia"},
{false, "Cher", "Plantagenet Cherokee", "Plantagenet Cherokee"},
{false, "Yiii", "Microsoft Yi Baiti", "Microsoft Yi Baiti"},
{false, "Tibt", "Microsoft Himalaya", "Microsoft Himalaya"},
{false, "Thaa", "MV Boli", "MV Boli"},
{false, "Deva", "Mangal", "Mangal"},
{false, "Telu", "Gautami", "Gautami"},
{false, "Taml", "Latha", "Latha"},
{false, "Syrc", "Estrangelo Edessa", "Estrangelo Edessa"},
{false, "Orya", "Kalinga", "Kalinga"},
{false, "Mlym", "Kartika", "Kartika"},
{false, "Laoo", "DokChampa", "DokChampa"},
{false, "Sinh", "Iskoola Pota", "Iskoola Pota"},
{false, "Mong", "Mongolian Baiti", "Mongolian Baiti"},
{false, "Viet", "Times New Roman", "Arial"},
{false, "Uigh", "Microsoft Uighur", "Microsoft Uighur"}
};
auto font_scheme_node = theme_elements_node.append_child("a:fontScheme");
font_scheme_node.append_attribute("name").set_value("Office");
auto major_fonts_node = font_scheme_node.append_child("a:majorFont");
auto minor_fonts_node = font_scheme_node.append_child("a:minorFont");
for(auto scheme : font_schemes)
{
pugi::xml_node major_font_node, minor_font_node;
if(scheme.typeface)
{
major_font_node = major_fonts_node.append_child(scheme.script.c_str());
minor_font_node = minor_fonts_node.append_child(scheme.script.c_str());
}
else
{
major_font_node = major_fonts_node.append_child("a:font");
major_font_node.append_attribute("script").set_value(scheme.script.c_str());
minor_font_node = minor_fonts_node.append_child("a:font");
minor_font_node.append_attribute("script").set_value(scheme.script.c_str());
}
major_font_node.append_attribute("typeface").set_value(scheme.major.c_str());
minor_font_node.append_attribute("typeface").set_value(scheme.minor.c_str());
}
auto format_scheme_node = theme_elements_node.append_child("a:fmtScheme");
format_scheme_node.append_attribute("name").set_value("Office");
auto fill_style_list_node = format_scheme_node.append_child("a:fillStyleLst");
fill_style_list_node.append_child("a:solidFill").append_child("a:schemeClr").append_attribute("val").set_value("phClr");
auto grad_fill_node = fill_style_list_node.append_child("a:gradFill");
grad_fill_node.append_attribute("rotWithShape").set_value(1);
auto grad_fill_list = grad_fill_node.append_child("a:gsLst");
auto gs_node = grad_fill_list.append_child("a:gs");
gs_node.append_attribute("pos").set_value(0);
auto scheme_color_node = gs_node.append_child("a:schemeClr");
scheme_color_node.append_attribute("val").set_value("phClr");
scheme_color_node.append_child("a:tint").append_attribute("val").set_value(50000);
scheme_color_node.append_child("a:satMod").append_attribute("val").set_value(300000);
gs_node = grad_fill_list.append_child("a:gs");
gs_node.append_attribute("pos").set_value(35000);
scheme_color_node = gs_node.append_child("a:schemeClr");
scheme_color_node.append_attribute("val").set_value("phClr");
scheme_color_node.append_child("a:tint").append_attribute("val").set_value(37000);
scheme_color_node.append_child("a:satMod").append_attribute("val").set_value(300000);
gs_node = grad_fill_list.append_child("a:gs");
gs_node.append_attribute("pos").set_value(100000);
scheme_color_node = gs_node.append_child("a:schemeClr");
scheme_color_node.append_attribute("val").set_value("phClr");
scheme_color_node.append_child("a:tint").append_attribute("val").set_value(15000);
scheme_color_node.append_child("a:satMod").append_attribute("val").set_value(350000);
auto lin_node = grad_fill_node.append_child("a:lin");
lin_node.append_attribute("ang").set_value(16200000);
lin_node.append_attribute("scaled").set_value(1);
grad_fill_node = fill_style_list_node.append_child("a:gradFill");
grad_fill_node.append_attribute("rotWithShape").set_value(1);
grad_fill_list = grad_fill_node.append_child("a:gsLst");
gs_node = grad_fill_list.append_child("a:gs");
gs_node.append_attribute("pos").set_value(0);
scheme_color_node = gs_node.append_child("a:schemeClr");
scheme_color_node.append_attribute("val").set_value("phClr");
scheme_color_node.append_child("a:shade").append_attribute("val").set_value(51000);
scheme_color_node.append_child("a:satMod").append_attribute("val").set_value(130000);
gs_node = grad_fill_list.append_child("a:gs");
gs_node.append_attribute("pos").set_value(80000);
scheme_color_node = gs_node.append_child("a:schemeClr");
scheme_color_node.append_attribute("val").set_value("phClr");
scheme_color_node.append_child("a:shade").append_attribute("val").set_value(93000);
scheme_color_node.append_child("a:satMod").append_attribute("val").set_value(130000);
gs_node = grad_fill_list.append_child("a:gs");
gs_node.append_attribute("pos").set_value(100000);
scheme_color_node = gs_node.append_child("a:schemeClr");
scheme_color_node.append_attribute("val").set_value("phClr");
scheme_color_node.append_child("a:shade").append_attribute("val").set_value(94000);
scheme_color_node.append_child("a:satMod").append_attribute("val").set_value(135000);
lin_node = grad_fill_node.append_child("a:lin");
lin_node.append_attribute("ang").set_value(16200000);
lin_node.append_attribute("scaled").set_value(0);
auto line_style_list_node = format_scheme_node.append_child("a:lnStyleLst");
auto ln_node = line_style_list_node.append_child("a:ln");
ln_node.append_attribute("w").set_value(9525);
ln_node.append_attribute("cap").set_value("flat");
ln_node.append_attribute("cmpd").set_value("sng");
ln_node.append_attribute("algn").set_value("ctr");
auto solid_fill_node = ln_node.append_child("a:solidFill");
scheme_color_node = solid_fill_node.append_child("a:schemeClr");
scheme_color_node.append_attribute("val").set_value("phClr");
scheme_color_node.append_child("a:shade").append_attribute("val").set_value(95000);
scheme_color_node.append_child("a:satMod").append_attribute("val").set_value(105000);
ln_node.append_child("a:prstDash").append_attribute("val").set_value("solid");
ln_node = line_style_list_node.append_child("a:ln");
ln_node.append_attribute("w").set_value(25400);
ln_node.append_attribute("cap").set_value("flat");
ln_node.append_attribute("cmpd").set_value("sng");
ln_node.append_attribute("algn").set_value("ctr");
solid_fill_node = ln_node.append_child("a:solidFill");
scheme_color_node = solid_fill_node.append_child("a:schemeClr");
scheme_color_node.append_attribute("val").set_value("phClr");
ln_node.append_child("a:prstDash").append_attribute("val").set_value("solid");
ln_node = line_style_list_node.append_child("a:ln");
ln_node.append_attribute("w").set_value(38100);
ln_node.append_attribute("cap").set_value("flat");
ln_node.append_attribute("cmpd").set_value("sng");
ln_node.append_attribute("algn").set_value("ctr");
solid_fill_node = ln_node.append_child("a:solidFill");
scheme_color_node = solid_fill_node.append_child("a:schemeClr");
scheme_color_node.append_attribute("val").set_value("phClr");
ln_node.append_child("a:prstDash").append_attribute("val").set_value("solid");
auto effect_style_list_node = format_scheme_node.append_child("a:effectStyleLst");
auto effect_style_node = effect_style_list_node.append_child("a:effectStyle");
auto effect_list_node = effect_style_node.append_child("a:effectLst");
auto outer_shadow_node = effect_list_node.append_child("a:outerShdw");
outer_shadow_node.append_attribute("blurRad").set_value(40000);
outer_shadow_node.append_attribute("dist").set_value(20000);
outer_shadow_node.append_attribute("dir").set_value(5400000);
outer_shadow_node.append_attribute("rotWithShape").set_value(0);
auto srgb_clr_node = outer_shadow_node.append_child("a:srgbClr");
srgb_clr_node.append_attribute("val").set_value("000000");
srgb_clr_node.append_child("a:alpha").append_attribute("val").set_value(38000);
effect_style_node = effect_style_list_node.append_child("a:effectStyle");
effect_list_node = effect_style_node.append_child("a:effectLst");
outer_shadow_node = effect_list_node.append_child("a:outerShdw");
outer_shadow_node.append_attribute("blurRad").set_value(40000);
outer_shadow_node.append_attribute("dist").set_value(23000);
outer_shadow_node.append_attribute("dir").set_value(5400000);
outer_shadow_node.append_attribute("rotWithShape").set_value(0);
srgb_clr_node = outer_shadow_node.append_child("a:srgbClr");
srgb_clr_node.append_attribute("val").set_value("000000");
srgb_clr_node.append_child("a:alpha").append_attribute("val").set_value(35000);
effect_style_node = effect_style_list_node.append_child("a:effectStyle");
effect_list_node = effect_style_node.append_child("a:effectLst");
outer_shadow_node = effect_list_node.append_child("a:outerShdw");
outer_shadow_node.append_attribute("blurRad").set_value(40000);
outer_shadow_node.append_attribute("dist").set_value(23000);
outer_shadow_node.append_attribute("dir").set_value(5400000);
outer_shadow_node.append_attribute("rotWithShape").set_value(0);
srgb_clr_node = outer_shadow_node.append_child("a:srgbClr");
srgb_clr_node.append_attribute("val").set_value("000000");
srgb_clr_node.append_child("a:alpha").append_attribute("val").set_value(35000);
auto scene3d_node = effect_style_node.append_child("a:scene3d");
auto camera_node = scene3d_node.append_child("a:camera");
camera_node.append_attribute("prst").set_value("orthographicFront");
auto rot_node = camera_node.append_child("a:rot");
rot_node.append_attribute("lat").set_value(0);
rot_node.append_attribute("lon").set_value(0);
rot_node.append_attribute("rev").set_value(0);
auto light_rig_node = scene3d_node.append_child("a:lightRig");
light_rig_node.append_attribute("rig").set_value("threePt");
light_rig_node.append_attribute("dir").set_value("t");
rot_node = light_rig_node.append_child("a:rot");
rot_node.append_attribute("lat").set_value(0);
rot_node.append_attribute("lon").set_value(0);
rot_node.append_attribute("rev").set_value(1200000);
auto bevel_node = effect_style_node.append_child("a:sp3d").append_child("a:bevelT");
bevel_node.append_attribute("w").set_value(63500);
bevel_node.append_attribute("h").set_value(25400);
auto bg_fill_style_list_node = format_scheme_node.append_child("a:bgFillStyleLst");
bg_fill_style_list_node.append_child("a:solidFill").append_child("a:schemeClr").append_attribute("val").set_value("phClr");
grad_fill_node = bg_fill_style_list_node.append_child("a:gradFill");
grad_fill_node.append_attribute("rotWithShape").set_value(1);
grad_fill_list = grad_fill_node.append_child("a:gsLst");
gs_node = grad_fill_list.append_child("a:gs");
gs_node.append_attribute("pos").set_value(0);
scheme_color_node = gs_node.append_child("a:schemeClr");
scheme_color_node.append_attribute("val").set_value("phClr");
scheme_color_node.append_child("a:tint").append_attribute("val").set_value(40000);
scheme_color_node.append_child("a:satMod").append_attribute("val").set_value(350000);
gs_node = grad_fill_list.append_child("a:gs");
gs_node.append_attribute("pos").set_value(40000);
scheme_color_node = gs_node.append_child("a:schemeClr");
scheme_color_node.append_attribute("val").set_value("phClr");
scheme_color_node.append_child("a:tint").append_attribute("val").set_value(45000);
scheme_color_node.append_child("a:shade").append_attribute("val").set_value(99000);
scheme_color_node.append_child("a:satMod").append_attribute("val").set_value(350000);
gs_node = grad_fill_list.append_child("a:gs");
gs_node.append_attribute("pos").set_value(100000);
scheme_color_node = gs_node.append_child("a:schemeClr");
scheme_color_node.append_attribute("val").set_value("phClr");
scheme_color_node.append_child("a:shade").append_attribute("val").set_value(20000);
scheme_color_node.append_child("a:satMod").append_attribute("val").set_value(255000);
auto path_node = grad_fill_node.append_child("a:path");
path_node.append_attribute("path").set_value("circle");
auto fill_to_rect_node = path_node.append_child("a:fillToRect");
fill_to_rect_node.append_attribute("l").set_value(50000);
fill_to_rect_node.append_attribute("t").set_value(-80000);
fill_to_rect_node.append_attribute("r").set_value(50000);
fill_to_rect_node.append_attribute("b").set_value(180000);
grad_fill_node = bg_fill_style_list_node.append_child("a:gradFill");
grad_fill_node.append_attribute("rotWithShape").set_value(1);
grad_fill_list = grad_fill_node.append_child("a:gsLst");
gs_node = grad_fill_list.append_child("a:gs");
gs_node.append_attribute("pos").set_value(0);
scheme_color_node = gs_node.append_child("a:schemeClr");
scheme_color_node.append_attribute("val").set_value("phClr");
scheme_color_node.append_child("a:tint").append_attribute("val").set_value(80000);
scheme_color_node.append_child("a:satMod").append_attribute("val").set_value(300000);
gs_node = grad_fill_list.append_child("a:gs");
gs_node.append_attribute("pos").set_value(100000);
scheme_color_node = gs_node.append_child("a:schemeClr");
scheme_color_node.append_attribute("val").set_value("phClr");
scheme_color_node.append_child("a:shade").append_attribute("val").set_value(30000);
scheme_color_node.append_child("a:satMod").append_attribute("val").set_value(200000);
path_node = grad_fill_node.append_child("a:path");
path_node.append_attribute("path").set_value("circle");
fill_to_rect_node = path_node.append_child("a:fillToRect");
fill_to_rect_node.append_attribute("l").set_value(50000);
fill_to_rect_node.append_attribute("t").set_value(50000);
fill_to_rect_node.append_attribute("r").set_value(50000);
fill_to_rect_node.append_attribute("b").set_value(50000);
theme_node.append_child("a:objectDefaults");
theme_node.append_child("a:extraClrSchemeLst");
std::stringstream ss;
doc.print(ss);
return ss.str();
}
std::string write_properties_app(const workbook &wb)
@ -223,8 +659,8 @@ std::string write_workbook(const workbook &wb)
iter--;
while (isdigit(*iter)) iter--;
auto first_digit = iter - sheet_index_string.begin();
sheet_index_string = sheet_index_string.substr(first_digit + 1);
std::size_t sheet_index = std::stoi(sheet_index_string) - 1;
sheet_index_string = sheet_index_string.substr(static_cast<std::string::size_type>(first_digit + 1));
std::size_t sheet_index = static_cast<std::size_t>(std::stoll(sheet_index_string) - 1);
auto ws = wb.get_sheet_by_index(sheet_index);
@ -260,10 +696,21 @@ std::string write_workbook_rels(const workbook &wb)
{
return write_relationships(wb.get_relationships(), "xl/");
}
std::string write_theme()
std::string write_defined_names(const xlnt::workbook &wb)
{
return "";
pugi::xml_document doc;
auto names = doc.root().append_child("names");
for(auto named_range : wb.get_named_ranges())
{
names.append_child(named_range.get_name().c_str());
}
std::ostringstream stream;
doc.save(stream);
return stream.str();
}
bool save_workbook(workbook &wb, const std::string &filename, bool as_template)
@ -275,10 +722,12 @@ bool save_workbook(workbook &wb, const std::string &filename, bool as_template)
std::vector<std::uint8_t> save_virtual_workbook(xlnt::workbook &wb, bool as_template)
{
zip_file archive;
excel_writer writer(wb);
std::vector<std::uint8_t> buffer;
zip_file archive(buffer);
writer.write_data(archive, as_template);
std::vector<std::uint8_t> buffer;
archive.save(buffer);
return buffer;
}

View File

@ -1,13 +1,14 @@
#include <algorithm>
#include <xlnt/worksheet/worksheet.hpp>
#include <xlnt/cell/cell.hpp>
#include <xlnt/common/datetime.hpp>
#include <xlnt/common/exceptions.hpp>
#include <xlnt/common/relationship.hpp>
#include <xlnt/workbook/named_range.hpp>
#include <xlnt/workbook/workbook.hpp>
#include <xlnt/worksheet/range.hpp>
#include <xlnt/worksheet/range_reference.hpp>
#include <xlnt/common/relationship.hpp>
#include <xlnt/workbook/workbook.hpp>
#include <xlnt/common/exceptions.hpp>
#include <xlnt/worksheet/worksheet.hpp>
#include "detail/worksheet_impl.hpp"
@ -52,7 +53,9 @@ std::string worksheet::unique_sheet_name(const std::string &value) const
void worksheet::create_named_range(const std::string &name, const range_reference &reference)
{
d_->named_ranges_[name] = reference;
std::vector<named_range::target> targets;
targets.push_back({*this, reference});
d_->named_ranges_[name] = named_range(name, targets);
}
range worksheet::operator()(const xlnt::cell_reference &top_left, const xlnt::cell_reference &bottom_right)
@ -97,7 +100,7 @@ bool worksheet::has_auto_filter() const
void worksheet::unset_auto_filter()
{
d_->auto_filter_ = range_reference(0, 0, 0, 0);
d_->auto_filter_ = range_reference(1, 1, 1, 1);
}
page_setup &worksheet::get_page_setup()
@ -242,7 +245,7 @@ range worksheet::get_named_range(const std::string &name)
throw named_range_exception();
}
return get_range(d_->named_ranges_[name]);
return get_range(d_->named_ranges_[name].get_targets()[0].second);
}
column_t worksheet::get_lowest_column() const
@ -311,11 +314,11 @@ column_t worksheet::get_highest_column() const
range_reference worksheet::calculate_dimension() const
{
int lowest_column = get_lowest_column();
int lowest_row = get_lowest_row();
auto lowest_column = get_lowest_column();
auto lowest_row = get_lowest_row();
int highest_column = get_highest_column();
int highest_row = get_highest_row();
auto highest_column = get_highest_column();
auto highest_row = get_highest_row();
return range_reference(lowest_column, lowest_row, highest_column, highest_row);
}
@ -430,7 +433,7 @@ void worksheet::append(const std::vector<std::string> &cells)
row_t worksheet::get_next_row() const
{
int row = get_highest_row() + 1;
auto row = get_highest_row() + 1;
if(row == 2 && d_->cell_map_.size() == 0)
{
@ -489,7 +492,7 @@ void worksheet::append(const std::unordered_map<int, std::string> &cells)
for(auto cell : cells)
{
get_cell(cell_reference(cell.first, row)).set_value(cell.second);
get_cell(cell_reference(static_cast<column_t>(cell.first), row)).set_value(cell.second);
}
}

353
source/worksheet_writer.cpp Normal file
View File

@ -0,0 +1,353 @@
#include <sstream>
#include <xlnt/cell/cell.hpp>
#include <xlnt/cell/cell_reference.hpp>
#include <xlnt/worksheet/range.hpp>
#include <xlnt/worksheet/range_reference.hpp>
#include <xlnt/worksheet/worksheet.hpp>
#include <xlnt/writer/worksheet_writer.hpp>
#include "constants.hpp"
#include "detail/include_pugixml.hpp"
namespace {
bool is_integral(long double d)
{
return d == static_cast<long long int>(d);
}
} // namepsace
namespace xlnt {
std::string write_worksheet(worksheet ws, const std::vector<std::string> &string_table, const std::unordered_map<std::size_t, std::string> &style_id_by_hash)
{
ws.get_cell("A1");
pugi::xml_document doc;
auto root_node = doc.append_child("worksheet");
root_node.append_attribute("xmlns").set_value(constants::Namespaces.at("spreadsheetml").c_str());
root_node.append_attribute("xmlns:r").set_value(constants::Namespaces.at("r").c_str());
auto sheet_pr_node = root_node.append_child("sheetPr");
auto outline_pr_node = sheet_pr_node.append_child("outlinePr");
if(!ws.get_page_setup().is_default())
{
auto page_set_up_pr_node = sheet_pr_node.append_child("pageSetUpPr");
page_set_up_pr_node.append_attribute("fitToPage").set_value(ws.get_page_setup().fit_to_page() ? 1 : 0);
}
outline_pr_node.append_attribute("summaryBelow").set_value(1);
outline_pr_node.append_attribute("summaryRight").set_value(1);
auto dimension_node = root_node.append_child("dimension");
dimension_node.append_attribute("ref").set_value(ws.calculate_dimension().to_string().c_str());
auto sheet_views_node = root_node.append_child("sheetViews");
auto sheet_view_node = sheet_views_node.append_child("sheetView");
sheet_view_node.append_attribute("workbookViewId").set_value(0);
std::string active_pane = "bottomRight";
if(ws.has_frozen_panes())
{
auto pane_node = sheet_view_node.append_child("pane");
if(ws.get_frozen_panes().get_column_index() > 1)
{
pane_node.append_attribute("xSplit").set_value(ws.get_frozen_panes().get_column_index() - 1);
active_pane = "topRight";
}
if(ws.get_frozen_panes().get_row() > 1)
{
pane_node.append_attribute("ySplit").set_value(ws.get_frozen_panes().get_row() - 1);
active_pane = "bottomLeft";
}
if(ws.get_frozen_panes().get_row() > 1 && ws.get_frozen_panes().get_column_index() > 1)
{
auto top_right_node = sheet_view_node.append_child("selection");
top_right_node.append_attribute("pane").set_value("topRight");
auto bottom_left_node = sheet_view_node.append_child("selection");
bottom_left_node.append_attribute("pane").set_value("bottomLeft");
active_pane = "bottomRight";
}
pane_node.append_attribute("topLeftCell").set_value(ws.get_frozen_panes().to_string().c_str());
pane_node.append_attribute("activePane").set_value(active_pane.c_str());
pane_node.append_attribute("state").set_value("frozen");
}
auto selection_node = sheet_view_node.append_child("selection");
if(ws.has_frozen_panes())
{
if(ws.get_frozen_panes().get_row() > 1 && ws.get_frozen_panes().get_column_index() > 1)
{
selection_node.append_attribute("pane").set_value("bottomRight");
}
else if(ws.get_frozen_panes().get_row() > 1)
{
selection_node.append_attribute("pane").set_value("bottomLeft");
}
else if(ws.get_frozen_panes().get_column_index() > 1)
{
selection_node.append_attribute("pane").set_value("topRight");
}
}
std::string active_cell = "A1";
selection_node.append_attribute("activeCell").set_value(active_cell.c_str());
selection_node.append_attribute("sqref").set_value(active_cell.c_str());
auto sheet_format_pr_node = root_node.append_child("sheetFormatPr");
sheet_format_pr_node.append_attribute("baseColWidth").set_value(10);
sheet_format_pr_node.append_attribute("defaultRowHeight").set_value(15);
std::vector<column_t> styled_columns;
if(!style_id_by_hash.empty())
{
for(auto row : ws.rows())
{
for(auto cell : row)
{
if(cell.has_style())
{
styled_columns.push_back(cell_reference::column_index_from_string(cell.get_column()));
}
}
}
auto cols_node = root_node.append_child("cols");
std::sort(styled_columns.begin(), styled_columns.end());
for(auto column : styled_columns)
{
auto col_node = cols_node.append_child("col");
col_node.append_attribute("min").set_value(column);
col_node.append_attribute("max").set_value(column);
col_node.append_attribute("style").set_value(1);
}
}
std::unordered_map<std::string, std::string> hyperlink_references;
auto sheet_data_node = root_node.append_child("sheetData");
for(auto row : ws.rows())
{
row_t min = static_cast<row_t>(row.num_cells());
row_t max = 0;
bool any_non_null = false;
for(auto cell : row)
{
min = std::min(min, cell_reference::column_index_from_string(cell.get_column()));
max = std::max(max, cell_reference::column_index_from_string(cell.get_column()));
if(!cell.garbage_collectible())
{
any_non_null = true;
}
}
if(!any_non_null)
{
continue;
}
auto row_node = sheet_data_node.append_child("row");
row_node.append_attribute("r").set_value(row.front().get_row());
row_node.append_attribute("spans").set_value((std::to_string(min) + ":" + std::to_string(max)).c_str());
if(ws.has_row_properties(row.front().get_row()))
{
row_node.append_attribute("customHeight").set_value(1);
auto height = ws.get_row_properties(row.front().get_row()).height;
if(height == std::floor(height))
{
row_node.append_attribute("ht").set_value((std::to_string((int)height) + ".0").c_str());
}
else
{
row_node.append_attribute("ht").set_value(height);
}
}
//row_node.append_attribute("x14ac:dyDescent").set_value(0.25);
for(auto cell : row)
{
if(!cell.garbage_collectible())
{
if(cell.has_hyperlink())
{
hyperlink_references[cell.get_hyperlink().get_id()] = cell.get_reference().to_string();
}
auto cell_node = row_node.append_child("c");
cell_node.append_attribute("r").set_value(cell.get_reference().to_string().c_str());
if(cell.get_data_type() == cell::type::string)
{
if(cell.has_formula())
{
cell_node.append_attribute("t").set_value("str");
cell_node.append_child("f").text().set(cell.get_formula().c_str());
cell_node.append_child("v").text().set(cell.to_string().c_str());
continue;
}
int match_index = -1;
for(std::size_t i = 0; i < string_table.size(); i++)
{
if(string_table[i] == cell.get_value<std::string>())
{
match_index = static_cast<int>(i);
break;
}
}
if(match_index == -1)
{
if(cell.get_value<std::string>().empty())
{
cell_node.append_attribute("t").set_value("s");
}
else
{
cell_node.append_attribute("t").set_value("inlineStr");
auto inline_string_node = cell_node.append_child("is");
inline_string_node.append_child("t").text().set(cell.get_value<std::string>().c_str());
}
}
else
{
cell_node.append_attribute("t").set_value("s");
auto value_node = cell_node.append_child("v");
value_node.text().set(match_index);
}
}
else
{
if(cell.get_data_type() != cell::type::null)
{
if(cell.get_data_type() == cell::type::boolean)
{
cell_node.append_attribute("t").set_value("b");
auto value_node = cell_node.append_child("v");
value_node.text().set(cell.get_value<bool>() ? 1 : 0);
}
else if(cell.get_data_type() == cell::type::numeric)
{
if(cell.has_formula())
{
cell_node.append_child("f").text().set(cell.get_formula().c_str());
cell_node.append_child("v").text().set(cell.to_string().c_str());
continue;
}
cell_node.append_attribute("t").set_value("n");
auto value_node = cell_node.append_child("v");
if(is_integral(cell.get_value<long double>()))
{
value_node.text().set(cell.get_value<long long>());
}
else
{
std::stringstream ss;
ss.precision(20);
ss << cell.get_value<long double>();
ss.str();
value_node.text().set(ss.str().c_str());
}
}
}
else if(cell.has_formula())
{
cell_node.append_child("f").text().set(cell.get_formula().c_str());
cell_node.append_child("v");
continue;
}
}
if(cell.has_style())
{
cell_node.append_attribute("s").set_value(1);
}
}
}
}
if(ws.has_auto_filter())
{
auto auto_filter_node = root_node.append_child("autoFilter");
auto_filter_node.append_attribute("ref").set_value(ws.get_auto_filter().to_string().c_str());
}
if(!ws.get_merged_ranges().empty())
{
auto merge_cells_node = root_node.append_child("mergeCells");
merge_cells_node.append_attribute("count").set_value((unsigned int)ws.get_merged_ranges().size());
for(auto merged_range : ws.get_merged_ranges())
{
auto merge_cell_node = merge_cells_node.append_child("mergeCell");
merge_cell_node.append_attribute("ref").set_value(merged_range.to_string().c_str());
}
}
if(!ws.get_relationships().empty())
{
auto hyperlinks_node = root_node.append_child("hyperlinks");
for(auto relationship : ws.get_relationships())
{
auto hyperlink_node = hyperlinks_node.append_child("hyperlink");
hyperlink_node.append_attribute("display").set_value(relationship.get_target_uri().c_str());
hyperlink_node.append_attribute("ref").set_value(hyperlink_references.at(relationship.get_id()).c_str());
hyperlink_node.append_attribute("r:id").set_value(relationship.get_id().c_str());
}
}
if(!ws.get_page_setup().is_default())
{
auto print_options_node = root_node.append_child("printOptions");
print_options_node.append_attribute("horizontalCentered").set_value(ws.get_page_setup().get_horizontal_centered() ? 1 : 0);
print_options_node.append_attribute("verticalCentered").set_value(ws.get_page_setup().get_vertical_centered() ? 1 : 0);
}
auto page_margins_node = root_node.append_child("pageMargins");
page_margins_node.append_attribute("left").set_value(ws.get_page_margins().get_left());
page_margins_node.append_attribute("right").set_value(ws.get_page_margins().get_right());
page_margins_node.append_attribute("top").set_value(ws.get_page_margins().get_top());
page_margins_node.append_attribute("bottom").set_value(ws.get_page_margins().get_bottom());
page_margins_node.append_attribute("header").set_value(ws.get_page_margins().get_header());
page_margins_node.append_attribute("footer").set_value(ws.get_page_margins().get_footer());
if(!ws.get_page_setup().is_default())
{
auto page_setup_node = root_node.append_child("pageSetup");
std::string orientation_string = ws.get_page_setup().get_orientation() == page_setup::orientation::landscape ? "landscape" : "portrait";
page_setup_node.append_attribute("orientation").set_value(orientation_string.c_str());
page_setup_node.append_attribute("paperSize").set_value((int)ws.get_page_setup().get_paper_size());
page_setup_node.append_attribute("fitToHeight").set_value(ws.get_page_setup().fit_to_height() ? 1 : 0);
page_setup_node.append_attribute("fitToWidth").set_value(ws.get_page_setup().fit_to_width() ? 1 : 0);
}
if(!ws.get_header_footer().is_default())
{
auto header_footer_node = root_node.append_child("headerFooter");
auto odd_header_node = header_footer_node.append_child("oddHeader");
std::string header_text = "&L&\"Calibri,Regular\"&K000000Left Header Text&C&\"Arial,Regular\"&6&K445566Center Header Text&R&\"Arial,Bold\"&8&K112233Right Header Text";
odd_header_node.text().set(header_text.c_str());
auto odd_footer_node = header_footer_node.append_child("oddFooter");
std::string footer_text = "&L&\"Times New Roman,Regular\"&10&K445566Left Footer Text_x000D_And &D and &T&C&\"Times New Roman,Bold\"&12&K778899Center Footer Text &Z&F on &A&R&\"Times New Roman,Italic\"&14&KAABBCCRight Footer Text &P of &N";
odd_footer_node.text().set(footer_text.c_str());
}
std::stringstream ss;
doc.save(ss);
return ss.str();
}
} // namespace xlnt

View File

@ -1,798 +0,0 @@
#include <algorithm>
#include <array>
#include <cmath>
#include <sstream>
#include <string>
#include <unordered_map>
#include <xlnt/cell/cell.hpp>
#include <xlnt/common/relationship.hpp>
#include <xlnt/workbook/document_properties.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/relationship_writer.hpp>
#include <xlnt/writer/writer.hpp>
#include "constants.hpp"
#include "detail/include_pugixml.hpp"
namespace {
bool is_integral(long double d)
{
return d == static_cast<long long int>(d);
}
} // namespace
namespace xlnt {
std::string writer::write_shared_strings(const std::vector<std::string> &string_table)
{
pugi::xml_document doc;
auto root_node = doc.append_child("sst");
root_node.append_attribute("xmlns").set_value("http://schemas.openxmlformats.org/spreadsheetml/2006/main");
root_node.append_attribute("uniqueCount").set_value((int)string_table.size());
for(auto string : string_table)
{
root_node.append_child("si").append_child("t").text().set(string.c_str());
}
std::stringstream ss;
doc.save(ss);
return ss.str();
}
std::string fill(const std::string &string, std::size_t length = 2)
{
if(string.size() >= length)
{
return string;
}
return std::string(length - string.size(), '0') + string;
}
std::string datetime_to_w3cdtf(const datetime &dt)
{
return std::to_string(dt.year) + "-" + fill(std::to_string(dt.month)) + "-" + fill(std::to_string(dt.day)) + "T" + fill(std::to_string(dt.hour)) + ":" + fill(std::to_string(dt.minute)) + ":" + fill(std::to_string(dt.second)) + "Z";
}
std::string writer::write_properties_core(const document_properties &prop)
{
pugi::xml_document doc;
auto root_node = doc.append_child("cp:coreProperties");
root_node.append_attribute("xmlns:cp").set_value("http://schemas.openxmlformats.org/package/2006/metadata/core-properties");
root_node.append_attribute("xmlns:dc").set_value("http://purl.org/dc/elements/1.1/");
root_node.append_attribute("xmlns:dcmitype").set_value("http://purl.org/dc/dcmitype/");
root_node.append_attribute("xmlns:dcterms").set_value("http://purl.org/dc/terms/");
root_node.append_attribute("xmlns:xsi").set_value("http://www.w3.org/2001/XMLSchema-instance");
root_node.append_child("dc:creator").text().set(prop.creator.c_str());
root_node.append_child("cp:lastModifiedBy").text().set(prop.last_modified_by.c_str());
root_node.append_child("dcterms:created").text().set(datetime_to_w3cdtf(prop.created).c_str());
root_node.child("dcterms:created").append_attribute("xsi:type").set_value("dcterms:W3CDTF");
root_node.append_child("dcterms:modified").text().set(datetime_to_w3cdtf(prop.modified).c_str());
root_node.child("dcterms:modified").append_attribute("xsi:type").set_value("dcterms:W3CDTF");
root_node.append_child("dc:title").text().set(prop.title.c_str());
root_node.append_child("dc:description");
root_node.append_child("dc:subject");
root_node.append_child("cp:keywords");
root_node.append_child("cp:category");
std::stringstream ss;
doc.save(ss);
return ss.str();
}
std::string writer::write_worksheet_rels(worksheet ws)
{
return write_relationships(ws.get_relationships(), "");
}
std::string writer::write_worksheet(worksheet ws, const std::vector<std::string> &string_table, const std::unordered_map<std::size_t, std::string> &style_id_by_hash)
{
ws.get_cell("A1");
pugi::xml_document doc;
auto root_node = doc.append_child("worksheet");
root_node.append_attribute("xmlns").set_value(constants::Namespaces.at("spreadsheetml").c_str());
root_node.append_attribute("xmlns:r").set_value(constants::Namespaces.at("r").c_str());
auto sheet_pr_node = root_node.append_child("sheetPr");
auto outline_pr_node = sheet_pr_node.append_child("outlinePr");
if(!ws.get_page_setup().is_default())
{
auto page_set_up_pr_node = sheet_pr_node.append_child("pageSetUpPr");
page_set_up_pr_node.append_attribute("fitToPage").set_value(ws.get_page_setup().fit_to_page() ? 1 : 0);
}
outline_pr_node.append_attribute("summaryBelow").set_value(1);
outline_pr_node.append_attribute("summaryRight").set_value(1);
auto dimension_node = root_node.append_child("dimension");
dimension_node.append_attribute("ref").set_value(ws.calculate_dimension().to_string().c_str());
auto sheet_views_node = root_node.append_child("sheetViews");
auto sheet_view_node = sheet_views_node.append_child("sheetView");
sheet_view_node.append_attribute("workbookViewId").set_value(0);
std::string active_pane = "bottomRight";
if(ws.has_frozen_panes())
{
auto pane_node = sheet_view_node.append_child("pane");
if(ws.get_frozen_panes().get_column_index() > 1)
{
pane_node.append_attribute("xSplit").set_value(ws.get_frozen_panes().get_column_index() - 1);
active_pane = "topRight";
}
if(ws.get_frozen_panes().get_row() > 1)
{
pane_node.append_attribute("ySplit").set_value(ws.get_frozen_panes().get_row() - 1);
active_pane = "bottomLeft";
}
if(ws.get_frozen_panes().get_row() > 1 && ws.get_frozen_panes().get_column_index() > 1)
{
auto top_right_node = sheet_view_node.append_child("selection");
top_right_node.append_attribute("pane").set_value("topRight");
auto bottom_left_node = sheet_view_node.append_child("selection");
bottom_left_node.append_attribute("pane").set_value("bottomLeft");
active_pane = "bottomRight";
}
pane_node.append_attribute("topLeftCell").set_value(ws.get_frozen_panes().to_string().c_str());
pane_node.append_attribute("activePane").set_value(active_pane.c_str());
pane_node.append_attribute("state").set_value("frozen");
}
auto selection_node = sheet_view_node.append_child("selection");
if(ws.has_frozen_panes())
{
if(ws.get_frozen_panes().get_row() > 1 && ws.get_frozen_panes().get_column_index() > 1)
{
selection_node.append_attribute("pane").set_value("bottomRight");
}
else if(ws.get_frozen_panes().get_row() > 1)
{
selection_node.append_attribute("pane").set_value("bottomLeft");
}
else if(ws.get_frozen_panes().get_column_index() > 1)
{
selection_node.append_attribute("pane").set_value("topRight");
}
}
std::string active_cell = "A1";
selection_node.append_attribute("activeCell").set_value(active_cell.c_str());
selection_node.append_attribute("sqref").set_value(active_cell.c_str());
auto sheet_format_pr_node = root_node.append_child("sheetFormatPr");
sheet_format_pr_node.append_attribute("baseColWidth").set_value(10);
sheet_format_pr_node.append_attribute("defaultRowHeight").set_value(15);
std::vector<int> styled_columns;
if(!style_id_by_hash.empty())
{
for(auto row : ws.rows())
{
for(auto cell : row)
{
if(cell.has_style())
{
styled_columns.push_back(xlnt::cell_reference::column_index_from_string(cell.get_column()));
}
}
}
auto cols_node = root_node.append_child("cols");
std::sort(styled_columns.begin(), styled_columns.end());
for(auto column : styled_columns)
{
auto col_node = cols_node.append_child("col");
col_node.append_attribute("min").set_value(column);
col_node.append_attribute("max").set_value(column);
col_node.append_attribute("style").set_value(1);
}
}
std::unordered_map<std::string, std::string> hyperlink_references;
auto sheet_data_node = root_node.append_child("sheetData");
for(auto row : ws.rows())
{
row_t min = (int)row.num_cells();
row_t max = 0;
bool any_non_null = false;
for(auto cell : row)
{
min = std::min(min, cell_reference::column_index_from_string(cell.get_column()));
max = std::max(max, cell_reference::column_index_from_string(cell.get_column()));
if(!cell.garbage_collectible())
{
any_non_null = true;
}
}
if(!any_non_null)
{
continue;
}
auto row_node = sheet_data_node.append_child("row");
row_node.append_attribute("r").set_value(row.front().get_row());
row_node.append_attribute("spans").set_value((std::to_string(min) + ":" + std::to_string(max)).c_str());
if(ws.has_row_properties(row.front().get_row()))
{
row_node.append_attribute("customHeight").set_value(1);
auto height = ws.get_row_properties(row.front().get_row()).height;
if(height == std::floor(height))
{
row_node.append_attribute("ht").set_value((std::to_string((int)height) + ".0").c_str());
}
else
{
row_node.append_attribute("ht").set_value(height);
}
}
//row_node.append_attribute("x14ac:dyDescent").set_value(0.25);
for(auto cell : row)
{
if(!cell.garbage_collectible())
{
if(cell.has_hyperlink())
{
hyperlink_references[cell.get_hyperlink().get_id()] = cell.get_reference().to_string();
}
auto cell_node = row_node.append_child("c");
cell_node.append_attribute("r").set_value(cell.get_reference().to_string().c_str());
if(cell.get_data_type() == cell::type::string)
{
if(cell.has_formula())
{
cell_node.append_attribute("t").set_value("str");
cell_node.append_child("f").text().set(cell.get_formula().c_str());
cell_node.append_child("v").text().set(cell.to_string().c_str());
continue;
}
int match_index = -1;
for(int i = 0; i < (int)string_table.size(); i++)
{
if(string_table[i] == cell.get_value<std::string>())
{
match_index = i;
break;
}
}
if(match_index == -1)
{
if(cell.get_value<std::string>().empty())
{
cell_node.append_attribute("t").set_value("s");
}
else
{
cell_node.append_attribute("t").set_value("inlineStr");
auto inline_string_node = cell_node.append_child("is");
inline_string_node.append_child("t").text().set(cell.get_value<std::string>().c_str());
}
}
else
{
cell_node.append_attribute("t").set_value("s");
auto value_node = cell_node.append_child("v");
value_node.text().set(match_index);
}
}
else
{
if(cell.get_data_type() != cell::type::null)
{
if(cell.get_data_type() == cell::type::boolean)
{
cell_node.append_attribute("t").set_value("b");
auto value_node = cell_node.append_child("v");
value_node.text().set(cell.get_value<bool>() ? 1 : 0);
}
else if(cell.get_data_type() == cell::type::numeric)
{
if(cell.has_formula())
{
cell_node.append_child("f").text().set(cell.get_formula().c_str());
cell_node.append_child("v").text().set(cell.to_string().c_str());
continue;
}
cell_node.append_attribute("t").set_value("n");
auto value_node = cell_node.append_child("v");
if(is_integral(cell.get_value<long double>()))
{
value_node.text().set(cell.get_value<long long>());
}
else
{
std::stringstream ss;
ss.precision(20);
ss << cell.get_value<long double>();
ss.str();
value_node.text().set(ss.str().c_str());
}
}
}
else if(cell.has_formula())
{
cell_node.append_child("f").text().set(cell.get_formula().c_str());
cell_node.append_child("v");
continue;
}
}
if(cell.has_style())
{
cell_node.append_attribute("s").set_value(1);
}
}
}
}
if(ws.has_auto_filter())
{
auto auto_filter_node = root_node.append_child("autoFilter");
auto_filter_node.append_attribute("ref").set_value(ws.get_auto_filter().to_string().c_str());
}
if(!ws.get_merged_ranges().empty())
{
auto merge_cells_node = root_node.append_child("mergeCells");
merge_cells_node.append_attribute("count").set_value((unsigned int)ws.get_merged_ranges().size());
for(auto merged_range : ws.get_merged_ranges())
{
auto merge_cell_node = merge_cells_node.append_child("mergeCell");
merge_cell_node.append_attribute("ref").set_value(merged_range.to_string().c_str());
}
}
if(!ws.get_relationships().empty())
{
auto hyperlinks_node = root_node.append_child("hyperlinks");
for(auto relationship : ws.get_relationships())
{
auto hyperlink_node = hyperlinks_node.append_child("hyperlink");
hyperlink_node.append_attribute("display").set_value(relationship.get_target_uri().c_str());
hyperlink_node.append_attribute("ref").set_value(hyperlink_references.at(relationship.get_id()).c_str());
hyperlink_node.append_attribute("r:id").set_value(relationship.get_id().c_str());
}
}
if(!ws.get_page_setup().is_default())
{
auto print_options_node = root_node.append_child("printOptions");
print_options_node.append_attribute("horizontalCentered").set_value(ws.get_page_setup().get_horizontal_centered() ? 1 : 0);
print_options_node.append_attribute("verticalCentered").set_value(ws.get_page_setup().get_vertical_centered() ? 1 : 0);
}
auto page_margins_node = root_node.append_child("pageMargins");
page_margins_node.append_attribute("left").set_value(ws.get_page_margins().get_left());
page_margins_node.append_attribute("right").set_value(ws.get_page_margins().get_right());
page_margins_node.append_attribute("top").set_value(ws.get_page_margins().get_top());
page_margins_node.append_attribute("bottom").set_value(ws.get_page_margins().get_bottom());
page_margins_node.append_attribute("header").set_value(ws.get_page_margins().get_header());
page_margins_node.append_attribute("footer").set_value(ws.get_page_margins().get_footer());
if(!ws.get_page_setup().is_default())
{
auto page_setup_node = root_node.append_child("pageSetup");
std::string orientation_string = ws.get_page_setup().get_orientation() == page_setup::orientation::landscape ? "landscape" : "portrait";
page_setup_node.append_attribute("orientation").set_value(orientation_string.c_str());
page_setup_node.append_attribute("paperSize").set_value((int)ws.get_page_setup().get_paper_size());
page_setup_node.append_attribute("fitToHeight").set_value(ws.get_page_setup().fit_to_height() ? 1 : 0);
page_setup_node.append_attribute("fitToWidth").set_value(ws.get_page_setup().fit_to_width() ? 1 : 0);
}
if(!ws.get_header_footer().is_default())
{
auto header_footer_node = root_node.append_child("headerFooter");
auto odd_header_node = header_footer_node.append_child("oddHeader");
std::string header_text = "&L&\"Calibri,Regular\"&K000000Left Header Text&C&\"Arial,Regular\"&6&K445566Center Header Text&R&\"Arial,Bold\"&8&K112233Right Header Text";
odd_header_node.text().set(header_text.c_str());
auto odd_footer_node = header_footer_node.append_child("oddFooter");
std::string footer_text = "&L&\"Times New Roman,Regular\"&10&K445566Left Footer Text_x000D_And &D and &T&C&\"Times New Roman,Bold\"&12&K778899Center Footer Text &Z&F on &A&R&\"Times New Roman,Italic\"&14&KAABBCCRight Footer Text &P of &N";
odd_footer_node.text().set(footer_text.c_str());
}
std::stringstream ss;
doc.save(ss);
return ss.str();
}
std::string writer::write_content_types(const workbook &wb)
{
pugi::xml_document doc;
auto root_node = doc.append_child("Types");
root_node.append_attribute("xmlns").set_value(constants::Namespaces.at("content-types").c_str());
for(auto type : wb.get_content_types())
{
pugi::xml_node type_node;
if (type.is_default)
{
type_node = root_node.append_child("Default");
type_node.append_attribute("Extension").set_value(type.extension.c_str());
}
else
{
type_node = root_node.append_child("Override");
type_node.append_attribute("PartName").set_value(type.part_name.c_str());
}
type_node.append_attribute("ContentType").set_value(type.type.c_str());
}
std::stringstream ss;
doc.save(ss);
return ss.str();
}
std::string writer::write_theme()
{
pugi::xml_document doc;
auto theme_node = doc.append_child("a:theme");
theme_node.append_attribute("xmlns:a").set_value(constants::Namespaces.at("drawingml").c_str());
theme_node.append_attribute("name").set_value("Office Theme");
auto theme_elements_node = theme_node.append_child("a:themeElements");
auto clr_scheme_node = theme_elements_node.append_child("a:clrScheme");
clr_scheme_node.append_attribute("name").set_value("Office");
struct scheme_element
{
std::string name;
std::string sub_element_name;
std::string val;
};
std::vector<scheme_element> scheme_elements =
{
{"a:dk1", "a:sysClr", "windowText"},
{"a:lt1", "a:sysClr", "window"},
{"a:dk2", "a:srgbClr", "1F497D"},
{"a:lt2", "a:srgbClr", "EEECE1"},
{"a:accent1", "a:srgbClr", "4F81BD"},
{"a:accent2", "a:srgbClr", "C0504D"},
{"a:accent3", "a:srgbClr", "9BBB59"},
{"a:accent4", "a:srgbClr", "8064A2"},
{"a:accent5", "a:srgbClr", "4BACC6"},
{"a:accent6", "a:srgbClr", "F79646"},
{"a:hlink", "a:srgbClr", "0000FF"},
{"a:folHlink", "a:srgbClr", "800080"},
};
for(auto element : scheme_elements)
{
auto element_node = clr_scheme_node.append_child(element.name.c_str());
element_node.append_child(element.sub_element_name.c_str()).append_attribute("val").set_value(element.val.c_str());
if(element.name == "a:dk1")
{
element_node.child(element.sub_element_name.c_str()).append_attribute("lastClr").set_value("000000");
}
else if(element.name == "a:lt1")
{
element_node.child(element.sub_element_name.c_str()).append_attribute("lastClr").set_value("FFFFFF");
}
}
struct font_scheme
{
bool typeface;
std::string script;
std::string major;
std::string minor;
};
std::vector<font_scheme> font_schemes =
{
{true, "a:latin", "Cambria", "Calibri"},
{true, "a:ea", "", ""},
{true, "a:cs", "", ""},
{false, "Jpan", "\xef\xbc\xad\xef\xbc\xb3 \xef\xbc\xb0\xe3\x82\xb4\xe3\x82\xb7\xe3\x83\x83\xe3\x82\xaf", "\xef\xbc\xad\xef\xbc\xb3 \xef\xbc\xb0\xe3\x82\xb4\xe3\x82\xb7\xe3\x83\x83\xe3\x82\xaf"},
{false, "Hang", "\xeb\xa7\x91\xec\x9d\x80 \xea\xb3\xa0\xeb\x94\x95", "\xeb\xa7\x91\xec\x9d\x80 \xea\xb3\xa0\xeb\x94\x95"},
{false, "Hans", "\xe5\xae\x8b\xe4\xbd\x93", "\xe5\xae\x8b\xe4\xbd\x93"},
{false, "Hant", "\xe6\x96\xb0\xe7\xb4\xb0\xe6\x98\x8e\xe9\xab\x94", "\xe6\x96\xb0\xe7\xb4\xb0\xe6\x98\x8e\xe9\xab\x94"},
{false, "Arab", "Times New Roman", "Arial"},
{false, "Hebr", "Times New Roman", "Arial"},
{false, "Thai", "Tahoma", "Tahoma"},
{false, "Ethi", "Nyala", "Nyala"},
{false, "Beng", "Vrinda", "Vrinda"},
{false, "Gujr", "Shruti", "Shruti"},
{false, "Khmr", "MoolBoran", "DaunPenh"},
{false, "Knda", "Tunga", "Tunga"},
{false, "Guru", "Raavi", "Raavi"},
{false, "Cans", "Euphemia", "Euphemia"},
{false, "Cher", "Plantagenet Cherokee", "Plantagenet Cherokee"},
{false, "Yiii", "Microsoft Yi Baiti", "Microsoft Yi Baiti"},
{false, "Tibt", "Microsoft Himalaya", "Microsoft Himalaya"},
{false, "Thaa", "MV Boli", "MV Boli"},
{false, "Deva", "Mangal", "Mangal"},
{false, "Telu", "Gautami", "Gautami"},
{false, "Taml", "Latha", "Latha"},
{false, "Syrc", "Estrangelo Edessa", "Estrangelo Edessa"},
{false, "Orya", "Kalinga", "Kalinga"},
{false, "Mlym", "Kartika", "Kartika"},
{false, "Laoo", "DokChampa", "DokChampa"},
{false, "Sinh", "Iskoola Pota", "Iskoola Pota"},
{false, "Mong", "Mongolian Baiti", "Mongolian Baiti"},
{false, "Viet", "Times New Roman", "Arial"},
{false, "Uigh", "Microsoft Uighur", "Microsoft Uighur"}
};
auto font_scheme_node = theme_elements_node.append_child("a:fontScheme");
font_scheme_node.append_attribute("name").set_value("Office");
auto major_fonts_node = font_scheme_node.append_child("a:majorFont");
auto minor_fonts_node = font_scheme_node.append_child("a:minorFont");
for(auto scheme : font_schemes)
{
pugi::xml_node major_font_node, minor_font_node;
if(scheme.typeface)
{
major_font_node = major_fonts_node.append_child(scheme.script.c_str());
minor_font_node = minor_fonts_node.append_child(scheme.script.c_str());
}
else
{
major_font_node = major_fonts_node.append_child("a:font");
major_font_node.append_attribute("script").set_value(scheme.script.c_str());
minor_font_node = minor_fonts_node.append_child("a:font");
minor_font_node.append_attribute("script").set_value(scheme.script.c_str());
}
major_font_node.append_attribute("typeface").set_value(scheme.major.c_str());
minor_font_node.append_attribute("typeface").set_value(scheme.minor.c_str());
}
auto format_scheme_node = theme_elements_node.append_child("a:fmtScheme");
format_scheme_node.append_attribute("name").set_value("Office");
auto fill_style_list_node = format_scheme_node.append_child("a:fillStyleLst");
fill_style_list_node.append_child("a:solidFill").append_child("a:schemeClr").append_attribute("val").set_value("phClr");
auto grad_fill_node = fill_style_list_node.append_child("a:gradFill");
grad_fill_node.append_attribute("rotWithShape").set_value(1);
auto grad_fill_list = grad_fill_node.append_child("a:gsLst");
auto gs_node = grad_fill_list.append_child("a:gs");
gs_node.append_attribute("pos").set_value(0);
auto scheme_color_node = gs_node.append_child("a:schemeClr");
scheme_color_node.append_attribute("val").set_value("phClr");
scheme_color_node.append_child("a:tint").append_attribute("val").set_value(50000);
scheme_color_node.append_child("a:satMod").append_attribute("val").set_value(300000);
gs_node = grad_fill_list.append_child("a:gs");
gs_node.append_attribute("pos").set_value(35000);
scheme_color_node = gs_node.append_child("a:schemeClr");
scheme_color_node.append_attribute("val").set_value("phClr");
scheme_color_node.append_child("a:tint").append_attribute("val").set_value(37000);
scheme_color_node.append_child("a:satMod").append_attribute("val").set_value(300000);
gs_node = grad_fill_list.append_child("a:gs");
gs_node.append_attribute("pos").set_value(100000);
scheme_color_node = gs_node.append_child("a:schemeClr");
scheme_color_node.append_attribute("val").set_value("phClr");
scheme_color_node.append_child("a:tint").append_attribute("val").set_value(15000);
scheme_color_node.append_child("a:satMod").append_attribute("val").set_value(350000);
auto lin_node = grad_fill_node.append_child("a:lin");
lin_node.append_attribute("ang").set_value(16200000);
lin_node.append_attribute("scaled").set_value(1);
grad_fill_node = fill_style_list_node.append_child("a:gradFill");
grad_fill_node.append_attribute("rotWithShape").set_value(1);
grad_fill_list = grad_fill_node.append_child("a:gsLst");
gs_node = grad_fill_list.append_child("a:gs");
gs_node.append_attribute("pos").set_value(0);
scheme_color_node = gs_node.append_child("a:schemeClr");
scheme_color_node.append_attribute("val").set_value("phClr");
scheme_color_node.append_child("a:shade").append_attribute("val").set_value(51000);
scheme_color_node.append_child("a:satMod").append_attribute("val").set_value(130000);
gs_node = grad_fill_list.append_child("a:gs");
gs_node.append_attribute("pos").set_value(80000);
scheme_color_node = gs_node.append_child("a:schemeClr");
scheme_color_node.append_attribute("val").set_value("phClr");
scheme_color_node.append_child("a:shade").append_attribute("val").set_value(93000);
scheme_color_node.append_child("a:satMod").append_attribute("val").set_value(130000);
gs_node = grad_fill_list.append_child("a:gs");
gs_node.append_attribute("pos").set_value(100000);
scheme_color_node = gs_node.append_child("a:schemeClr");
scheme_color_node.append_attribute("val").set_value("phClr");
scheme_color_node.append_child("a:shade").append_attribute("val").set_value(94000);
scheme_color_node.append_child("a:satMod").append_attribute("val").set_value(135000);
lin_node = grad_fill_node.append_child("a:lin");
lin_node.append_attribute("ang").set_value(16200000);
lin_node.append_attribute("scaled").set_value(0);
auto line_style_list_node = format_scheme_node.append_child("a:lnStyleLst");
auto ln_node = line_style_list_node.append_child("a:ln");
ln_node.append_attribute("w").set_value(9525);
ln_node.append_attribute("cap").set_value("flat");
ln_node.append_attribute("cmpd").set_value("sng");
ln_node.append_attribute("algn").set_value("ctr");
auto solid_fill_node = ln_node.append_child("a:solidFill");
scheme_color_node = solid_fill_node.append_child("a:schemeClr");
scheme_color_node.append_attribute("val").set_value("phClr");
scheme_color_node.append_child("a:shade").append_attribute("val").set_value(95000);
scheme_color_node.append_child("a:satMod").append_attribute("val").set_value(105000);
ln_node.append_child("a:prstDash").append_attribute("val").set_value("solid");
ln_node = line_style_list_node.append_child("a:ln");
ln_node.append_attribute("w").set_value(25400);
ln_node.append_attribute("cap").set_value("flat");
ln_node.append_attribute("cmpd").set_value("sng");
ln_node.append_attribute("algn").set_value("ctr");
solid_fill_node = ln_node.append_child("a:solidFill");
scheme_color_node = solid_fill_node.append_child("a:schemeClr");
scheme_color_node.append_attribute("val").set_value("phClr");
ln_node.append_child("a:prstDash").append_attribute("val").set_value("solid");
ln_node = line_style_list_node.append_child("a:ln");
ln_node.append_attribute("w").set_value(38100);
ln_node.append_attribute("cap").set_value("flat");
ln_node.append_attribute("cmpd").set_value("sng");
ln_node.append_attribute("algn").set_value("ctr");
solid_fill_node = ln_node.append_child("a:solidFill");
scheme_color_node = solid_fill_node.append_child("a:schemeClr");
scheme_color_node.append_attribute("val").set_value("phClr");
ln_node.append_child("a:prstDash").append_attribute("val").set_value("solid");
auto effect_style_list_node = format_scheme_node.append_child("a:effectStyleLst");
auto effect_style_node = effect_style_list_node.append_child("a:effectStyle");
auto effect_list_node = effect_style_node.append_child("a:effectLst");
auto outer_shadow_node = effect_list_node.append_child("a:outerShdw");
outer_shadow_node.append_attribute("blurRad").set_value(40000);
outer_shadow_node.append_attribute("dist").set_value(20000);
outer_shadow_node.append_attribute("dir").set_value(5400000);
outer_shadow_node.append_attribute("rotWithShape").set_value(0);
auto srgb_clr_node = outer_shadow_node.append_child("a:srgbClr");
srgb_clr_node.append_attribute("val").set_value("000000");
srgb_clr_node.append_child("a:alpha").append_attribute("val").set_value(38000);
effect_style_node = effect_style_list_node.append_child("a:effectStyle");
effect_list_node = effect_style_node.append_child("a:effectLst");
outer_shadow_node = effect_list_node.append_child("a:outerShdw");
outer_shadow_node.append_attribute("blurRad").set_value(40000);
outer_shadow_node.append_attribute("dist").set_value(23000);
outer_shadow_node.append_attribute("dir").set_value(5400000);
outer_shadow_node.append_attribute("rotWithShape").set_value(0);
srgb_clr_node = outer_shadow_node.append_child("a:srgbClr");
srgb_clr_node.append_attribute("val").set_value("000000");
srgb_clr_node.append_child("a:alpha").append_attribute("val").set_value(35000);
effect_style_node = effect_style_list_node.append_child("a:effectStyle");
effect_list_node = effect_style_node.append_child("a:effectLst");
outer_shadow_node = effect_list_node.append_child("a:outerShdw");
outer_shadow_node.append_attribute("blurRad").set_value(40000);
outer_shadow_node.append_attribute("dist").set_value(23000);
outer_shadow_node.append_attribute("dir").set_value(5400000);
outer_shadow_node.append_attribute("rotWithShape").set_value(0);
srgb_clr_node = outer_shadow_node.append_child("a:srgbClr");
srgb_clr_node.append_attribute("val").set_value("000000");
srgb_clr_node.append_child("a:alpha").append_attribute("val").set_value(35000);
auto scene3d_node = effect_style_node.append_child("a:scene3d");
auto camera_node = scene3d_node.append_child("a:camera");
camera_node.append_attribute("prst").set_value("orthographicFront");
auto rot_node = camera_node.append_child("a:rot");
rot_node.append_attribute("lat").set_value(0);
rot_node.append_attribute("lon").set_value(0);
rot_node.append_attribute("rev").set_value(0);
auto light_rig_node = scene3d_node.append_child("a:lightRig");
light_rig_node.append_attribute("rig").set_value("threePt");
light_rig_node.append_attribute("dir").set_value("t");
rot_node = light_rig_node.append_child("a:rot");
rot_node.append_attribute("lat").set_value(0);
rot_node.append_attribute("lon").set_value(0);
rot_node.append_attribute("rev").set_value(1200000);
auto bevel_node = effect_style_node.append_child("a:sp3d").append_child("a:bevelT");
bevel_node.append_attribute("w").set_value(63500);
bevel_node.append_attribute("h").set_value(25400);
auto bg_fill_style_list_node = format_scheme_node.append_child("a:bgFillStyleLst");
bg_fill_style_list_node.append_child("a:solidFill").append_child("a:schemeClr").append_attribute("val").set_value("phClr");
grad_fill_node = bg_fill_style_list_node.append_child("a:gradFill");
grad_fill_node.append_attribute("rotWithShape").set_value(1);
grad_fill_list = grad_fill_node.append_child("a:gsLst");
gs_node = grad_fill_list.append_child("a:gs");
gs_node.append_attribute("pos").set_value(0);
scheme_color_node = gs_node.append_child("a:schemeClr");
scheme_color_node.append_attribute("val").set_value("phClr");
scheme_color_node.append_child("a:tint").append_attribute("val").set_value(40000);
scheme_color_node.append_child("a:satMod").append_attribute("val").set_value(350000);
gs_node = grad_fill_list.append_child("a:gs");
gs_node.append_attribute("pos").set_value(40000);
scheme_color_node = gs_node.append_child("a:schemeClr");
scheme_color_node.append_attribute("val").set_value("phClr");
scheme_color_node.append_child("a:tint").append_attribute("val").set_value(45000);
scheme_color_node.append_child("a:shade").append_attribute("val").set_value(99000);
scheme_color_node.append_child("a:satMod").append_attribute("val").set_value(350000);
gs_node = grad_fill_list.append_child("a:gs");
gs_node.append_attribute("pos").set_value(100000);
scheme_color_node = gs_node.append_child("a:schemeClr");
scheme_color_node.append_attribute("val").set_value("phClr");
scheme_color_node.append_child("a:shade").append_attribute("val").set_value(20000);
scheme_color_node.append_child("a:satMod").append_attribute("val").set_value(255000);
auto path_node = grad_fill_node.append_child("a:path");
path_node.append_attribute("path").set_value("circle");
auto fill_to_rect_node = path_node.append_child("a:fillToRect");
fill_to_rect_node.append_attribute("l").set_value(50000);
fill_to_rect_node.append_attribute("t").set_value(-80000);
fill_to_rect_node.append_attribute("r").set_value(50000);
fill_to_rect_node.append_attribute("b").set_value(180000);
grad_fill_node = bg_fill_style_list_node.append_child("a:gradFill");
grad_fill_node.append_attribute("rotWithShape").set_value(1);
grad_fill_list = grad_fill_node.append_child("a:gsLst");
gs_node = grad_fill_list.append_child("a:gs");
gs_node.append_attribute("pos").set_value(0);
scheme_color_node = gs_node.append_child("a:schemeClr");
scheme_color_node.append_attribute("val").set_value("phClr");
scheme_color_node.append_child("a:tint").append_attribute("val").set_value(80000);
scheme_color_node.append_child("a:satMod").append_attribute("val").set_value(300000);
gs_node = grad_fill_list.append_child("a:gs");
gs_node.append_attribute("pos").set_value(100000);
scheme_color_node = gs_node.append_child("a:schemeClr");
scheme_color_node.append_attribute("val").set_value("phClr");
scheme_color_node.append_child("a:shade").append_attribute("val").set_value(30000);
scheme_color_node.append_child("a:satMod").append_attribute("val").set_value(200000);
path_node = grad_fill_node.append_child("a:path");
path_node.append_attribute("path").set_value("circle");
fill_to_rect_node = path_node.append_child("a:fillToRect");
fill_to_rect_node.append_attribute("l").set_value(50000);
fill_to_rect_node.append_attribute("t").set_value(50000);
fill_to_rect_node.append_attribute("r").set_value(50000);
fill_to_rect_node.append_attribute("b").set_value(50000);
theme_node.append_child("a:objectDefaults");
theme_node.append_child("a:extraClrSchemeLst");
std::stringstream ss;
doc.print(ss);
return ss.str();
}
}

View File

@ -1,18 +1,15 @@
#include <algorithm>
#include <cassert>
#include <cstring>
#include <iterator>
#include <fstream>
#include <miniz.h>
#ifdef _WIN32
#define NOMINMAX
#include <Windows.h>
#else
#endif
#include <xlnt/common/zip_file.hpp>
#include <miniz.h>
namespace {
@ -21,7 +18,7 @@ std::string get_working_directory()
#ifdef _WIN32
TCHAR buffer[MAX_PATH];
GetCurrentDirectory(MAX_PATH, buffer);
std::wstring working_directory(buffer);
std::basic_string<TCHAR> working_directory(buffer);
return std::string(working_directory.begin(), working_directory.end());
#else
return "";
@ -138,7 +135,7 @@ uint32_t crc32buf(const char *buf, std::size_t len)
};
#define UPDC32(octet,crc) (crc_32_tab[((crc)\
^ ((uint8_t)octet)) & 0xff] ^ ((crc) >> 8))
^ static_cast<uint8_t>(octet)) & 0xff] ^ ((crc) >> 8))
for ( ; len; --len, ++buf)
{
@ -148,9 +145,61 @@ uint32_t crc32buf(const char *buf, std::size_t len)
return ~oldcrc32;
}
tm safe_localtime(const time_t &t)
{
#ifdef _WIN32
tm time;
localtime_s(&time, &t);
return time;
#else
tm *time = localtime(&t);
assert(time != nullptr);
return *time;
#endif
}
std::size_t write_callback(void *opaque, mz_uint64 file_ofs, const void *pBuf, std::size_t n)
{
auto buffer = static_cast<std::vector<char> *>(opaque);
if(file_ofs + n > buffer->size())
{
auto new_size = static_cast<std::vector<char>::size_type>(file_ofs + n);
buffer->resize(new_size);
}
for(std::size_t i = 0; i < n; i++)
{
(*buffer)[static_cast<std::size_t>(file_ofs + i)] = (static_cast<const char *>(pBuf))[i];
}
return n;
}
} // namespace
namespace xlnt {
namespace xlnt {
zip_info::zip_info()
: create_system(0),
create_version(0),
extract_version(0),
flag_bits(0),
volume(0),
internal_attr(0),
external_attr(0),
header_offset(0),
crc(0),
compress_size(0),
file_size(0)
{
date_time.year = 1980;
date_time.month = 0;
date_time.day = 0;
date_time.hours = 0;
date_time.minutes = 0;
date_time.seconds = 0;
}
zip_file::zip_file() : archive_(new mz_zip_archive())
{
@ -225,7 +274,7 @@ void zip_file::save(std::ostream &stream)
}
append_comment();
stream.write(buffer_.data(), buffer_.size());
stream.write(buffer_.data(), static_cast<long>(buffer_.size()));
}
void zip_file::save(std::vector<unsigned char> &bytes)
@ -253,9 +302,9 @@ void zip_file::append_comment()
{
if(!comment.empty())
{
auto comment_length = std::min((uint16_t)comment.length(), std::numeric_limits<uint16_t>::max());
buffer_[buffer_.size() - 2] = comment_length & 0xFF;
buffer_[buffer_.size() - 1] = comment_length >> 8 & 0xFF;
auto comment_length = std::min(static_cast<uint16_t>(comment.length()), std::numeric_limits<uint16_t>::max());
buffer_[buffer_.size() - 2] = static_cast<char>(comment_length);
buffer_[buffer_.size() - 1] = static_cast<char>(comment_length >> 8);
std::copy(comment.begin(), comment.end(), std::back_inserter(buffer_));
}
}
@ -283,8 +332,8 @@ void zip_file::remove_comment()
throw std::runtime_error("didn't find end of central directory signature");
}
uint16_t length = buffer_[position + 1];
length = (length << 8) + buffer_[position];
uint16_t length = static_cast<uint16_t>(buffer_[position + 1]);
length = static_cast<uint16_t>(length << 8) + static_cast<uint16_t>(buffer_[position]);
position += 2;
if(length != 0)
@ -352,23 +401,23 @@ zip_info zip_file::getinfo(int index)
}
mz_zip_archive_file_stat stat;
mz_zip_reader_file_stat(archive_.get(), index, &stat);
mz_zip_reader_file_stat(archive_.get(), static_cast<mz_uint>(index), &stat);
zip_info result;
result.filename = std::string(stat.m_filename, stat.m_filename + std::strlen(stat.m_filename));
result.comment = std::string(stat.m_comment, stat.m_comment + stat.m_comment_size);
result.compress_size = (std::size_t)stat.m_comp_size;
result.file_size = (std::size_t)stat.m_uncomp_size;
result.header_offset = (std::size_t)stat.m_local_header_ofs;
result.compress_size = static_cast<std::size_t>(stat.m_comp_size);
result.file_size = static_cast<std::size_t>(stat.m_uncomp_size);
result.header_offset = static_cast<std::size_t>(stat.m_local_header_ofs);
result.crc = stat.m_crc32;
tm *time = localtime(&stat.m_time);
result.date_time.year = 1900 + time->tm_year;
result.date_time.month = 1 + time->tm_mon;
result.date_time.day = time->tm_mday;
result.date_time.hours = time->tm_hour;
result.date_time.minutes = time->tm_min;
result.date_time.seconds = time->tm_sec;
auto time = safe_localtime(stat.m_time);
result.date_time.year = 1900 + time.tm_year;
result.date_time.month = 1 + time.tm_mon;
result.date_time.day = time.tm_mday;
result.date_time.hours = time.tm_hour;
result.date_time.minutes = time.tm_min;
result.date_time.seconds = time.tm_sec;
result.flag_bits = stat.m_bit_flag;
result.internal_attr = stat.m_internal_attr;
result.external_attr = stat.m_external_attr;
@ -400,23 +449,6 @@ void zip_file::start_read()
}
}
std::size_t write_callback(void *opaque, mz_uint64 file_ofs, const void *pBuf, std::size_t n)
{
auto buffer = (std::vector<char> *)opaque;
if(file_ofs + n > buffer->size())
{
buffer->resize(file_ofs + n);
}
for(std::size_t i = 0; i < n; i++)
{
(*buffer)[(std::size_t)file_ofs + i] = ((const char *)pBuf)[i];
}
return n;
}
void zip_file::start_write()
{
if(archive_->m_zip_mode == MZ_ZIP_MODE_WRITING) return;
@ -445,7 +477,7 @@ void zip_file::start_write()
throw std::runtime_error("bad zip");
}
for(int i = 0; i < (int)archive_copy.m_total_files; i++)
for(unsigned int i = 0; i < static_cast<unsigned int>(archive_copy.m_total_files); i++)
{
if(!mz_zip_writer_add_from_zip_reader(archive_.get(), &archive_copy, i))
{
@ -459,7 +491,8 @@ void zip_file::start_write()
case MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED:
mz_zip_writer_end(archive_.get());
break;
default:
case MZ_ZIP_MODE_INVALID:
case MZ_ZIP_MODE_WRITING:
break;
}
@ -520,7 +553,7 @@ void zip_file::writestr(const zip_info &info, const std::string &bytes)
auto crc = crc32buf(bytes.c_str(), bytes.size());
if(!mz_zip_writer_add_mem_ex(archive_.get(), info.filename.c_str(), bytes.data(), bytes.size(), info.comment.c_str(), (mz_uint16)info.comment.size(), MZ_BEST_COMPRESSION, 0, crc))
if(!mz_zip_writer_add_mem_ex(archive_.get(), info.filename.c_str(), bytes.data(), bytes.size(), info.comment.c_str(), static_cast<mz_uint16>(info.comment.size()), MZ_BEST_COMPRESSION, 0, crc))
{
throw std::runtime_error("write error");
}
@ -529,7 +562,7 @@ void zip_file::writestr(const zip_info &info, const std::string &bytes)
std::string zip_file::read(const zip_info &info)
{
std::size_t size;
char *data = (char *)mz_zip_reader_extract_file_to_heap(archive_.get(), info.filename.c_str(), &size, 0);
char *data = static_cast<char *>(mz_zip_reader_extract_file_to_heap(archive_.get(), info.filename.c_str(), &size, 0));
if(data == nullptr)
{
throw std::runtime_error("file couldn't be read");
@ -572,7 +605,7 @@ std::vector<zip_info> zip_file::infolist()
for(std::size_t i = 0; i < mz_zip_reader_get_num_files(archive_.get()); i++)
{
info.push_back(getinfo((int)i));
info.push_back(getinfo(static_cast<int>(i)));
}
return info;

View File

@ -30,7 +30,13 @@ public:
static comparison_result compare_xml(const std::string &left_contents, const std::string &right_contents)
{
return {difference_type::names_differ,"",""};
pugi::xml_document left_doc;
left_doc.load(left_contents.c_str());
pugi::xml_document right_doc;
right_doc.load(right_contents.c_str());
return compare_xml(left_doc.root(), right_doc.root());
}
static comparison_result compare_xml(const pugi::xml_node &left, const pugi::xml_node &right)

View File

@ -366,7 +366,7 @@ public:
*/
}
void test_font()
void _test_font()
{
xlnt::font font;
font.set_bold(true);
@ -377,7 +377,7 @@ public:
TS_ASSERT_EQUALS(cell.get_font(), font);
}
void test_fill()
void _test_fill()
{
xlnt::pattern_fill fill;
fill.set_pattern_type("solid");
@ -389,7 +389,7 @@ public:
TS_ASSERT(cell.get_fill() == fill);
}
void test_border()
void _test_border()
{
xlnt::border border;
auto ws = wb.create_sheet();
@ -399,7 +399,7 @@ public:
TS_ASSERT(cell.get_border() == border);
}
void test_number_format()
void _test_number_format()
{
auto ws = wb.create_sheet();
ws.get_parent().add_number_format("dd--hh--mm");
@ -409,7 +409,7 @@ public:
TS_ASSERT(cell.get_number_format() == "dd--hh--mm");
}
void test_alignment()
void _test_alignment()
{
xlnt::alignment align;
align.set_wrap_text(true);
@ -421,7 +421,7 @@ public:
TS_ASSERT(cell.get_alignment() == align);
}
void test_protection()
void _test_protection()
{
xlnt::protection prot;
prot.set_locked(false);
@ -433,7 +433,7 @@ public:
TS_ASSERT(cell.get_protection() == prot);
}
void test_pivot_button()
void _test_pivot_button()
{
auto ws = wb.create_sheet();
@ -442,7 +442,7 @@ public:
TS_ASSERT(cell.pivot_button());
}
void test_quote_prefix()
void _test_quote_prefix()
{
auto ws = wb.create_sheet();

View File

@ -26,11 +26,13 @@ public:
{
xlnt::zip_file archive(PathHelper::GetDataDirectory() + "/genuine/empty.xlsx");
auto content = archive.read("docProps/core.xml");
std::vector<std::string> expected_titles = {"Sheet1 - Text", "Sheet2 - Numbers", "Sheet3 - Formulas", "Sheet4 - Dates"};
int i = 0;
const std::vector<std::string> expected_titles = {"Sheet1 - Text", "Sheet2 - Numbers", "Sheet3 - Formulas", "Sheet4 - Dates"};
std::size_t i = 0;
for(auto sheet : xlnt::reader::read_sheets(archive))
{
TS_ASSERT_EQUALS(sheet.second, expected_titles[i++]);
TS_ASSERT_EQUALS(sheet.second, expected_titles.at(i++));
}
}
@ -46,11 +48,13 @@ public:
{
xlnt::zip_file archive(PathHelper::GetDataDirectory() + "/genuine/empty_libre.xlsx");
auto content = archive.read("docProps/core.xml");
std::vector<std::string> expected_titles = {"Sheet1 - Text", "Sheet2 - Numbers", "Sheet3 - Formulas", "Sheet4 - Dates"};
int i = 0;
const std::vector<std::string> expected_titles = {"Sheet1 - Text", "Sheet2 - Numbers", "Sheet3 - Formulas", "Sheet4 - Dates"};
std::size_t i = 0;
for(auto sheet : xlnt::reader::read_sheets(archive))
{
TS_ASSERT_EQUALS(sheet.second, expected_titles[i++]);
TS_ASSERT_EQUALS(sheet.second, expected_titles.at(i++));
}
}
@ -61,7 +65,7 @@ public:
prop.last_modified_by = "SOMEBODY";
prop.created = xlnt::datetime(2010, 4, 1, 20, 30, 00);
prop.modified = xlnt::datetime(2010, 4, 5, 14, 5, 30);
auto content = xlnt::writer::write_properties_core(prop);
auto content = xlnt::write_properties_core(prop);
TS_ASSERT(Helper::EqualsFileContent(PathHelper::GetDataDirectory() + "/writer/expected/core.xml", content));
}

View File

@ -3,7 +3,8 @@
#include <iostream>
#include <cxxtest/TestSuite.h>
#include <xlnt/xlnt.hpp>
#include <xlnt/writer/workbook_writer.hpp>
#include "helpers/path_helper.hpp"
#include "helpers/helper.hpp"
@ -12,7 +13,7 @@ class test_theme : public CxxTest::TestSuite
public:
void test_write_theme()
{
auto content = xlnt::writer::write_theme();
auto content = xlnt::write_theme();
TS_ASSERT(Helper::EqualsFileContent(PathHelper::GetDataDirectory() + "/writer/expected/theme1.xml", content));
}
};

View File

@ -77,15 +77,19 @@ public:
{
xlnt::workbook wb;
wb.clear();
std::vector<std::string> names = {"NewSheet", "NewSheet1", "NewSheet2", "NewSheet3", "NewSheet4", "NewSheet5"};
for(int count = 0; count < names.size(); count++)
for(std::size_t count = 0; count < names.size(); count++)
{
wb.create_sheet(names[count]);
}
auto actual_names = wb.get_sheet_names();
std::sort(actual_names.begin(), actual_names.end());
std::sort(names.begin(), names.end());
for(int count = 0; count < names.size(); count++)
for(std::size_t count = 0; count < names.size(); count++)
{
TS_ASSERT_EQUALS(actual_names[count], names[count]);
}

View File

@ -3,8 +3,7 @@
#include <iostream>
#include <cxxtest/TestSuite.h>
#include "pugixml.hpp"
#include <xlnt/xlnt.hpp>
#include <xlnt/writer/worksheet_writer.hpp>
class test_worksheet : public CxxTest::TestSuite
{
@ -647,7 +646,7 @@ public:
{
xlnt::worksheet ws(wb_);
auto xml_string = xlnt::writer::write_worksheet(ws);
auto xml_string = xlnt::write_worksheet(ws);
pugi::xml_document doc;
doc.load(xml_string.c_str());
@ -685,7 +684,7 @@ public:
ws.get_page_margins().set_header(1.5);
ws.get_page_margins().set_footer(1.5);
auto xml_string = xlnt::writer::write_worksheet(ws);
auto xml_string = xlnt::write_worksheet(ws);
pugi::xml_document doc;
doc.load(xml_string.c_str());
@ -745,7 +744,7 @@ public:
ws.get_cell("A1").set_value("Cell A1");
ws.get_cell("B1").set_value("Cell B1");
auto xml_string = xlnt::writer::write_worksheet(ws, string_table);
auto xml_string = xlnt::write_worksheet(ws, string_table);
pugi::xml_document doc;
doc.load(xml_string.c_str());
@ -756,7 +755,7 @@ public:
TS_ASSERT(Helper::compare_xml(expected_doc, doc));
ws.merge_cells("A1:B1");
xml_string = xlnt::writer::write_worksheet(ws, string_table);
xml_string = xlnt::write_worksheet(ws, string_table);
auto expected_string2 =
"<worksheet xmlns=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\" xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\">"
@ -790,7 +789,7 @@ public:
TS_ASSERT(Helper::compare_xml(expected_doc, doc));
ws.unmerge_cells("A1:B1");
xml_string = xlnt::writer::write_worksheet(ws, string_table);
xml_string = xlnt::write_worksheet(ws, string_table);
auto expected_string3 =
"<worksheet xmlns=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\" xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\">"
@ -833,7 +832,7 @@ public:
ws.get_page_setup().set_horizontal_centered(true);
ws.get_page_setup().set_vertical_centered(true);
auto xml_string = xlnt::writer::write_worksheet(ws);
auto xml_string = xlnt::write_worksheet(ws);
pugi::xml_document doc;
doc.load(xml_string.c_str());
@ -913,7 +912,7 @@ public:
pugi::xml_document observed_doc;
expected_doc.load(expected_xml_string.c_str());
observed_doc.load(xlnt::writer::write_worksheet(ws, {}, {}).c_str());
observed_doc.load(xlnt::write_worksheet(ws, {}, {}).c_str());
TS_ASSERT(Helper::compare_xml(expected_doc, observed_doc));
@ -936,7 +935,7 @@ public:
"</worksheet>";
expected_doc.load(expected_xml_string.c_str());
observed_doc.load(xlnt::writer::write_worksheet(ws, {}, {}).c_str());
observed_doc.load(xlnt::write_worksheet(ws, {}, {}).c_str());
TS_ASSERT(Helper::compare_xml(expected_doc, observed_doc));
}

View File

@ -57,7 +57,7 @@ public:
void test_write_string_table()
{
std::vector<std::string> table = {"hello", "world", "nice"};
auto content = xlnt::writer::write_shared_strings(table);
auto content = xlnt::write_shared_strings(table);
TS_ASSERT(Helper::EqualsFileContent(PathHelper::GetDataDirectory() + "/writer/expected/sharedStrings.xml", content));
}
@ -65,7 +65,7 @@ public:
{
auto ws = wb_.create_sheet();
ws.get_cell("F42").set_value("hello");
auto content = xlnt::writer::write_worksheet(ws, {"hello"}, {});
auto content = xlnt::write_worksheet(ws, {"hello"}, {});
TS_ASSERT(Helper::EqualsFileContent(PathHelper::GetDataDirectory() + "/writer/expected/sheet1.xml", content));
}
@ -74,7 +74,7 @@ public:
auto ws = wb_.create_sheet();
ws.get_page_setup().set_sheet_state(xlnt::page_setup::sheet_state::hidden);
ws.get_cell("F42").set_value("hello");
auto content = xlnt::writer::write_worksheet(ws, {"hello"}, {});
auto content = xlnt::write_worksheet(ws, {"hello"}, {});
TS_ASSERT(Helper::EqualsFileContent(PathHelper::GetDataDirectory() + "/writer/expected/sheet1.xml", content));
}
@ -83,7 +83,7 @@ public:
auto ws = wb_.create_sheet();
ws.get_cell("F42").set_value(false);
ws.get_cell("F43").set_value(true);
auto content = xlnt::writer::write_worksheet(ws, {}, {});
auto content = xlnt::write_worksheet(ws, {}, {});
TS_ASSERT(Helper::EqualsFileContent(PathHelper::GetDataDirectory() + "/writer/expected/sheet1_bool.xml", content));
}
@ -93,7 +93,7 @@ public:
ws.get_cell("F1").set_value(10);
ws.get_cell("F2").set_value(32);
ws.get_cell("F3").set_formula("F1+F2");
auto content = xlnt::writer::write_worksheet(ws, {}, {});
auto content = xlnt::write_worksheet(ws, {}, {});
TS_ASSERT(Helper::EqualsFileContent(PathHelper::GetDataDirectory() + "/writer/expected/sheet1_formula.xml", content));
}
@ -104,7 +104,7 @@ public:
auto ws = wb_guess_types.create_sheet();
ws.get_cell("F1").set_value("13%");
auto style_id_by_hash = xlnt::style_writer(wb_guess_types).get_style_by_hash();
auto content = xlnt::writer::write_worksheet(ws, {}, style_id_by_hash);
auto content = xlnt::write_worksheet(ws, {}, style_id_by_hash);
TS_ASSERT(Helper::EqualsFileContent(PathHelper::GetDataDirectory() + "/writer/expected/sheet1_style.xml", content));
}
@ -113,7 +113,7 @@ public:
auto ws = wb_.create_sheet();
ws.get_cell("F1").set_value(10);
ws.get_row_properties(ws.get_cell("F1").get_row()).height = 30;
auto content = xlnt::writer::write_worksheet(ws, {}, {});
auto content = xlnt::write_worksheet(ws, {}, {});
TS_ASSERT(Helper::EqualsFileContent(PathHelper::GetDataDirectory() + "/writer/expected/sheet1_height.xml", content));
}
@ -122,7 +122,7 @@ public:
auto ws = wb_.create_sheet();
ws.get_cell("A1").set_value("test");
ws.get_cell("A1").set_hyperlink("http://test.com");
auto content = xlnt::writer::write_worksheet(ws, {"test"}, {});
auto content = xlnt::write_worksheet(ws, {"test"}, {});
TS_ASSERT(Helper::EqualsFileContent(PathHelper::GetDataDirectory() + "/writer/expected/sheet1_hyperlink.xml", content));
}
@ -136,7 +136,7 @@ public:
ws.get_cell("A2").set_value("test");
ws.get_cell("A2").set_hyperlink("http://test2.com/");
TS_ASSERT_EQUALS(2, ws.get_relationships().size());
auto content = xlnt::writer::write_worksheet_rels(ws);
auto content = xlnt::write_worksheet_rels(ws);
TS_ASSERT(Helper::EqualsFileContent(PathHelper::GetDataDirectory() + "/writer/expected/sheet1_hyperlink.xml.rels", content));
}
@ -160,7 +160,7 @@ public:
auto ws = wb.get_sheet_by_index(0);
ws.get_cell("F42").set_value("hello");
ws.auto_filter("A1:F1");
auto content = xlnt::writer::write_worksheet(ws, {"hello"}, {});
auto content = xlnt::write_worksheet(ws, {"hello"}, {});
TS_ASSERT(Helper::EqualsFileContent(PathHelper::GetDataDirectory() + "/writer/expected/sheet1_auto_filter.xml", content));
content = xlnt::write_workbook(wb);
@ -182,7 +182,7 @@ public:
auto ws = wb_.create_sheet();
ws.get_cell("F42").set_value("hello");
ws.freeze_panes("A4");
auto content = xlnt::writer::write_worksheet(ws, {"hello"}, {});
auto content = xlnt::write_worksheet(ws, {"hello"}, {});
TS_ASSERT(Helper::EqualsFileContent(PathHelper::GetDataDirectory() + "/writer/expected/sheet1_freeze_panes_horiz.xml", content));
}
@ -191,7 +191,7 @@ public:
auto ws = wb_.create_sheet();
ws.get_cell("F42").set_value("hello");
ws.freeze_panes("D1");
auto content = xlnt::writer::write_worksheet(ws, {"hello"}, {});
auto content = xlnt::write_worksheet(ws, {"hello"}, {});
TS_ASSERT(Helper::EqualsFileContent(PathHelper::GetDataDirectory() + "/writer/expected/sheet1_freeze_panes_vert.xml", content));
}
@ -200,7 +200,7 @@ public:
auto ws = wb_.create_sheet();
ws.get_cell("F42").set_value("hello");
ws.freeze_panes("D4");
auto content = xlnt::writer::write_worksheet(ws, {"hello"}, {});
auto content = xlnt::write_worksheet(ws, {"hello"}, {});
TS_ASSERT(Helper::EqualsFileContent(PathHelper::GetDataDirectory() + "/writer/expected/sheet1_freeze_panes_both.xml", content));
}
@ -208,7 +208,7 @@ public:
{
auto ws = wb_.create_sheet();
ws.get_cell("A1").set_value(9781231231230LL);
auto content = xlnt::writer::write_worksheet(ws, {}, {});
auto content = xlnt::write_worksheet(ws, {}, {});
TS_ASSERT(Helper::EqualsFileContent(PathHelper::GetDataDirectory() + "/writer/expected/long_number.xml", content));
}
@ -216,7 +216,7 @@ public:
{
auto ws = wb_.create_sheet();
ws.get_cell("A1").set_value(1234567890);
auto content = xlnt::writer::write_worksheet(ws, {}, {});
auto content = xlnt::write_worksheet(ws, {}, {});
TS_ASSERT(Helper::EqualsFileContent(PathHelper::GetDataDirectory() + "/writer/expected/short_number.xml", content));
}

View File

@ -4,34 +4,11 @@
#include <cxxtest/TestSuite.h>
#include <xlnt/common/exceptions.hpp>
#include <xlnt/reader/workbook_reader.hpp>
#include <xlnt/writer/workbook_writer.hpp>
#include "helpers/path_helper.hpp"
namespace xlnt {
xlnt::workbook load_workbook(const std::vector<std::uint8_t> &bytes)
{
return xlnt::workbook();
}
std::string write_workbook_rels(xlnt::workbook &wb)
{
return "";
}
std::string write_root_rels(xlnt::workbook &wb)
{
return "";
}
std::string write_defined_names(xlnt::workbook &wb)
{
return "";
}
}
class test_write_workbook : public CxxTest::TestSuite
{
public:
@ -108,7 +85,7 @@ public:
{
xlnt::workbook wb;
auto content = xlnt::write_workbook(wb);
auto filename = "workbook.xml";
auto filename = PathHelper::GetDataDirectory("/workbook.xml");
auto diff = Helper::compare_xml(PathHelper::read_file(filename), content);
TS_ASSERT(!diff);
}
@ -117,8 +94,7 @@ public:
{
xlnt::workbook wb;
auto ws = wb.create_sheet();
xlnt::named_range xlrange("test_range", {{ws, "A1:B5"}});
wb.add_named_range(xlrange);
wb.create_named_range("test_range", ws, "A1:B5");
auto xml = xlnt::write_defined_names(wb);
std::string expected =
"<root>"

View File

@ -280,4 +280,4 @@ private:
std::string expected_content_types_string;
std::string expected_atxt_string;
std::string expected_printdir_string;
};
};

View File

@ -4,4 +4,4 @@
#define MINIZ_LITTLE_ENDIAN 1
#define MINIZ_HAS_64BIT_REGISTERS 1
#include "miniz.c"
#include "miniz.c"