implement garbage collection to remove unreferenced formats and constituent parts

This commit is contained in:
Thomas Fussell 2016-11-07 21:11:30 -05:00
parent 1474c8ab82
commit ca692790fa
28 changed files with 1422 additions and 1073 deletions

View File

@ -174,46 +174,37 @@ public:
/// </summary>
bool has_hyperlink() const;
// computed format
/// <summary>
/// For each of alignment, border, fill, font, number format, and protection,
/// returns a format using the value from the cell format if that value is
/// applied, or else the value from the named style if that value is applied,
/// or else the default value. This is used to retreive the formatting of the cell
/// as it will be displayed in an editing application.
/// </summary>
base_format get_computed_format() const;
// computed formatting
/// <summary>
/// Returns the result of get_computed_format().get_alignment().
/// </summary>
alignment get_computed_alignment() const;
alignment computed_alignment() const;
/// <summary>
/// Returns the result of get_computed_format().get_border().
/// </summary>
border get_computed_border() const;
border computed_border() const;
/// <summary>
/// Returns the result of get_computed_format().get_fill().
/// </summary>
fill get_computed_fill() const;
fill computed_fill() const;
/// <summary>
/// Returns the result of get_computed_format().get_font().
/// </summary>
font get_computed_font() const;
font computed_font() const;
/// <summary>
/// Returns the result of get_computed_format().get_number_format().
/// </summary>
number_format get_computed_number_format() const;
number_format computed_number_format() const;
/// <summary>
/// Returns the result of get_computed_format().get_protection().
/// </summary>
protection get_computed_protection() const;
protection computed_protection() const;
// format
@ -226,12 +217,12 @@ public:
/// Return a reference to the format applied to this cell.
/// If this cell has no format, an invalid_attribute exception will be thrown.
/// </summary>
format get_format() const;
const format format() const;
/// <summary>
/// Applies the cell-level formatting of new_format to this cell.
/// </summary>
void set_format(const format &new_format);
void format(const class format new_format);
/// <summary>
/// Remove the cell-level formatting from this cell.
@ -314,21 +305,21 @@ public:
bool has_style() const;
/// <summary>
/// Returns a reference to the named style applied to this cell.
/// Returns a wrapper pointing to the named style applied to this cell.
/// </summary>
style get_style() const;
const style style() const;
/// <summary>
/// Equivalent to set_style(new_style.name())
/// Equivalent to style(new_style.name())
/// </summary>
void set_style(const style &new_style);
void style(const class style &new_style);
/// <summary>
/// Sets the named style applied to this cell to a style named style_name.
/// If this style has not been previously created in the workbook, a
/// key_not_found exception will be thrown.
/// </summary>
void set_style(const std::string &style_name);
void style(const std::string &style_name);
/// <summary>
/// Removes the named style from this cell.
@ -506,13 +497,7 @@ private:
/// Returns a non-const reference to the format of this cell.
/// This is for internal use only.
/// </summary>
format &get_format_internal();
/// <summary>
/// Use workbook::create_format() to create a new format then copy
/// this cell's formatting to that new format and return it.
/// </summary>
format &duplicate_format();
class format modifiable_format();
/// <summary>
/// Private constructor to create a cell from its implementation.

View File

@ -1,94 +0,0 @@
// Copyright (c) 2014-2016 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 <xlnt/xlnt_config.hpp>
#include <xlnt/styles/alignment.hpp>
#include <xlnt/styles/border.hpp>
#include <xlnt/styles/fill.hpp>
#include <xlnt/styles/font.hpp>
#include <xlnt/styles/number_format.hpp>
#include <xlnt/styles/protection.hpp>
namespace xlnt {
/// <summary>
/// Describes the formatting of a particular cell.
/// </summary>
class XLNT_API base_format
{
public:
// Alignment
class alignment &alignment();
const class alignment &alignment() const;
void alignment(const xlnt::alignment &new_alignment, bool applied);
bool alignment_applied() const;
// Border
virtual class border &border();
virtual const class border &border() const;
virtual void border(const xlnt::border &new_border, bool applied);
bool border_applied() const;
// Fill
virtual class fill &fill();
virtual const class fill &fill() const;
virtual void fill(const xlnt::fill &new_fill, bool applied);
bool fill_applied() const;
// Font
virtual class font &font();
virtual const class font &font() const;
virtual void font(const xlnt::font &new_font, bool applied);
bool font_applied() const;
// Number Format
virtual class number_format &number_format();
virtual const class number_format &number_format() const;
virtual void number_format(const xlnt::number_format &new_number_format, bool applied);
bool number_format_applied() const;
// Protection
class protection &protection();
const class protection &protection() const;
void protection(const xlnt::protection &new_protection, bool applied);
bool protection_applied() const;
protected:
class alignment alignment_;
class border border_;
class fill fill_;
class font font_;
class number_format number_format_;
class protection protection_;
bool apply_alignment_ = false;
bool apply_border_ = false;
bool apply_fill_ = false;
bool apply_font_ = false;
bool apply_number_format_ = false;
bool apply_protection_ = false;
};
} // namespace xlnt

View File

@ -26,7 +26,6 @@
#include <string>
#include <xlnt/xlnt_config.hpp>
#include <xlnt/styles/base_format.hpp>
namespace xlnt {
@ -46,42 +45,50 @@ struct stylesheet;
/// <summary>
/// Describes the formatting of a particular cell.
/// </summary>
class XLNT_API format : public base_format
class XLNT_API format
{
public:
std::size_t id() const;
class alignment &alignment();
const class alignment &alignment() const;
format alignment(const xlnt::alignment &new_alignment, bool applied);
bool alignment_applied() const;
class border &border();
const class border &border() const;
format border(const xlnt::border &new_border, bool applied);
bool border_applied() const;
class fill &fill();
const class fill &fill() const;
format fill(const xlnt::fill &new_fill, bool applied);
bool fill_applied() const;
class font &font();
const class font &font() const;
format font(const xlnt::font &new_font, bool applied);
bool font_applied() const;
class number_format &number_format();
const class number_format &number_format() const;
format number_format(const xlnt::number_format &new_number_format, bool applied);
bool number_format_applied() const;
class protection &protection();
const class protection &protection() const;
format protection(const xlnt::protection &new_protection, bool applied);
bool protection_applied() const;
bool has_style() const;
void clear_style();
void style(const std::string &name);
void style(const xlnt::style &new_style);
const class style &style() const;
class border &border() override;
const class border &border() const override;
void border(const xlnt::border &new_border, bool applied) override;
class fill &fill() override;
const class fill &fill() const override;
void fill(const xlnt::fill &new_fill, bool applied) override;
class font &font() override;
const class font &font() const override;
void font(const xlnt::font &new_font, bool applied) override;
class number_format &number_format() override;
const class number_format &number_format() const override;
void number_format(const xlnt::number_format &new_number_format, bool applied) override;
format &alignment_id(std::size_t id);
format &border_id(std::size_t id);
format &fill_id(std::size_t id);
format &font_id(std::size_t id);
format &number_format_id(std::size_t id);
format &protection_id(std::size_t id);
format style(const std::string &name);
format style(const xlnt::style &new_style);
const class style style() const;
private:
friend struct detail::stylesheet;
friend class cell;
format(detail::format_impl *d);
detail::format_impl *d_;
};

View File

@ -27,42 +27,75 @@
#include <string>
#include <xlnt/xlnt_config.hpp>
#include <xlnt/styles/base_format.hpp>
namespace xlnt {
class alignment;
class border;
class cell;
class fill;
class font;
class number_format;
class protection;
namespace detail {
struct style_impl;
struct stylesheet;
}
} // namespace detail
/// <summary>
/// Describes a style which has a name and can be applied to multiple individual
/// formats. In Excel this is a "Cell Style".
/// </summary>
class XLNT_API style : public base_format
class XLNT_API style
{
public:
style() = delete;
style(const style &other) = default;
std::string name() const;
style &name(const std::string &name);
style name(const std::string &name);
class alignment &alignment();
const class alignment &alignment() const;
style alignment(const xlnt::alignment &new_alignment, bool applied);
bool alignment_applied() const;
class border &border();
const class border &border() const;
style border(const xlnt::border &new_border, bool applied);
bool border_applied() const;
class fill &fill();
const class fill &fill() const;
style fill(const xlnt::fill &new_fill, bool applied);
bool fill_applied() const;
class font &font();
const class font &font() const;
style font(const xlnt::font &new_font, bool applied);
bool font_applied() const;
class number_format &number_format();
const class number_format &number_format() const;
style number_format(const xlnt::number_format &new_number_format, bool applied);
bool number_format_applied() const;
class protection &protection();
const class protection &protection() const;
style protection(const xlnt::protection &new_protection, bool applied);
bool protection_applied() const;
bool hidden() const;
style &hidden(bool value);
style hidden(bool value);
optional<bool> custom() const;
style &custom(bool value);
style custom(bool value);
optional<std::size_t> builtin_id() const;
style &builtin_id(std::size_t builtin_id);
style builtin_id(std::size_t builtin_id);
style &alignment_id(std::size_t id);
style &border_id(std::size_t id);
style &fill_id(std::size_t id);
style &font_id(std::size_t id);
style &number_format_id(std::size_t id);
style &protection_id(std::size_t id);
bool operator==(const style &other);
bool operator==(const style &other) const;
private:
friend struct detail::stylesheet;

View File

@ -78,6 +78,13 @@ public:
has_value_ = false;
value_ = T();
}
bool operator==(const optional<T> &other) const
{
return has_value_ == other.has_value_
&& (!has_value_
|| (has_value_ && value_ == other.value_));
}
private:
bool has_value_;

View File

@ -278,6 +278,11 @@ public:
/// exception to be thrown.
/// </summary>
const_iterator cend() const;
/// <summary>
/// Apply the function "f" to every non-empty cell in every worksheet in this workbook.
/// </summary>
void apply_to_cells(std::function<void(cell)> f);
/// <summary>
/// Returns a temporary vector containing the titles of each sheet in the order
@ -417,17 +422,17 @@ public:
// formats
format &get_format(std::size_t format_index);
const format &get_format(std::size_t format_index) const;
format &create_format();
format get_format(std::size_t format_index);
const format get_format(std::size_t format_index) const;
format create_format();
void clear_formats();
// styles
bool has_style(const std::string &name) const;
style &get_style(const std::string &name);
const style &get_style(const std::string &name) const;
style &create_style(const std::string &name);
class style style(const std::string &name);
const class style style(const std::string &name) const;
class style create_style(const std::string &name);
void clear_styles();
// manifest
@ -488,11 +493,6 @@ private:
const detail::workbook_impl &impl() const;
/// <summary>
/// Apply the function "f" to every cell in every worksheet in this workbook.
/// </summary>
void apply_to_cells(std::function<void(cell)> f);
void register_app_properties_in_manifest();
void register_core_properties_in_manifest();

View File

@ -56,7 +56,7 @@ if(MSVC)
elseif(CMAKE_CXX_COMPILER_ID MATCHES "GNU")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wno-unknown-pragmas")
elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Weverything -Wno-c++98-compat -Wno-padded")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Weverything -Wno-c++98-compat -Wno-c++98-compat-pedantic -Wno-padded")
endif()
if(APPLE)

View File

@ -30,8 +30,14 @@
#include <xlnt/cell/comment.hpp>
#include <xlnt/cell/formatted_text.hpp>
#include <xlnt/packaging/relationship.hpp>
#include <xlnt/styles/alignment.hpp>
#include <xlnt/styles/border.hpp>
#include <xlnt/styles/color.hpp>
#include <xlnt/styles/fill.hpp>
#include <xlnt/styles/font.hpp>
#include <xlnt/styles/format.hpp>
#include <xlnt/styles/number_format.hpp>
#include <xlnt/styles/protection.hpp>
#include <xlnt/styles/style.hpp>
#include <xlnt/utils/date.hpp>
#include <xlnt/utils/datetime.hpp>
@ -119,7 +125,7 @@ std::pair<bool, xlnt::time> cast_time(const std::string &s)
result.hour = static_cast<int>(numeric_components[0]);
result.minute = static_cast<int>(numeric_components[1]);
if (result.minute != numeric_components[1])
if (std::fabs(static_cast<double>(result.minute) - numeric_components[1]) > std::numeric_limits<double>::epsilon())
{
result.minute = result.hour;
result.hour = 0;
@ -142,12 +148,18 @@ namespace xlnt {
const std::unordered_map<std::string, int> &cell::error_codes()
{
static const std::unordered_map<std::string, int> *codes =
new std::unordered_map<std::string, int>({ { "#NULL!", 0 }, { "#DIV/0!", 1 }, { "#VALUE!", 2 },
{ "#REF!", 3 }, { "#NAME?", 4 }, { "#NUM!", 5 },
{ "#N/A!", 6 } });
new std::unordered_map<std::string, int>({
{ "#NULL!", 0 },
{ "#DIV/0!", 1 },
{ "#VALUE!", 2 },
{ "#REF!", 3 },
{ "#NAME?", 4 },
{ "#NUM!", 5 },
{ "#N/A!", 6 }
});
return *codes;
};
}
std::string cell::check_string(const std::string &to_check)
{
@ -358,7 +370,7 @@ XLNT_API void cell::set_value(cell c)
d_->value_text_ = c.d_->value_text_;
d_->hyperlink_ = c.d_->hyperlink_;
d_->formula_ = c.d_->formula_;
d_->format_id_ = c.d_->format_id_;
d_->format_ = c.d_->format_;
}
template <>
@ -438,7 +450,7 @@ bool cell::operator==(const cell &comparand) const
cell &cell::operator=(const cell &rhs)
{
d_->column_ = rhs.d_->column_;
d_->format_id_ = rhs.d_->format_id_;
d_->format_ = rhs.d_->format_;
d_->formula_ = rhs.d_->formula_;
d_->hyperlink_ = rhs.d_->hyperlink_;
d_->is_merged_ = rhs.d_->is_merged_;
@ -608,34 +620,34 @@ void cell::set_data_type(type t)
d_->type_ = t;
}
number_format cell::get_computed_number_format() const
number_format cell::computed_number_format() const
{
return get_computed_format().number_format();
return xlnt::number_format();
}
font cell::get_computed_font() const
font cell::computed_font() const
{
return get_computed_format().font();
return xlnt::font();
}
fill cell::get_computed_fill() const
fill cell::computed_fill() const
{
return get_computed_format().fill();
return xlnt::fill();
}
border cell::get_computed_border() const
border cell::computed_border() const
{
return get_computed_format().border();
return xlnt::border();
}
alignment cell::get_computed_alignment() const
alignment cell::computed_alignment() const
{
return get_computed_format().alignment();
return xlnt::alignment();
}
protection cell::get_computed_protection() const
protection cell::computed_protection() const
{
return get_computed_format().protection();
return xlnt::protection();
}
void cell::clear_value()
@ -649,7 +661,7 @@ void cell::clear_value()
template <>
XLNT_API bool cell::get_value() const
{
return d_->value_numeric_ != 0;
return d_->value_numeric_ != 0.L;
}
template <>
@ -758,44 +770,38 @@ XLNT_API timedelta cell::get_value() const
void cell::set_alignment(const xlnt::alignment &alignment_)
{
auto &format = duplicate_format();
format.alignment(alignment_, true);
d_->format_id_ = format.id();
auto new_format = has_format() ? modifiable_format() : get_workbook().create_format();
format(new_format.alignment(alignment_, true));
}
void cell::set_border(const xlnt::border &border_)
{
auto &format = duplicate_format();
format.border(border_, true);
d_->format_id_ = format.id();
auto new_format = has_format() ? modifiable_format() : get_workbook().create_format();
format(new_format.border(border_, true));
}
void cell::set_fill(const xlnt::fill &fill_)
{
auto &format = duplicate_format();
format.fill(fill_, true);
d_->format_id_ = format.id();
auto new_format = has_format() ? modifiable_format() : get_workbook().create_format();
format(new_format.fill(fill_, true));
}
void cell::set_font(const font &font_)
{
auto &format = duplicate_format();
format.font(font_, true);
d_->format_id_ = format.id();
auto new_format = has_format() ? modifiable_format() : get_workbook().create_format();
format(new_format.font(font_, true));
}
void cell::set_number_format(const number_format &number_format_)
{
auto &format = duplicate_format();
format.number_format(number_format_, true);
d_->format_id_ = format.id();
auto new_format = has_format() ? modifiable_format() : get_workbook().create_format();
format(new_format.number_format(number_format_, true));
}
void cell::set_protection(const xlnt::protection &protection_)
{
auto &format = duplicate_format();
format.protection(protection_, true);
d_->format_id_ = format.id();
auto new_format = has_format() ? modifiable_format() : get_workbook().create_format();
format(new_format.protection(protection_, true));
}
template <>
@ -817,7 +823,7 @@ bool cell::has_value() const
std::string cell::to_string() const
{
auto nf = get_computed_number_format();
auto nf = computed_number_format();
switch (get_data_type())
{
@ -838,12 +844,12 @@ std::string cell::to_string() const
bool cell::has_format() const
{
return d_->format_id_.is_set();
return d_->format_.is_set();
}
void cell::set_format(const format &new_format)
void cell::format(const class format new_format)
{
d_->format_id_ = new_format.id();
d_->format_ = new_format.d_;
}
calendar cell::get_base_date() const
@ -891,157 +897,91 @@ void cell::guess_type_and_set_value(const std::string &value)
void cell::clear_format()
{
d_->format_id_.clear();
d_->format_.clear();
}
void cell::clear_style()
{
if (has_format())
{
get_format_internal().clear_style();
modifiable_format().clear_style();
}
}
void cell::set_style(const style &new_style)
void cell::style(const class style &new_style)
{
auto &new_format = duplicate_format();
new_format.style(new_style);
d_->format_id_ = new_format.id();
auto new_format = has_format() ? format() : get_workbook().create_format();
format(new_format.style(new_style));
}
void cell::set_style(const std::string &style_name)
void cell::style(const std::string &style_name)
{
auto &new_format = duplicate_format();
new_format.style(get_workbook().get_style(style_name).name());
d_->format_id_ = new_format.id();
style(get_workbook().style(style_name));
}
style cell::get_style() const
const style cell::style() const
{
if (!has_format() || !get_format().has_style())
if (!has_format() || !format().has_style())
{
throw invalid_attribute();
}
return get_format().style();
return format().style();
}
bool cell::has_style() const
{
return has_format() && get_format().has_style();
return has_format() && format().has_style();
}
base_format cell::get_computed_format() const
format cell::modifiable_format()
{
base_format result;
// Check style first
if (has_style())
{
style cell_style = get_style();
if (cell_style.alignment_applied()) result.alignment(cell_style.alignment(), true);
if (cell_style.border_applied()) result.border(cell_style.border(), true);
if (cell_style.fill_applied()) result.fill(cell_style.fill(), true);
if (cell_style.font_applied()) result.font(cell_style.font(), true);
if (cell_style.number_format_applied()) result.number_format(cell_style.number_format(), true);
if (cell_style.protection_applied()) result.protection(cell_style.protection(), true);
}
// Cell format overrides style
if (has_format())
{
format cell_format = get_format();
if (cell_format.alignment_applied()) result.alignment(cell_format.alignment(), true);
if (cell_format.border_applied()) result.border(cell_format.border(), true);
if (cell_format.fill_applied()) result.fill(cell_format.fill(), true);
if (cell_format.font_applied()) result.font(cell_format.font(), true);
if (cell_format.number_format_applied()) result.number_format(cell_format.number_format(), true);
if (cell_format.protection_applied()) result.protection(cell_format.protection(), true);
}
// Use defaults for any remaining non-applied components
if (!result.alignment_applied()) result.alignment(alignment(), true);
if (!result.border_applied()) result.border(border(), true);
if (!result.fill_applied()) result.fill(fill(), true);
if (!result.font_applied()) result.font(font(), true);
if (!result.number_format_applied()) result.number_format(number_format(), true);
if (!result.protection_applied()) result.protection(protection(), true);
return result;
}
format &cell::get_format_internal()
{
if (!d_->format_id_)
if (!d_->format_)
{
throw invalid_attribute();
}
return get_workbook().get_format(*d_->format_id_);
return xlnt::format(*d_->format_);
}
format &cell::duplicate_format()
const format cell::format() const
{
auto &new_format = get_workbook().create_format();
if (has_format())
{
auto &current_format = get_format_internal();
new_format.alignment(current_format.alignment(), current_format.alignment_applied());
new_format.border(current_format.border(), current_format.border_applied());
new_format.fill(current_format.fill(), current_format.fill_applied());
new_format.font(current_format.font(), current_format.font_applied());
new_format.number_format(current_format.number_format(), current_format.number_format_applied());
new_format.protection(current_format.protection(), current_format.protection_applied());
}
return new_format;
}
format cell::get_format() const
{
if (!d_->format_id_)
if (!d_->format_)
{
throw invalid_attribute();
}
return get_workbook().get_format(*d_->format_id_);
return xlnt::format(*d_->format_);
}
alignment cell::get_alignment() const
{
return get_format().alignment();
return format().alignment();
}
border cell::get_border() const
{
return get_format().border();
return format().border();
}
fill cell::get_fill() const
{
return get_format().fill();
return format().fill();
}
font cell::get_font() const
{
return get_format().font();
return format().font();
}
number_format cell::get_number_format() const
{
return get_format().number_format();
return format().number_format();
}
protection cell::get_protection() const
{
return get_format().protection();
return format().protection();
}
bool cell::has_hyperlink() const
@ -1053,7 +993,7 @@ bool cell::has_hyperlink() const
bool cell::has_comment()
{
return (bool)d_->comment_;
return d_->comment_.is_set();
}
void cell::clear_comment()

View File

@ -18,18 +18,6 @@ public:
wb_guess_types.set_guess_types(true);
}
void test_temp()
{
xlnt::workbook wb;
auto ws = wb.get_active_sheet();
auto cell = ws.get_cell("A1");
cell.set_value(3.141592);
cell.set_font(xlnt::font().bold(true));
cell.set_font(xlnt::font().size(20));
wb.save("a.xlsx");
wb.load("a.xlsx");
}
void test_infer_numeric()
{
auto ws = wb_guess_types.create_sheet();
@ -325,7 +313,7 @@ public:
cell.set_font(font);
TS_ASSERT(cell.has_format());
TS_ASSERT(cell.get_format().font_applied());
TS_ASSERT(cell.format().font_applied());
TS_ASSERT_EQUALS(cell.get_font(), font);
}
@ -340,7 +328,7 @@ public:
cell.set_fill(fill);
TS_ASSERT(cell.has_format());
TS_ASSERT(cell.get_format().fill_applied());
TS_ASSERT(cell.format().fill_applied());
TS_ASSERT_EQUALS(cell.get_fill(), fill);
}
@ -354,7 +342,7 @@ public:
cell.set_border(border);
TS_ASSERT(cell.has_format());
TS_ASSERT(cell.get_format().border_applied());
TS_ASSERT(cell.format().border_applied());
TS_ASSERT_EQUALS(cell.get_border(), border);
}
@ -367,7 +355,7 @@ public:
cell.set_number_format(format);
TS_ASSERT(cell.has_format());
TS_ASSERT(cell.get_format().number_format_applied());
TS_ASSERT(cell.format().number_format_applied());
TS_ASSERT_EQUALS(cell.get_number_format().get_format_string(), "dd--hh--mm");
}
@ -382,7 +370,7 @@ public:
cell.set_alignment(align);
TS_ASSERT(cell.has_format());
TS_ASSERT(cell.get_format().alignment_applied());
TS_ASSERT(cell.format().alignment_applied());
TS_ASSERT_EQUALS(cell.get_alignment(), align);
}
@ -397,7 +385,7 @@ public:
cell.set_protection(protection);
TS_ASSERT(cell.has_format());
TS_ASSERT(cell.get_format().protection_applied());
TS_ASSERT(cell.format().protection_applied());
TS_ASSERT_EQUALS(cell.get_protection(), protection);
TS_ASSERT(cell.has_format());
@ -412,34 +400,34 @@ public:
TS_ASSERT(!cell.has_style());
auto &test_style = wb.create_style("test_style");
auto test_style = wb.create_style("test_style");
test_style.number_format(xlnt::number_format::date_ddmmyyyy(), true);
cell.set_style(test_style);
cell.style(test_style);
TS_ASSERT(cell.has_style());
TS_ASSERT_EQUALS(cell.get_style().number_format(), xlnt::number_format::date_ddmmyyyy());
TS_ASSERT_EQUALS(cell.get_style(), test_style);
TS_ASSERT_EQUALS(cell.style().number_format(), xlnt::number_format::date_ddmmyyyy());
TS_ASSERT_EQUALS(cell.style(), test_style);
auto &other_style = wb.create_style("other_style");
auto other_style = wb.create_style("other_style");
other_style.number_format(xlnt::number_format::date_time2(), true);
cell.set_style("other_style");
TS_ASSERT_EQUALS(cell.get_style().number_format(), xlnt::number_format::date_time2());
TS_ASSERT_EQUALS(cell.get_style(), other_style);
cell.style("other_style");
TS_ASSERT_EQUALS(cell.style().number_format(), xlnt::number_format::date_time2());
TS_ASSERT_EQUALS(cell.style(), other_style);
auto &last_style = wb.create_style("last_style");
auto last_style = wb.create_style("last_style");
last_style.number_format(xlnt::number_format::percentage(), true);
cell.set_style(last_style);
TS_ASSERT_EQUALS(cell.get_style().number_format(), xlnt::number_format::percentage());
TS_ASSERT_EQUALS(cell.get_style(), last_style);
cell.style(last_style);
TS_ASSERT_EQUALS(cell.style().number_format(), xlnt::number_format::percentage());
TS_ASSERT_EQUALS(cell.style(), last_style);
TS_ASSERT_THROWS(cell.set_style("doesn't exist"), xlnt::key_not_found);
TS_ASSERT_THROWS(cell.style("doesn't exist"), xlnt::key_not_found);
cell.clear_style();
TS_ASSERT(!cell.has_style());
TS_ASSERT_THROWS(cell.get_style(), xlnt::invalid_attribute);
TS_ASSERT_THROWS(cell.style(), xlnt::invalid_attribute);
}
void test_print()

View File

@ -34,6 +34,7 @@
namespace xlnt {
namespace detail {
struct format_impl;
struct worksheet_impl;
struct cell_impl
@ -54,7 +55,7 @@ struct cell_impl
optional<std::string> formula_;
optional<std::string> hyperlink_;
optional<std::size_t> format_id_;
optional<format_impl *> format_;
optional<comment> comment_;
};

View File

@ -427,6 +427,6 @@ const std::vector<std::uint8_t> &excel_thumbnail()
};
return *data;
};
}
} // namespace xlnt

View File

@ -30,13 +30,36 @@ struct format_impl
std::size_t id;
optional<std::size_t> alignment_id;
bool alignment_applied = false;
optional<std::size_t> border_id;
bool border_applied = false;
optional<std::size_t> fill_id;
bool fill_applied = false;
optional<std::size_t> font_id;
bool font_applied = false;
optional<std::size_t> number_format_id;
bool number_format_applied = false;
optional<std::size_t> protection_id;
bool protection_applied = false;
optional<std::string> style;
XLNT_API friend bool operator==(const format_impl &left, const format_impl &right)
{
return left.parent == right.parent
&& left.alignment_id == right.alignment_id
&& left.border_id == right.border_id
&& left.fill_id == right.fill_id
&& left.font_id == right.font_id
&& left.number_format_id == right.number_format_id
&& left.protection_id == right.protection_id
&& left.style == right.style;
}
};
} // namespace detail

View File

@ -31,12 +31,23 @@ struct style_impl
optional<std::size_t> builtin_id;
optional<std::size_t> outline_style;
optional<class alignment> alignment;
optional<class border> border;
optional<class fill> fill;
optional<class font> font;
optional<class number_format> number_format;
optional<class protection> protection;
optional<std::size_t> alignment_id;
bool alignment_applied = false;
optional<std::size_t> border_id;
bool border_applied = false;
optional<std::size_t> fill_id;
bool fill_applied = false;
optional<std::size_t> font_id;
bool font_applied = false;
optional<std::size_t> number_format_id;
bool number_format_applied = false;
optional<std::size_t> protection_id;
bool protection_applied = false;
};
} // namespace detail

View File

@ -42,66 +42,54 @@ namespace detail {
struct stylesheet
{
~stylesheet()
{
}
format &create_format()
format create_format()
{
format_impls.push_back(format_impl());
auto &impl = format_impls.back();
impl.parent = this;
impl.id = format_impls.size() - 1;
impl.border_id = 0;
impl.fill_id = 0;
impl.font_id = 0;
impl.number_format_id = 0;
return format(&impl);
}
format get_format(std::size_t index)
{
auto iter = format_impls.begin();
std::advance(iter, index);
return format(&*iter);
}
class style create_style(const std::string &name)
{
auto &impl = style_impls.emplace(name, style_impl()).first->second;
impl.parent = this;
impl.name = name;
impl.border_id = 0;
impl.fill_id = 0;
impl.font_id = 0;
impl.number_format_id = 0;
formats.push_back(format(&impl));
auto &format = formats.back();
return format;
style_names.push_back(name);
return xlnt::style(&impl);
}
format &get_format(std::size_t index)
class style style(const std::string &name)
{
return formats.at(index);
}
style &create_style()
{
style_impls.push_back(style_impl());
auto &impl = style_impls.back();
impl.parent = this;
styles.push_back(style(&impl));
return styles.back();
}
style &get_style(const std::string &name)
{
for (auto &s : styles)
{
if (s.name() == name)
{
return s;
}
}
throw key_not_found();
if (!has_style(name)) throw key_not_found();
return xlnt::style(&style_impls[name]);
}
bool has_style(const std::string &name)
{
for (auto &s : styles)
{
if (s.name() == name)
{
return true;
}
}
return false;
return style_impls.count(name) > 0;
}
std::size_t next_custom_number_format_id() const
@ -119,70 +107,290 @@ struct stylesheet
return id;
}
std::size_t add_border(const border &new_border)
template<typename T, typename C>
std::size_t find_or_add(C &container, const T &item)
{
std::size_t index = 0;
std::size_t i = 0;
for (const border &f : borders)
for (auto iter = container.begin(); iter != container.end(); ++iter)
{
if (f == new_border)
if (*iter == item)
{
return index;
return i;
}
++index;
++i;
}
borders.push_back(new_border);
container.emplace(container.end(), item);
return index;
return container.size() - 1;
}
std::size_t add_fill(const fill &new_fill)
template<typename T>
std::unordered_map<std::size_t, std::size_t> garbage_collect(
const std::unordered_map<std::size_t, std::size_t> &reference_counts,
std::vector<T> &container)
{
std::size_t index = 0;
for (const fill &f : fills)
{
if (f == new_fill)
{
return index;
}
++index;
}
fills.push_back(new_fill);
std::unordered_map<std::size_t, std::size_t> id_map;
std::size_t unreferenced = 0;
const auto original_size = container.size();
return index;
for (std::size_t i = 0; i < original_size; ++i)
{
id_map[i] = i - unreferenced;
if (reference_counts.count(i) == 0 || reference_counts.at(i) == 0)
{
container.erase(container.begin() + i - unreferenced);
unreferenced++;
}
}
return id_map;
}
std::size_t add_font(const font &new_font)
void garbage_collect(std::size_t new_format, std::size_t old_format)
{
std::size_t index = 0;
if (!garbage_collection_enabled) return;
std::unordered_map<std::size_t, std::size_t> format_reference_counts;
for (const font &f : fonts)
for (const auto &impl : format_impls)
{
if (f == new_font)
{
return index;
}
++index;
format_reference_counts[impl.id] = 0;
}
fonts.push_back(new_font);
format_reference_counts[new_format]++;
parent->apply_to_cells([&format_reference_counts](cell c)
{
if (c.has_format())
{
format_reference_counts[c.format().id()]++;
}
});
if (format_reference_counts[old_format] > 0)
{
format_reference_counts[old_format]--;
}
for (const auto &id_count_pair : format_reference_counts)
{
if (id_count_pair.second != 0) continue;
return index;
auto target_id = id_count_pair.first;
auto target = std::find_if(format_impls.begin(), format_impls.end(),
[=](const format_impl &impl) { return impl.id == target_id; });
format_impls.erase(target);
}
std::size_t new_id = 0;
std::unordered_map<std::size_t, std::size_t> alignment_reference_counts;
std::unordered_map<std::size_t, std::size_t> border_reference_counts;
std::unordered_map<std::size_t, std::size_t> fill_reference_counts;
std::unordered_map<std::size_t, std::size_t> font_reference_counts;
std::unordered_map<std::size_t, std::size_t> number_format_reference_counts;
std::unordered_map<std::size_t, std::size_t> protection_reference_counts;
for (auto &impl : format_impls)
{
impl.id = new_id++;
if (impl.alignment_id.is_set())
{
alignment_reference_counts[impl.alignment_id.get()]++;
}
if (impl.border_id.is_set())
{
border_reference_counts[impl.border_id.get()]++;
}
if (impl.fill_id.is_set())
{
fill_reference_counts[impl.fill_id.get()]++;
}
if (impl.font_id.is_set())
{
font_reference_counts[impl.font_id.get()]++;
}
if (impl.number_format_id.is_set())
{
number_format_reference_counts[impl.number_format_id.get()]++;
}
if (impl.protection_id.is_set())
{
protection_reference_counts[impl.protection_id.get()]++;
}
}
for (auto &name_impl_pair : style_impls)
{
auto &impl = name_impl_pair.second;
if (impl.alignment_id.is_set())
{
alignment_reference_counts[impl.alignment_id.get()]++;
}
if (impl.border_id.is_set())
{
border_reference_counts[impl.border_id.get()]++;
}
if (impl.fill_id.is_set())
{
fill_reference_counts[impl.fill_id.get()]++;
}
if (impl.font_id.is_set())
{
font_reference_counts[impl.font_id.get()]++;
}
if (impl.number_format_id.is_set())
{
number_format_reference_counts[impl.number_format_id.get()]++;
}
if (impl.protection_id.is_set())
{
protection_reference_counts[impl.protection_id.get()]++;
}
}
auto alignment_id_map = garbage_collect(alignment_reference_counts, alignments);
auto border_id_map = garbage_collect(border_reference_counts, borders);
auto fill_id_map = garbage_collect(fill_reference_counts, fills);
auto font_id_map = garbage_collect(font_reference_counts, fonts);
auto number_format_id_map = garbage_collect(number_format_reference_counts, number_formats);
auto protection_id_map = garbage_collect(protection_reference_counts, protections);
for (auto &impl : format_impls)
{
if (impl.alignment_id.is_set())
{
impl.alignment_id = alignment_id_map[impl.alignment_id.get()];
}
if (impl.border_id.is_set())
{
impl.border_id = border_id_map[impl.border_id.get()];
}
if (impl.fill_id.is_set())
{
impl.fill_id = fill_id_map[impl.fill_id.get()];
}
if (impl.font_id.is_set())
{
impl.font_id = font_id_map[impl.font_id.get()];
}
if (impl.number_format_id.is_set())
{
impl.number_format_id = number_format_id_map[impl.number_format_id.get()];
}
if (impl.protection_id.is_set())
{
impl.protection_id = protection_id_map[impl.protection_id.get()];
}
}
}
format_impl *find_or_create(const format_impl &pattern)
{
auto iter = format_impls.begin();
auto id = find_or_add(format_impls, pattern);
std::advance(iter, id);
auto &result = *iter;
result.parent = this;
result.id = id;
if (id != pattern.id)
{
garbage_collect(id, pattern.id);
}
return &result;
}
format_impl *find_or_create_with(format_impl *pattern, const alignment &new_alignment, bool applied)
{
format_impl new_format = *pattern;
new_format.alignment_id = find_or_add(alignments, new_alignment);
new_format.alignment_applied = applied;
return find_or_create(new_format);
}
format_impl *find_or_create_with(format_impl *pattern, const border &new_border, bool applied)
{
format_impl new_format = *pattern;
new_format.border_id = find_or_add(borders, new_border);
new_format.border_applied = applied;
return find_or_create(new_format);
}
format_impl *find_or_create_with(format_impl *pattern, const fill &new_fill, bool applied)
{
format_impl new_format = *pattern;
new_format.fill_id = find_or_add(fills, new_fill);
new_format.fill_applied = applied;
return find_or_create(new_format);
}
format_impl *find_or_create_with(format_impl *pattern, const font &new_font, bool applied)
{
format_impl new_format = *pattern;
new_format.font_id = find_or_add(fonts, new_font);
new_format.font_applied = applied;
return find_or_create(new_format);
}
format_impl *find_or_create_with(format_impl *pattern, const number_format &new_number_format, bool applied)
{
format_impl new_format = *pattern;
new_format.number_format_id = find_or_add(number_formats, new_number_format);
new_format.number_format_applied = applied;
return find_or_create(new_format);
}
format_impl *find_or_create_with(format_impl *pattern, const protection &new_protection, bool applied)
{
format_impl new_format = *pattern;
new_format.protection_id = find_or_add(protections, new_protection);
new_format.protection_applied = applied;
return find_or_create(new_format);
}
std::size_t style_index(const std::string &name) const
{
return std::distance(style_names.begin(),
std::find(style_names.begin(), style_names.end(), name));
}
void clear()
{
format_impls.clear();
formats.clear();
style_impls.clear();
styles.clear();
style_names.clear();
alignments.clear();
borders.clear();
@ -193,64 +401,24 @@ struct stylesheet
colors.clear();
}
format_impl *deduplicate(format_impl *f)
void enable_garbage_collection()
{
std::unordered_map<format_impl *, std::size_t> reference_counts;
garbage_collection_enabled = true;
}
for (auto ws : *parent)
{
auto dimension = ws.calculate_dimension();
for (auto row = dimension.get_top_left().get_row(); row <= dimension.get_bottom_right().get_row(); row++)
{
for (auto column = dimension.get_top_left().get_column(); column <= dimension.get_bottom_right().get_column(); column++)
{
if (ws.has_cell(cell_reference(column, row)))
{
auto cell = ws.get_cell(cell_reference(column, row));
if (cell.has_format())
{
reference_counts[formats.at(cell.get_format().id()).d_]++;
}
}
}
}
}
auto result = f;
for (auto &impl : format_impls)
{
if (reference_counts[&impl] == 0 && &impl != f)
{
result = &impl;
break;
}
}
/*
if (result != f)
{
auto impl_iter = std::find_if(format_impls.begin(), format_impls.end(),
[=](const format_impl &impl) { return &impl == f; });
auto index = std::distance(format_impls.begin(), impl_iter);
formats.erase(formats.begin() + index);
format_impls.erase(impl_iter);
}
*/
return f;
void disable_garbage_collection()
{
garbage_collection_enabled = false;
}
workbook *parent;
bool garbage_collection_enabled = true;
std::list<format_impl> format_impls;
std::vector<format> formats;
std::list<style_impl> style_impls;
std::vector<style> styles;
std::unordered_map<std::string, style_impl> style_impls;
std::vector<std::string> style_names;
std::vector<alignment> alignments;
std::vector<border> borders;

View File

@ -1296,13 +1296,16 @@ void xlsx_consumer::read_stylesheet()
auto &data = *style_datas.emplace(style_datas.end());
parser().next_expect(xml::parser::event_type::start_element, xmlns, "cellStyle");
data.name = parser().attribute("name");
data.record_id = parser().attribute<std::size_t>("xfId");
data.builtin_id = parser().attribute<std::size_t>("builtinId");
if (parser().attribute_present("customBuiltin"))
{
data.custom_builtin = parser().attribute("customBuiltin") == "1";
data.custom_builtin = is_true(parser().attribute("customBuiltin"));
}
parser().next_expect(xml::parser::event_type::end_element, xmlns, "cellStyle");
}
@ -1530,14 +1533,13 @@ void xlsx_consumer::read_stylesheet()
for (const auto &record : style_records)
{
auto &new_style = stylesheet.create_style();
auto style_data_iter = std::find_if(style_datas.begin(), style_datas.end(),
[&xf_id](const style_data &s) { return s.record_id == xf_id; });
++xf_id;
if (style_data_iter == style_datas.end()) continue;
new_style.name(style_data_iter->name);
auto new_style = stylesheet.create_style(style_data_iter->name);
new_style.builtin_id(style_data_iter->builtin_id);
new_style.alignment(record.alignment.first, record.alignment.second);
@ -1548,18 +1550,33 @@ void xlsx_consumer::read_stylesheet()
new_style.protection(record.protection.first, record.protection.second);
}
std::size_t record_index = 0;
for (const auto &record : format_records)
{
auto &new_format = stylesheet.create_format();
stylesheet.format_impls.push_back(format_impl());
auto &new_format = stylesheet.format_impls.back();
new_format.style(stylesheet.styles.at(record.style_id.first).name());
new_format.id = record_index++;
new_format.parent = &stylesheet;
if (record.style_id.second)
{
new_format.style = stylesheet.style_names[record.style_id.first];
}
new_format.alignment(record.alignment.first, record.alignment.second);
new_format.border(stylesheet.borders.at(record.border_id.first), record.border_id.second);
new_format.fill(stylesheet.fills.at(record.fill_id.first), record.fill_id.second);
new_format.font(stylesheet.fonts.at(record.font_id.first), record.font_id.second);
new_format.number_format(lookup_number_format(record.number_format_id.first), record.number_format_id.second);
new_format.protection(record.protection.first, record.protection.second);
new_format.alignment_id = stylesheet.find_or_add(stylesheet.alignments, record.alignment.first);
new_format.alignment_applied = record.alignment.second;
new_format.border_id = record.border_id.first;
new_format.border_applied = record.border_id.second;
new_format.fill_id = record.fill_id.first;
new_format.fill_applied = record.fill_id.second;
new_format.font_id = record.font_id.first;
new_format.font_applied = record.font_id.second;
new_format.number_format_id = record.number_format_id.first;
new_format.number_format_applied = record.number_format_id.second;
new_format.protection_id = stylesheet.find_or_add(stylesheet.protections, record.protection.first);
new_format.protection_applied = record.protection.second;
}
}
@ -1845,7 +1862,7 @@ void xlsx_consumer::read_worksheet(const std::string &rel_id)
if (has_format)
{
cell.set_format(target_.get_format(format_id));
cell.format(target_.get_format(format_id));
}
parser().next_expect(xml::parser::event_type::end_element, xmlns, "c");

View File

@ -101,7 +101,7 @@ struct crypto_helper
auto decoded = pipe.read_all();
return std::vector<std::uint8_t>(decoded.begin(), decoded.end());
};
}
static std::vector<std::uint8_t> hash(hash_algorithm algorithm,
const std::vector<std::uint8_t> &input)
@ -112,7 +112,7 @@ struct crypto_helper
auto hash = pipe.read_all();
return std::vector<std::uint8_t>(hash.begin(), hash.end());
};
}
static std::vector<std::uint8_t> get_file(POLE::Storage &storage, const std::string &name)
{
@ -130,7 +130,7 @@ struct crypto_helper
index += sizeof(T);
return result;
};
}
struct standard_encryption_info
{

View File

@ -148,19 +148,14 @@ void xlsx_producer::end_part()
{
current_part_serializer_.reset();
}
if (current_part_stream_)
{
current_part_stream_.reset();
}
archive_->close();
}
void xlsx_producer::begin_part(const path &part)
{
end_part();
current_part_stream_.reset(archive_->open(part.string()));
current_part_serializer_.reset(new xml::serializer(*current_part_stream_, part.string()));
current_part_serializer_.reset(new xml::serializer(archive_->open(part.string()), part.string()));
}
// Package Parts
@ -770,11 +765,15 @@ void xlsx_producer::write_styles(const relationship &rel)
{
const auto &number_formats = stylesheet.number_formats;
auto num_custom = std::count_if(number_formats.begin(), number_formats.end(),
[](const number_format &nf) { return nf.get_id() >= 164; });
serializer().start_element(xmlns, "numFmts");
serializer().attribute("count", number_formats.size());
serializer().attribute("count", num_custom);
for (const auto &num_fmt : number_formats)
{
if (num_fmt.get_id() < 164) continue;
serializer().start_element(xmlns, "numFmt");
serializer().attribute("numFmtId", num_fmt.get_id());
serializer().attribute("formatCode", num_fmt.get_format_string());
@ -1020,68 +1019,90 @@ void xlsx_producer::write_styles(const relationship &rel)
// Style XFs
serializer().start_element(xmlns, "cellStyleXfs");
serializer().attribute("count", stylesheet.styles.size());
serializer().attribute("count", stylesheet.style_impls.size());
for (auto &current_style : stylesheet.styles)
for (auto &current_style_name_impl : stylesheet.style_impls)
{
auto &current_style_impl = current_style_name_impl.second;
serializer().start_element(xmlns, "xf");
serializer().attribute("numFmtId", current_style.number_format().get_id());
serializer().attribute("fontId", std::distance(stylesheet.fonts.begin(),
std::find(stylesheet.fonts.begin(), stylesheet.fonts.end(), current_style.font())));
serializer().attribute("fillId", std::distance(stylesheet.fills.begin(),
std::find(stylesheet.fills.begin(), stylesheet.fills.end(), current_style.fill())));
serializer().attribute("borderId", std::distance(stylesheet.borders.begin(),
std::find(stylesheet.borders.begin(), stylesheet.borders.end(), current_style.border())));
serializer().attribute("numFmtId", current_style_impl.number_format_id.get());
serializer().attribute("fontId", current_style_impl.font_id.get());
serializer().attribute("fillId", current_style_impl.fill_id.get());
serializer().attribute("borderId", current_style_impl.border_id.get());
if (current_style.number_format_applied()) serializer().attribute("applyNumberFormat", write_bool(true));
if (current_style.fill_applied()) serializer().attribute("applyFill", write_bool(true));
if (current_style.font_applied()) serializer().attribute("applyFont", write_bool(true));
if (current_style.border_applied()) serializer().attribute("applyBorder", write_bool(true));
if (current_style.alignment_applied()) serializer().attribute("applyAlignment", write_bool(true));
if (current_style.protection_applied()) serializer().attribute("applyProtection", write_bool(true));
if (current_style_impl.number_format_applied)
{
serializer().attribute("applyNumberFormat", write_bool(true));
}
if (current_style.alignment_applied())
if (current_style_impl.fill_applied)
{
serializer().attribute("applyFill", write_bool(true));
}
if (current_style_impl.font_applied)
{
serializer().attribute("applyFont", write_bool(true));
}
if (current_style_impl.border_applied)
{
serializer().attribute("applyBorder", write_bool(true));
}
if (current_style_impl.alignment_applied)
{
serializer().attribute("applyAlignment", write_bool(true));
}
if (current_style_impl.protection_applied)
{
serializer().attribute("applyProtection", write_bool(true));
}
if (current_style_impl.alignment_applied)
{
const auto current_alignment = current_style.alignment();
const auto &current_alignment = stylesheet.alignments[current_style_impl.alignment_id.get()];
serializer().start_element(xmlns, "alignment");
if (current_alignment.vertical())
{
serializer().attribute("vertical", *current_alignment.vertical());
serializer().attribute("vertical", current_alignment.vertical().get());
}
if (current_alignment.horizontal())
{
serializer().attribute("horizontal", *current_alignment.horizontal());
serializer().attribute("horizontal", current_alignment.horizontal().get());
}
if (current_alignment.rotation())
{
serializer().attribute("textRotation", *current_alignment.rotation());
serializer().attribute("textRotation", current_alignment.rotation().get());
}
if (current_alignment.wrap())
{
serializer().attribute("wrapText", write_bool(*current_alignment.wrap()));
serializer().attribute("wrapText", write_bool(current_alignment.wrap().get()));
}
if (current_alignment.indent())
{
serializer().attribute("indent", *current_alignment.indent());
serializer().attribute("indent", current_alignment.indent().get());
}
if (current_alignment.shrink())
{
serializer().attribute("shrinkToFit", write_bool(*current_alignment.shrink()));
serializer().attribute("shrinkToFit", write_bool(current_alignment.shrink().get()));
}
serializer().end_element(xmlns, "alignment");
}
if (current_style.protection_applied())
if (current_style_impl.protection_applied)
{
const auto current_protection = current_style.protection();
const auto &current_protection = stylesheet.protections[current_style_impl.protection_id.get()];
serializer().start_element(xmlns, "protection");
serializer().attribute("locked", write_bool(current_protection.locked()));
@ -1097,36 +1118,54 @@ void xlsx_producer::write_styles(const relationship &rel)
// Format XFs
serializer().start_element(xmlns, "cellXfs");
serializer().attribute("count", stylesheet.formats.size());
serializer().attribute("count", stylesheet.format_impls.size());
for (auto &current_format : stylesheet.formats)
for (auto &current_format_impl : stylesheet.format_impls)
{
serializer().start_element(xmlns, "xf");
serializer().attribute("numFmtId", current_format.number_format().get_id());
serializer().attribute("fontId", std::distance(stylesheet.fonts.begin(),
std::find(stylesheet.fonts.begin(), stylesheet.fonts.end(), current_format.font())));
serializer().attribute("fillId", std::distance(stylesheet.fills.begin(),
std::find(stylesheet.fills.begin(), stylesheet.fills.end(), current_format.fill())));
serializer().attribute("borderId", std::distance(stylesheet.borders.begin(),
std::find(stylesheet.borders.begin(), stylesheet.borders.end(), current_format.border())));
serializer().start_element(xmlns, "xf");
serializer().attribute("numFmtId", current_format_impl.number_format_id.get());
serializer().attribute("fontId", current_format_impl.font_id.get());
serializer().attribute("fillId", current_format_impl.fill_id.get());
serializer().attribute("borderId", current_format_impl.border_id.get());
if (current_format.number_format_applied()) serializer().attribute("applyNumberFormat", write_bool(true));
if (current_format.fill_applied()) serializer().attribute("applyFill", write_bool(true));
if (current_format.font_applied()) serializer().attribute("applyFont", write_bool(true));
if (current_format.border_applied()) serializer().attribute("applyBorder", write_bool(true));
if (current_format.alignment_applied()) serializer().attribute("applyAlignment", write_bool(true));
if (current_format.protection_applied()) serializer().attribute("applyProtection", write_bool(true));
if (current_format_impl.number_format_applied)
{
serializer().attribute("applyNumberFormat", write_bool(true));
}
if (current_format.has_style())
if (current_format_impl.fill_applied)
{
serializer().attribute("applyFill", write_bool(true));
}
if (current_format_impl.font_applied)
{
serializer().attribute("applyFont", write_bool(true));
}
if (current_format_impl.border_applied)
{
serializer().attribute("applyBorder", write_bool(true));
}
if (current_format_impl.alignment_applied)
{
serializer().attribute("applyAlignment", write_bool(true));
}
if (current_format_impl.protection_applied)
{
serializer().attribute("applyProtection", write_bool(true));
}
if (current_format_impl.style.is_set())
{
serializer().attribute("xfId", std::distance(stylesheet.styles.begin(),
std::find_if(stylesheet.styles.begin(), stylesheet.styles.end(),
[&](const xlnt::style &s) { return s.name() == current_format.style().name(); })));
serializer().attribute("xfId", stylesheet.style_index(current_format_impl.style.get()));
}
if (current_format.alignment_applied())
if (current_format_impl.alignment_applied)
{
const auto current_alignment = current_format.alignment();
const auto &current_alignment = stylesheet.alignments[current_format_impl.alignment_id.get()];
serializer().start_element(xmlns, "alignment");
@ -1163,9 +1202,9 @@ void xlsx_producer::write_styles(const relationship &rel)
serializer().end_element(xmlns, "alignment");
}
if (current_format.protection_applied())
if (current_format_impl.protection_applied)
{
const auto current_protection = current_format.protection();
const auto &current_protection = stylesheet.protections[current_format_impl.protection_id.get()];
serializer().start_element(xmlns, "protection");
serializer().attribute("locked", write_bool(current_protection.locked()));
@ -1181,29 +1220,31 @@ void xlsx_producer::write_styles(const relationship &rel)
// Styles
serializer().start_element(xmlns, "cellStyles");
serializer().attribute("count", stylesheet.styles.size());
serializer().attribute("count", stylesheet.style_impls.size());
std::size_t style_index = 0;
for (auto &current_style : stylesheet.styles)
for (auto &current_style_name : stylesheet.style_names)
{
const auto &current_style = stylesheet.style_impls.at(current_style_name);
serializer().start_element(xmlns, "cellStyle");
serializer().attribute("name", current_style.name());
serializer().attribute("name", current_style.name);
serializer().attribute("xfId", style_index++);
if (current_style.builtin_id())
if (current_style.builtin_id)
{
serializer().attribute("builtinId", *current_style.builtin_id());
serializer().attribute("builtinId", current_style.builtin_id.get());
}
if (current_style.hidden())
if (current_style.hidden_style)
{
serializer().attribute("hidden", write_bool(true));
}
if (current_style.custom())
if (current_style.custom_builtin)
{
serializer().attribute("customBuiltin", write_bool(*current_style.custom()));
serializer().attribute("customBuiltin", write_bool(current_style.custom_builtin.get()));
}
serializer().end_element(xmlns, "cellStyle");
@ -1972,7 +2013,7 @@ void xlsx_producer::write_worksheet(const relationship &rel)
if (cell.has_format())
{
serializer().attribute("s", cell.get_format().id());
serializer().attribute("s", cell.format().id());
}
if (cell.get_data_type() == cell::type::string)
@ -2510,9 +2551,8 @@ void xlsx_producer::write_thumbnail(const relationship &rel)
end_part();
const auto &thumbnail = source_.get_thumbnail();
current_part_stream_.reset(archive_->open(rel.get_target().get_path().string()));
vector_istreambuf thumbnail_buffer(thumbnail);
*current_part_stream_ << &thumbnail_buffer;
archive_->open(rel.get_target().get_path().string()) << &thumbnail_buffer;
}
xml::serializer &xlsx_producer::serializer()

View File

@ -136,7 +136,6 @@ private:
const workbook &source_;
ZipFileWriter *archive_;
std::unique_ptr<std::ostream> current_part_stream_;
std::unique_ptr<xml::serializer> current_part_serializer_;
};

View File

@ -35,12 +35,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
#include <algorithm>
#include <cassert>
#include <cstring>
#include <fstream>
#include <iomanip>
#include <iostream>
#include <iterator> // for std::back_inserter
#include <stdexcept>
#include <cstring>
#include <string>
extern "C" {
@ -52,7 +52,7 @@ extern "C" {
namespace xlnt {
namespace detail {
template<class T>
template <class T>
inline T read_int(std::istream &stream)
{
T value;
@ -60,7 +60,7 @@ inline T read_int(std::istream &stream)
return value;
}
template<class T>
template <class T>
inline void write_int(std::ostream &stream, T value)
{
stream.write(reinterpret_cast<char *>(&value), sizeof(T));
@ -70,24 +70,24 @@ zip_file_header::zip_file_header()
{
}
bool zip_file_header::read(std::istream& istream,const bool global)
bool zip_file_header::read(std::istream &istream, const bool global)
{
auto sig = read_int<std::uint32_t>(istream);
// read and check for local/global magic
if(global)
if (global)
{
if(sig!=0x02014b50)
if (sig != 0x02014b50)
{
std::cerr<<"Did not find global header signature"<<std::endl;
std::cerr << "Did not find global header signature" << std::endl;
return false;
}
version = read_int<std::uint16_t>(istream);
}
else if(sig!=0x04034b50)
else if (sig != 0x04034b50)
{
std::cerr<<"Did not find local header signature"<<std::endl;
std::cerr << "Did not find local header signature" << std::endl;
return false;
}
@ -106,18 +106,18 @@ bool zip_file_header::read(std::istream& istream,const bool global)
std::uint16_t comment_length = 0;
if(global)
if (global)
{
comment_length = read_int<std::uint16_t>(istream);
/*std::uint16_t disk_number_start = */read_int<std::uint16_t>(istream);
/*std::uint16_t int_file_attrib = */read_int<std::uint16_t>(istream);
/*std::uint32_t ext_file_attrib = */read_int<std::uint32_t>(istream);
/*std::uint16_t disk_number_start = */ read_int<std::uint16_t>(istream);
/*std::uint16_t int_file_attrib = */ read_int<std::uint16_t>(istream);
/*std::uint32_t ext_file_attrib = */ read_int<std::uint32_t>(istream);
header_offset = read_int<std::uint32_t>(istream);
}
filename.resize(filename_length, '\0');
istream.read(&filename[0], filename_length);
extra.resize(extra_length, 0);
istream.read(reinterpret_cast<char *>(extra.data()), extra_length);
@ -130,259 +130,349 @@ bool zip_file_header::read(std::istream& istream,const bool global)
return true;
}
void zip_file_header::Write(std::ostream& ostream,const bool global) const
void zip_file_header::Write(std::ostream &ostream, const bool global) const
{
if(global){
write_int(ostream,(unsigned int)0x02014b50); // header sig
write_int(ostream,(unsigned short)00);} // version made by
else write_int(ostream,(unsigned int)0x04034b50);
write_int(ostream,version);
write_int(ostream,flags);
write_int(ostream,compression_type);
write_int(ostream,stamp_date);
write_int(ostream,stamp_time);
write_int(ostream,crc);
write_int(ostream,compressed_size);
write_int(ostream,uncompressed_size);
write_int(ostream,(unsigned short)filename.length());
write_int(ostream,(unsigned short)0); // extra lengthx
if(global){
write_int(ostream,(unsigned short)0); // filecomment
write_int(ostream,(unsigned short)0); // disk# start
write_int(ostream,(unsigned short)0); // internal file
write_int(ostream,(unsigned int)0); // ext final
write_int(ostream,(unsigned int)header_offset);} // rel offset
for(unsigned int i=0;i<filename.length();i++) write_int(ostream,filename.c_str()[i]);
if (global)
{
write_int(ostream, static_cast<unsigned int>(0x02014b50)); // header sig
write_int(ostream, static_cast<unsigned short>(0)); // version made by
}
else
{
write_int(ostream, static_cast<unsigned int>(0x04034b50));
}
write_int(ostream, version);
write_int(ostream, flags);
write_int(ostream, compression_type);
write_int(ostream, stamp_date);
write_int(ostream, stamp_time);
write_int(ostream, crc);
write_int(ostream, compressed_size);
write_int(ostream, uncompressed_size);
write_int(ostream, static_cast<unsigned short>(filename.length()));
write_int(ostream, static_cast<unsigned short>(0)); // extra lengthx
if (global)
{
write_int(ostream, static_cast<unsigned short>(0)); // filecomment
write_int(ostream, static_cast<unsigned short>(0)); // disk# start
write_int(ostream, static_cast<unsigned short>(0)); // internal file
write_int(ostream, static_cast<unsigned int>(0)); // ext final
write_int(ostream, static_cast<unsigned int>(header_offset)); // rel offset
}
for (unsigned int i = 0; i < filename.length(); i++)
{
write_int(ostream, filename.c_str()[i]);
}
}
class ZipStreambufDecompress:public std::streambuf
class ZipStreambufDecompress : public std::streambuf
{
static const unsigned int buffer_size=512;
std::istream& istream;
static const unsigned int buffer_size = 512;
std::istream &istream;
z_stream strm;
unsigned char in[buffer_size],out[buffer_size];
unsigned char in[buffer_size], out[buffer_size];
zip_file_header header;
int total_read,total_uncompressed;
//bool own_istream;
int total_read, total_uncompressed;
// bool own_istream;
bool valid;
bool compressed_data;
static const unsigned short DEFLATE=8;
static const unsigned short UNCOMPRESSED=0;
static const unsigned short DEFLATE = 8;
static const unsigned short UNCOMPRESSED = 0;
public:
ZipStreambufDecompress(std::istream& stream,zip_file_header central_header)
:istream(stream),header(central_header),total_read(0),total_uncompressed(0),valid(true)
ZipStreambufDecompress(std::istream &stream, zip_file_header central_header)
: istream(stream), header(central_header), total_read(0), total_uncompressed(0), valid(true)
{
strm.zalloc=Z_NULL;strm.zfree=Z_NULL;strm.opaque=Z_NULL;strm.avail_in=0;strm.next_in=Z_NULL;
setg((char*)in,(char*)in,(char*)in);
setp(0,0);
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
strm.avail_in = 0;
strm.next_in = Z_NULL;
setg((char *)in, (char *)in, (char *)in);
setp(0, 0);
// skip the header
valid=header.read(istream,false);
if(header.compression_type==DEFLATE) compressed_data=true;
else if(header.compression_type==UNCOMPRESSED) compressed_data=false;
else{
compressed_data=false;std::cerr<<"ZIP: got unrecognized compressed data (Supported deflate/uncompressed)"<<std::endl;
valid=false;}
valid = header.read(istream, false);
if (header.compression_type == DEFLATE)
compressed_data = true;
else if (header.compression_type == UNCOMPRESSED)
compressed_data = false;
else
{
compressed_data = false;
std::cerr << "ZIP: got unrecognized compressed data (Supported deflate/uncompressed)" << std::endl;
valid = false;
}
// initialize the inflate
if(compressed_data && valid){
int result=inflateInit2(&strm,-MAX_WBITS);
if(result!=Z_OK){std::cerr<<"gzip: inflateInit2 did not return Z_OK"<<std::endl;valid=false;}}
header = central_header;
if (compressed_data && valid)
{
int result = inflateInit2(&strm, -MAX_WBITS);
if (result != Z_OK)
{
std::cerr << "gzip: inflateInit2 did not return Z_OK" << std::endl;
valid = false;
}
}
header = central_header;
}
virtual ~ZipStreambufDecompress()
{if(compressed_data && valid) inflateEnd(&strm);}
{
if (compressed_data && valid) inflateEnd(&strm);
}
int process()
{if(!valid) return -1;
if(compressed_data){
strm.avail_out=buffer_size-4;
strm.next_out=(Bytef*)(out+4);
while(strm.avail_out!=0){
if(strm.avail_in==0){ // buffer empty, read some more from file
istream.read((char*)in,std::min((unsigned int)buffer_size,header.compressed_size-total_read));
strm.avail_in=istream.gcount();
total_read+=strm.avail_in;
strm.next_in=(Bytef*)in;}
int ret=inflate(&strm,Z_NO_FLUSH); // decompress
switch(ret){
case Z_STREAM_ERROR:
std::cerr<<"libz error Z_STREAM_ERROR"<<std::endl;
valid=false;return -1;
{
if (!valid) return -1;
if (compressed_data)
{
strm.avail_out = buffer_size - 4;
strm.next_out = (Bytef *)(out + 4);
while (strm.avail_out != 0)
{
if (strm.avail_in == 0)
{ // buffer empty, read some more from file
istream.read((char *)in, std::min((unsigned int)buffer_size, header.compressed_size - total_read));
strm.avail_in = istream.gcount();
total_read += strm.avail_in;
strm.next_in = (Bytef *)in;
}
int ret = inflate(&strm, Z_NO_FLUSH); // decompress
switch (ret)
{
case Z_STREAM_ERROR:
std::cerr << "libz error Z_STREAM_ERROR" << std::endl;
valid = false;
return -1;
case Z_NEED_DICT:
case Z_DATA_ERROR:
case Z_MEM_ERROR:
std::cerr<<"gzip error "<<strm.msg<<std::endl;
valid=false;return -1;}
if(ret==Z_STREAM_END) break;}
int unzip_count=buffer_size-strm.avail_out-4;
total_uncompressed+=unzip_count;
return unzip_count;}
else{ // uncompressed, so just read
istream.read((char*)(out+4),std::min(buffer_size-4,header.uncompressed_size-total_read));
int count=istream.gcount();
total_read+=count;
return count;}
return 1;}
case Z_MEM_ERROR:
std::cerr << "gzip error " << strm.msg << std::endl;
valid = false;
return -1;
}
if (ret == Z_STREAM_END) break;
}
int unzip_count = buffer_size - strm.avail_out - 4;
total_uncompressed += unzip_count;
return unzip_count;
}
else
{ // uncompressed, so just read
istream.read((char *)(out + 4), std::min(buffer_size - 4, header.uncompressed_size - total_read));
int count = istream.gcount();
total_read += count;
return count;
}
return 1;
}
virtual int underflow()
{if(gptr() && (gptr()<egptr())) return traits_type::to_int_type(*gptr()); // if we already have data just use it
int put_back_count=gptr()-eback();
if(put_back_count>4) put_back_count=4;
std::memmove(out+(4-put_back_count),gptr()-put_back_count,put_back_count);
int num=process();
setg((char*)(out+4-put_back_count),(char*)(out+4),(char*)(out+4+num));
if(num<=0) return EOF;
return traits_type::to_int_type(*gptr());}
{
if (gptr() && (gptr() < egptr()))
return traits_type::to_int_type(*gptr()); // if we already have data just use it
int put_back_count = gptr() - eback();
if (put_back_count > 4) put_back_count = 4;
std::memmove(out + (4 - put_back_count), gptr() - put_back_count, put_back_count);
int num = process();
setg((char *)(out + 4 - put_back_count), (char *)(out + 4), (char *)(out + 4 + num));
if (num <= 0) return EOF;
return traits_type::to_int_type(*gptr());
}
virtual int overflow(int c=EOF)
{assert(false);return EOF;}
virtual int overflow(int c = EOF)
{
assert(false);
return EOF;
}
};
class ZipStreambufCompress:public std::streambuf
class ZipStreambufCompress : public std::streambuf
{
static const int buffer_size=512;
std::ostream& ostream; // owned when header==0 (when not part of zip file)
static const int buffer_size = 512;
std::ostream &ostream; // owned when header==0 (when not part of zip file)
z_stream strm;
unsigned char in[buffer_size],out[buffer_size];
unsigned char in[buffer_size], out[buffer_size];
zip_file_header* header;
zip_file_header *header;
unsigned int uncompressed_size;
unsigned int crc;
bool valid;
public:
ZipStreambufCompress(zip_file_header* central_header,std::ostream& stream)
:ostream(stream),header(central_header),valid(true)
ZipStreambufCompress(zip_file_header *central_header, std::ostream &stream)
: ostream(stream), header(central_header), valid(true)
{
strm.zalloc=Z_NULL;strm.zfree=Z_NULL;strm.opaque=Z_NULL;
int ret=deflateInit2(&strm,Z_DEFAULT_COMPRESSION,Z_DEFLATED,-MAX_WBITS,8,Z_DEFAULT_STRATEGY);
if(ret != Z_OK){std::cerr<<"libz: failed to deflateInit"<<std::endl;valid=false;return;}
setg(0,0,0);
setp((char*)in,(char*)(in+buffer_size-4)); // we want to be 4 aligned
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
int ret = deflateInit2(&strm, Z_DEFAULT_COMPRESSION, Z_DEFLATED, -MAX_WBITS, 8, Z_DEFAULT_STRATEGY);
if (ret != Z_OK)
{
std::cerr << "libz: failed to deflateInit" << std::endl;
valid = false;
return;
}
setg(0, 0, 0);
setp((char *)in, (char *)(in + buffer_size - 4)); // we want to be 4 aligned
// Write appropriate header
if(header){header->header_offset=stream.tellp();header->Write(ostream,false);}
uncompressed_size=crc=0;
if (header)
{
header->header_offset = stream.tellp();
header->Write(ostream, false);
}
uncompressed_size = crc = 0;
}
virtual ~ZipStreambufCompress()
{if(valid){
process(true);
deflateEnd(&strm);
if(header){
std::ios::streampos final_position=ostream.tellp();
header->uncompressed_size=uncompressed_size;
header->crc=crc;
ostream.seekp(header->header_offset);
header->Write(ostream,false);
ostream.seekp(final_position);}
else{write_int(ostream,crc);write_int(ostream,uncompressed_size);}}
if(!header) delete &ostream;}
{
if (valid)
{
process(true);
deflateEnd(&strm);
if (header)
{
std::ios::streampos final_position = ostream.tellp();
header->uncompressed_size = uncompressed_size;
header->crc = crc;
ostream.seekp(header->header_offset);
header->Write(ostream, false);
ostream.seekp(final_position);
}
else
{
write_int(ostream, crc);
write_int(ostream, uncompressed_size);
}
}
if (!header) delete &ostream;
}
protected:
int process(bool flush)
{if(!valid) return -1;
strm.next_in=(Bytef*)pbase();
strm.avail_in=pptr()-pbase();
while(strm.avail_in!=0 || flush){
strm.avail_out=buffer_size;
strm.next_out=(Bytef*)out;
int ret=deflate(&strm,flush?Z_FINISH:Z_NO_FLUSH);
if(!(ret!=Z_BUF_ERROR && ret!=Z_STREAM_ERROR)){
valid=false;
std::cerr<<"gzip: gzip error "<<strm.msg<<std::endl;;
return -1;}
int generated_output=strm.next_out-(Bytef*)out;
ostream.write((char*)out,generated_output);
if(header) header->compressed_size+=generated_output;
if(ret==Z_STREAM_END) break;}
// update counts, crc's and buffers
int consumed_input=pptr()-pbase();
uncompressed_size+=consumed_input;
crc=crc32(crc,(Bytef*)in,consumed_input);
setp(pbase(),pbase()+buffer_size-4);return 1;}
{
if (!valid) return -1;
strm.next_in = (Bytef *)pbase();
strm.avail_in = pptr() - pbase();
while (strm.avail_in != 0 || flush)
{
strm.avail_out = buffer_size;
strm.next_out = (Bytef *)out;
int ret = deflate(&strm, flush ? Z_FINISH : Z_NO_FLUSH);
if (!(ret != Z_BUF_ERROR && ret != Z_STREAM_ERROR))
{
valid = false;
std::cerr << "gzip: gzip error " << strm.msg << std::endl;
;
return -1;
}
int generated_output = strm.next_out - (Bytef *)out;
ostream.write((char *)out, generated_output);
if (header) header->compressed_size += generated_output;
if (ret == Z_STREAM_END) break;
}
// update counts, crc's and buffers
int consumed_input = pptr() - pbase();
uncompressed_size += consumed_input;
crc = crc32(crc, (Bytef *)in, consumed_input);
setp(pbase(), pbase() + buffer_size - 4);
return 1;
}
virtual int sync()
{if(pptr() && pptr()>pbase()) return process(false);return 0;}
{
if (pptr() && pptr() > pbase()) return process(false);
return 0;
}
virtual int underflow()
{std::runtime_error("Attempt to read write only ostream");return 0;}
virtual int overflow(int c=EOF)
{if(c!=EOF){*pptr()=c;pbump(1);}
if(process(false)==EOF) return EOF;
return c;}
};
class ZIP_FILE_ISTREAM:public std::istream
{
ZipStreambufDecompress buf;
public:
ZIP_FILE_ISTREAM(std::istream& istream,zip_file_header header)
:std::istream(&buf),buf(istream,header)
{
std::runtime_error("Attempt to read write only ostream");
return 0;
}
virtual ~ZIP_FILE_ISTREAM()
virtual int overflow(int c = EOF)
{
if (c != EOF)
{
*pptr() = c;
pbump(1);
}
if (process(false) == EOF) return EOF;
return c;
}
};
class ZIP_FILE_OSTREAM:public std::ostream
zip_file_istream::zip_file_istream(std::unique_ptr<std::streambuf> &&buffer)
: std::istream(&*buffer)
{
ZipStreambufCompress buf;
buf.swap(buffer);
}
public:
ZIP_FILE_OSTREAM(zip_file_header* header,std::ostream& ostream)
:std::ostream(&buf),buf(header,ostream)
{
}
virtual ~ZIP_FILE_OSTREAM()
{
}
};
ZipFileWriter::ZipFileWriter(std::ostream& stream) : target_stream_(stream)
zip_file_istream::~zip_file_istream()
{
if(!target_stream_) throw std::runtime_error("ZIP: Invalid file handle");
}
zip_file_ostream::zip_file_ostream(std::unique_ptr<std::streambuf> &&buffer)
: std::ostream(&*buffer)
{
buf.swap(buffer);
}
zip_file_ostream::~zip_file_ostream()
{
}
ZipFileWriter::ZipFileWriter(std::ostream &stream) : target_stream_(stream)
{
if (!target_stream_) throw std::runtime_error("ZIP: Invalid file handle");
}
ZipFileWriter::~ZipFileWriter()
{
// Write all file headers
std::ios::streampos final_position=target_stream_.tellp();
for(unsigned int i=0;i<file_headers_.size();i++)
std::ios::streampos final_position = target_stream_.tellp();
for (unsigned int i = 0; i < file_headers_.size(); i++)
{
file_headers_[i].Write(target_stream_,true);
file_headers_[i].Write(target_stream_, true);
}
std::ios::streampos central_end=target_stream_.tellp();
std::ios::streampos central_end = target_stream_.tellp();
// Write end of central
write_int(target_stream_,(unsigned int)0x06054b50); // end of central
write_int(target_stream_,(unsigned short)0); // this disk number
write_int(target_stream_,(unsigned short)0); // this disk number
write_int(target_stream_,(unsigned short)file_headers_.size()); // one entry in center in this disk
write_int(target_stream_,(unsigned short)file_headers_.size()); // one entry in center
write_int(target_stream_,(unsigned int)(central_end - final_position)); // size of header
write_int(target_stream_,(unsigned int)final_position); // offset to header
write_int(target_stream_,(unsigned short)0); // zip comment
write_int(target_stream_, (unsigned int)0x06054b50); // end of central
write_int(target_stream_, (unsigned short)0); // this disk number
write_int(target_stream_, (unsigned short)0); // this disk number
write_int(target_stream_, (unsigned short)file_headers_.size()); // one entry in center in this disk
write_int(target_stream_, (unsigned short)file_headers_.size()); // one entry in center
write_int(target_stream_, (unsigned int)(central_end - final_position)); // size of header
write_int(target_stream_, (unsigned int)final_position); // offset to header
write_int(target_stream_, (unsigned short)0); // zip comment
}
std::ostream* ZipFileWriter::open(const std::string& filename)
std::ostream &ZipFileWriter::open(const std::string &filename)
{
zip_file_header header;
header.filename = filename;
file_headers_.push_back(header);
return new ZIP_FILE_OSTREAM(&file_headers_.back(),target_stream_);
auto streambuf = std::make_unique<ZipStreambufCompress>(&file_headers_.back(), target_stream_);
auto stream = new zip_file_ostream(std::move(streambuf));
write_stream_.reset(stream);
return *write_stream_;
}
void ZipFileWriter::close()
{
write_stream_.reset(nullptr);
}
ZipFileReader::ZipFileReader(std::istream &stream) : source_stream_(stream)
{
if(!stream)
if (!stream)
{
throw std::runtime_error("ZIP: Invalid file handle");
}
@ -398,26 +488,30 @@ bool ZipFileReader::read_central_header()
{
// Find the header
// NOTE: this assumes the zip file header is the last thing written to file...
source_stream_.seekg(0,std::ios_base::end);
std::ios::streampos end_position=source_stream_.tellg();
source_stream_.seekg(0, std::ios_base::end);
std::ios::streampos end_position = source_stream_.tellg();
auto max_comment_size = std::uint32_t(0xffff); // max size of header
auto read_size_before_comment = std::uint32_t(22);
std::ios::streamoff read_start=max_comment_size+read_size_before_comment;
std::ios::streamoff read_start = max_comment_size + read_size_before_comment;
if(read_start>end_position) read_start=end_position;
source_stream_.seekg(end_position-read_start);
if (read_start > end_position) read_start = end_position;
source_stream_.seekg(end_position - read_start);
std::vector<char> buf(static_cast<std::size_t>(read_start), '\0');
if(read_start<=0){std::cerr<<"ZIP: Invalid read buffer size"<<std::endl;return false;}
if (read_start <= 0)
{
std::cerr << "ZIP: Invalid read buffer size" << std::endl;
return false;
}
source_stream_.read(buf.data(), read_start);
auto found_header = false;
std::size_t header_index = 0;
for(std::size_t i = 0; i < read_start - 3; ++i)
for (std::size_t i = 0; i < read_start - 3; ++i)
{
if(buf[i] == 0x50 && buf[i + 1] == 0x4b && buf[i + 2] == 0x05 && buf[i + 3] == 0x06)
if (buf[i] == 0x50 && buf[i + 1] == 0x4b && buf[i + 2] == 0x05 && buf[i + 3] == 0x06)
{
found_header = true;
header_index = i;
@ -425,35 +519,35 @@ bool ZipFileReader::read_central_header()
}
}
if(!found_header)
if (!found_header)
{
std::cerr<<"ZIP: Failed to find zip header"<<std::endl;
std::cerr << "ZIP: Failed to find zip header" << std::endl;
return false;
}
// seek to end of central header and read
source_stream_.seekg(end_position - (read_start - static_cast<std::ptrdiff_t>(header_index)));
/*auto word = */read_int<std::uint32_t>(source_stream_);
/*auto word = */ read_int<std::uint32_t>(source_stream_);
auto disk_number1 = read_int<std::uint16_t>(source_stream_);
auto disk_number2 = read_int<std::uint16_t>(source_stream_);
if(disk_number1 != disk_number2 || disk_number1 != 0)
if (disk_number1 != disk_number2 || disk_number1 != 0)
{
std::cerr<<"ZIP: multiple disk zip files are not supported"<<std::endl;
std::cerr << "ZIP: multiple disk zip files are not supported" << std::endl;
return false;
}
auto num_files = read_int<std::uint16_t>(source_stream_); // one entry in center in this disk
auto num_files_this_disk = read_int<std::uint16_t>(source_stream_); // one entry in center
if(num_files != num_files_this_disk)
if (num_files != num_files_this_disk)
{
std::cerr<<"ZIP: multi disk zip files are not supported"<<std::endl;
std::cerr << "ZIP: multi disk zip files are not supported" << std::endl;
return false;
}
/*auto size_of_header = */read_int<std::uint32_t>(source_stream_); // size of header
/*auto size_of_header = */ read_int<std::uint32_t>(source_stream_); // size of header
auto header_offset = read_int<std::uint32_t>(source_stream_); // offset to header
// go to header and read all file headers
@ -481,7 +575,8 @@ std::istream &ZipFileReader::open(const std::string &filename)
auto header = file_headers_.at(filename);
source_stream_.seekg(header.header_offset);
read_stream_.reset(new ZIP_FILE_ISTREAM(source_stream_, header));
auto streambuf = std::make_unique<ZipStreambufDecompress>(source_stream_, header);
read_stream_.reset(new zip_file_istream(std::move(streambuf)));
return *read_stream_;
}
@ -496,7 +591,7 @@ std::vector<std::string> ZipFileReader::files() const
bool ZipFileReader::has_file(const std::string &filename) const
{
return file_headers_.count(filename) != 0;
return file_headers_.count(filename) != 0;
}
} // namespace detail

View File

@ -59,8 +59,28 @@ struct zip_file_header
zip_file_header();
bool read(std::istream& istream, const bool global);
void Write(std::ostream& ostream, const bool global) const;
bool read(std::istream &istream, const bool global);
void Write(std::ostream &ostream, const bool global) const;
};
class zip_file_istream : public std::istream
{
public:
zip_file_istream(std::unique_ptr<std::streambuf> &&buf);
virtual ~zip_file_istream();
private:
std::unique_ptr<std::streambuf> buf;
};
class zip_file_ostream : public std::ostream
{
public:
zip_file_ostream(std::unique_ptr<std::streambuf> &&buf);
virtual ~zip_file_ostream();
private:
std::unique_ptr<std::streambuf> buf;
};
class ZipFileWriter
@ -68,11 +88,12 @@ class ZipFileWriter
public:
ZipFileWriter(std::ostream &filename);
virtual ~ZipFileWriter();
std::ostream* open(const std::string& filename);
std::ostream &open(const std::string &filename);
void close();
private:
std::ostream &target_stream_;
std::vector<zip_file_header> file_headers_;
std::ostream &target_stream_;
std::unique_ptr<std::ostream> write_stream_;
};
class ZipFileReader
@ -82,7 +103,7 @@ public:
virtual ~ZipFileReader();
std::istream &open(const std::string &filename);
std::vector<std::string> files() const;
bool has_file(const std::string &filename) const;
bool has_file(const std::string &filename) const;
private:
bool read_central_header();

View File

@ -1,154 +0,0 @@
// Copyright (c) 2014-2016 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
#include <xlnt/styles/base_format.hpp>
namespace xlnt {
alignment &base_format::alignment()
{
return alignment_;
}
const alignment &base_format::alignment() const
{
return alignment_;
}
void base_format::alignment(const xlnt::alignment &new_alignment, bool apply)
{
alignment_ = new_alignment;
apply_alignment_ = apply;
}
number_format &base_format::number_format()
{
return number_format_;
}
const number_format &base_format::number_format() const
{
return number_format_;
}
void base_format::number_format(const xlnt::number_format &new_number_format, bool apply)
{
number_format_ = new_number_format;
apply_number_format_ = apply;
}
border &base_format::border()
{
return border_;
}
const border &base_format::border() const
{
return border_;
}
void base_format::border(const xlnt::border &new_border, bool apply)
{
border_ = new_border;
apply_border_ = apply;
}
fill &base_format::fill()
{
return fill_;
}
const fill &base_format::fill() const
{
return fill_;
}
void base_format::fill(const xlnt::fill &new_fill, bool apply)
{
fill_ = new_fill;
apply_fill_ = apply;
}
font &base_format::font()
{
return font_;
}
const font &base_format::font() const
{
return font_;
}
void base_format::font(const xlnt::font &new_font, bool apply)
{
font_ = new_font;
apply_font_ = apply;
}
protection &base_format::protection()
{
return protection_;
}
const protection &base_format::protection() const
{
return protection_;
}
void base_format::protection(const xlnt::protection &new_protection, bool apply)
{
protection_ = new_protection;
apply_protection_ = apply;
}
bool base_format::alignment_applied() const
{
return apply_alignment_;
}
bool base_format::border_applied() const
{
return apply_border_;
}
bool base_format::fill_applied() const
{
return apply_fill_;
}
bool base_format::font_applied() const
{
return apply_font_;
}
bool base_format::number_format_applied() const
{
return apply_number_format_;
}
bool base_format::protection_applied() const
{
return apply_protection_;
}
} // namespace xlnt

View File

@ -43,23 +43,16 @@ void format::clear_style()
d_->style.clear();
}
void format::style(const xlnt::style &new_style)
format format::style(const xlnt::style &new_style)
{
d_->style = new_style.name();
return format(d_);
}
void format::style(const std::string &new_style)
format format::style(const std::string &new_style)
{
for (auto &style : d_->parent->styles)
{
if (style.name() == new_style)
{
d_->style = new_style;
return;
}
}
throw key_not_found();
d_->style = new_style;
return format(d_);
}
bool format::has_style() const
@ -67,76 +60,91 @@ bool format::has_style() const
return d_->style;
}
const style &format::style() const
const style format::style() const
{
if (!has_style())
{
throw invalid_attribute();
}
return d_->parent->get_style(*d_->style);
return d_->parent->style(d_->style.get());
}
xlnt::alignment &format::alignment()
{
return d_->parent->alignments.at(d_->alignment_id.get());
}
const xlnt::alignment &format::alignment() const
{
return d_->parent->alignments.at(d_->alignment_id.get());
}
format format::alignment(const xlnt::alignment &new_alignment, bool applied)
{
d_ = d_->parent->find_or_create_with(d_, new_alignment, applied);
return format(d_);
}
xlnt::border &format::border()
{
return base_format::border();
return d_->parent->borders.at(d_->border_id.get());
}
const xlnt::border &format::border() const
{
return base_format::border();
return d_->parent->borders.at(d_->border_id.get());
}
void format::border(const xlnt::border &new_border, bool applied)
format format::border(const xlnt::border &new_border, bool applied)
{
border_id(d_->parent->add_border(new_border));
base_format::border(new_border, applied);
d_ = d_->parent->find_or_create_with(d_, new_border, applied);
return format(d_);
}
xlnt::fill &format::fill()
{
return base_format::fill();
return d_->parent->fills.at(d_->fill_id.get());
}
const xlnt::fill &format::fill() const
{
return base_format::fill();
return d_->parent->fills.at(d_->fill_id.get());
}
void format::fill(const xlnt::fill &new_fill, bool applied)
format format::fill(const xlnt::fill &new_fill, bool applied)
{
fill_id(d_->parent->add_fill(new_fill));
base_format::fill(new_fill, applied);
d_ = d_->parent->find_or_create_with(d_, new_fill, applied);
return format(d_);
}
xlnt::font &format::font()
{
return base_format::font();
return d_->parent->fonts.at(d_->font_id.get());
}
const xlnt::font &format::font() const
{
return base_format::font();
return d_->parent->fonts.at(d_->font_id.get());
}
void format::font(const xlnt::font &new_font, bool applied)
format format::font(const xlnt::font &new_font, bool applied)
{
font_id(d_->parent->add_font(new_font));
base_format::font(new_font, applied);
d_ = d_->parent->deduplicate(d_);
d_ = d_->parent->find_or_create_with(d_, new_font, applied);
return format(d_);
}
xlnt::number_format &format::number_format()
{
return base_format::number_format();
return d_->parent->number_formats.at(d_->number_format_id.get());
}
const xlnt::number_format &format::number_format() const
{
return base_format::number_format();
return d_->parent->number_formats.at(d_->number_format_id.get());
}
void format::number_format(const xlnt::number_format &new_number_format, bool applied)
format format::number_format(const xlnt::number_format &new_number_format, bool applied)
{
auto copy = new_number_format;
@ -146,25 +154,54 @@ void format::number_format(const xlnt::number_format &new_number_format, bool ap
d_->parent->number_formats.push_back(copy);
}
base_format::number_format(copy, applied);
d_ = d_->parent->find_or_create_with(d_, copy, applied);
return format(d_);
}
format &format::border_id(std::size_t id)
xlnt::protection &format::protection()
{
d_->border_id = id;
return *this;
return d_->parent->protections.at(d_->protection_id.get());
}
format &format::fill_id(std::size_t id)
const xlnt::protection &format::protection() const
{
d_->fill_id = id;
return *this;
return d_->parent->protections.at(d_->protection_id.get());
}
format &format::font_id(std::size_t id)
format format::protection(const xlnt::protection &new_protection, bool applied)
{
d_->font_id = id;
return *this;
d_ = d_->parent->find_or_create_with(d_, new_protection, applied);
return format(d_);
}
bool format::alignment_applied() const
{
return d_->alignment_applied;
}
bool format::border_applied() const
{
return d_->border_applied;
}
bool format::fill_applied() const
{
return d_->fill_applied;
}
bool format::font_applied() const
{
return d_->font_applied;
}
bool format::number_format_applied() const
{
return d_->number_format_applied;
}
bool format::protection_applied() const
{
return d_->protection_applied;
}
} // namespace xlnt

View File

@ -355,9 +355,7 @@ std::string number_format::format(long double number, calendar base_date) const
XLNT_API bool operator==(const number_format &left, const number_format &right)
{
return left.id_set_ == right.id_set_
&& left.id_ == right.id_
&& left.format_string_ == right.format_string_;
return left.format_string_ == right.format_string_;
}
} // namespace xlnt

View File

@ -22,13 +22,13 @@
// @license: http://www.opensource.org/licenses/mit-license.php
// @author: see AUTHORS file
#include <detail/stylesheet.hpp>
#include <xlnt/styles/alignment.hpp>
#include <xlnt/styles/border.hpp>
#include <xlnt/styles/fill.hpp>
#include <xlnt/styles/font.hpp>
#include <xlnt/styles/number_format.hpp>
#include <xlnt/styles/protection.hpp>
#include <detail/style_impl.hpp> // include order is important here
#include <xlnt/styles/style.hpp>
namespace xlnt {
@ -42,10 +42,10 @@ bool style::hidden() const
return d_->hidden_style;
}
style &style::hidden(bool value)
style style::hidden(bool value)
{
d_->hidden_style = value;
return *this;
return style(d_);
}
optional<std::size_t> style::builtin_id() const
@ -53,7 +53,7 @@ optional<std::size_t> style::builtin_id() const
return d_->builtin_id;
}
style &style::builtin_id(std::size_t builtin_id)
style style::builtin_id(std::size_t builtin_id)
{
d_->builtin_id = builtin_id;
return *this;
@ -64,7 +64,7 @@ std::string style::name() const
return d_->name;
}
style &style::name(const std::string &name)
style style::name(const std::string &name)
{
d_->name = name;
return *this;
@ -75,15 +75,167 @@ optional<bool> style::custom() const
return d_->custom_builtin;
}
style &style::custom(bool value)
style style::custom(bool value)
{
d_->custom_builtin = value;
return *this;
}
bool style::operator==(const style &other)
bool style::operator==(const style &other) const
{
return d_ == other.d_;
return name() == other.name();
}
xlnt::alignment &style::alignment()
{
return d_->parent->alignments.at(d_->alignment_id.get());
}
const xlnt::alignment &style::alignment() const
{
return d_->parent->alignments.at(d_->alignment_id.get());
}
style style::alignment(const xlnt::alignment &new_alignment, bool applied)
{
d_->alignment_id = d_->parent->find_or_add(d_->parent->alignments, new_alignment);
d_->alignment_applied = applied;
return style(d_);
}
xlnt::border &style::border()
{
return d_->parent->borders.at(d_->border_id.get());
}
const xlnt::border &style::border() const
{
return d_->parent->borders.at(d_->border_id.get());
}
style style::border(const xlnt::border &new_border, bool applied)
{
d_->border_id = d_->parent->find_or_add(d_->parent->borders, new_border);
d_->border_applied = applied;
return style(d_);
}
xlnt::fill &style::fill()
{
return d_->parent->fills.at(d_->fill_id.get());
}
const xlnt::fill &style::fill() const
{
return d_->parent->fills.at(d_->fill_id.get());
}
style style::fill(const xlnt::fill &new_fill, bool applied)
{
d_->fill_id = d_->parent->find_or_add(d_->parent->fills, new_fill);
d_->fill_applied = applied;
return style(d_);
}
xlnt::font &style::font()
{
return d_->parent->fonts.at(d_->font_id.get());
}
const xlnt::font &style::font() const
{
return d_->parent->fonts.at(d_->font_id.get());
}
style style::font(const xlnt::font &new_font, bool applied)
{
d_->font_id = d_->parent->find_or_add(d_->parent->fonts, new_font);
d_->font_applied = applied;
return style(d_);
}
xlnt::number_format &style::number_format()
{
auto target_id = d_->number_format_id.get();
return *std::find_if(d_->parent->number_formats.begin(), d_->parent->number_formats.end(),
[=](const class number_format &nf) { return nf.get_id() == target_id; });
}
const xlnt::number_format &style::number_format() const
{
auto target_id = d_->number_format_id.get();
return *std::find_if(d_->parent->number_formats.begin(), d_->parent->number_formats.end(),
[=](const class number_format &nf) { return nf.get_id() == target_id; });
}
style style::number_format(const xlnt::number_format &new_number_format, bool applied)
{
auto copy = new_number_format;
if (!copy.has_id())
{
copy.set_id(d_->parent->next_custom_number_format_id());
d_->parent->number_formats.push_back(copy);
}
else if (std::find_if(d_->parent->number_formats.begin(),
d_->parent->number_formats.end(),
[&copy](const class number_format &nf) { return nf.get_id() == copy.get_id(); })
== d_->parent->number_formats.end())
{
d_->parent->number_formats.push_back(copy);
}
d_->number_format_id = copy.get_id();
d_->number_format_applied = applied;
return style(d_);
}
xlnt::protection &style::protection()
{
return d_->parent->protections.at(d_->protection_id.get());
}
const xlnt::protection &style::protection() const
{
return d_->parent->protections.at(d_->protection_id.get());
}
style style::protection(const xlnt::protection &new_protection, bool applied)
{
d_->protection_id = d_->parent->find_or_add(d_->parent->protections, new_protection);
d_->protection_applied = applied;
return style(d_);
}
bool style::alignment_applied() const
{
return d_->alignment_applied;
}
bool style::border_applied() const
{
return d_->border_applied;
}
bool style::fill_applied() const
{
return d_->fill_applied;
}
bool style::font_applied() const
{
return d_->font_applied;
}
bool style::number_format_applied() const
{
return d_->number_format_applied;
}
bool style::protection_applied() const
{
return d_->protection_applied;
}
} // namespace xlnt

View File

@ -20,12 +20,14 @@ public:
{
std::vector<std::uint8_t> original_buffer;
original.save(original_buffer);
original.save("b.xlsx");
xlnt::workbook resulting_workbook;
resulting_workbook.load(original_buffer);
std::vector<std::uint8_t> resulting_buffer;
resulting_workbook.save(resulting_buffer);
resulting_workbook.save("a.xlsx");
return xml_helper::xlsx_archives_match(original_buffer, resulting_buffer);
}

View File

@ -249,7 +249,7 @@ public:
xlnt::workbook wb;
xlnt::style s = wb.create_style("s");
wb.get_active_sheet().get_cell("B2").set_value("B2");
wb.get_active_sheet().get_cell("B2").set_style(s);
wb.get_active_sheet().get_cell("B2").style(s);
TS_ASSERT(wb.get_active_sheet().get_cell("B2").has_style());
wb.clear_styles();
TS_ASSERT(!wb.get_active_sheet().get_cell("B2").has_style());
@ -257,7 +257,7 @@ public:
xlnt::font font;
font.size(41);
format.font(font, true);
wb.get_active_sheet().get_cell("B2").set_format(format);
wb.get_active_sheet().get_cell("B2").format(format);
TS_ASSERT(wb.get_active_sheet().get_cell("B2").has_format());
wb.clear_formats();
TS_ASSERT(!wb.get_active_sheet().get_cell("B2").has_format());
@ -280,7 +280,7 @@ public:
TS_ASSERT(wb.has_theme());
wb.create_style("style1");
wb.get_style("style1");
wb_const.get_style("style1");
wb.style("style1");
wb_const.style("style1");
}
};

View File

@ -57,6 +57,48 @@
#include <xlnt/worksheet/range.hpp>
#include <xlnt/worksheet/worksheet.hpp>
namespace {
#ifdef WIN32
std::wstring utf8_to_utf16(const std::string &utf8_string)
{
std::wstring_convert<std::codecvt_utf8<wchar_t> convert;
return convert.from_bytes(utf8_string);
}
void open_stream(std::ifstream &stream, const std::wstring &path)
{
stream.open(path, std::ios::binary);
}
void open_stream(std::ofstream &stream, const std::wstring &path)
{
stream.open(path, std::ios::binary);
}
void open_stream(std::ifstream &stream, const std::string &path)
{
open_stream(stream, utf8_to_utf16(path));
}
void open_stream(std::ofstream &stream, const std::string &path)
{
stream.open(path, utf8_to_utf16(path));
}
#else
void open_stream(std::ifstream &stream, const std::string &path)
{
stream.open(path, std::ios::binary);
}
void open_stream(std::ofstream &stream, const std::string &path)
{
stream.open(path, std::ios::binary);
}
#endif
} // namespace
namespace xlnt {
workbook workbook::minimal()
@ -145,12 +187,6 @@ workbook workbook::empty_excel()
ws.d_->has_format_properties_ = true;
ws.d_->has_view_ = true;
wb.d_->stylesheet_.fills.push_back(pattern_fill().type(pattern_fill_type::none));
wb.d_->stylesheet_.fills.push_back(pattern_fill().type(pattern_fill_type::gray125));
auto default_font = font().name("Calibri").size(12).scheme("minor").family(2).color(theme_color(1));
wb.d_->stylesheet_.fonts.push_back(default_font);
auto default_border = border().side(border_side::bottom, border::border_property())
.side(border_side::top, border::border_property())
.side(border_side::start, border::border_property())
@ -158,14 +194,31 @@ workbook workbook::empty_excel()
.side(border_side::diagonal, border::border_property());
wb.d_->stylesheet_.borders.push_back(default_border);
auto &normal_style = wb.create_style("Normal").builtin_id(0);
normal_style.font(default_font, false);
normal_style.border(default_border, false);
auto default_fill = fill(pattern_fill().type(pattern_fill_type::none));
wb.d_->stylesheet_.fills.push_back(default_fill);
auto gray125_fill = pattern_fill().type(pattern_fill_type::gray125);
wb.d_->stylesheet_.fills.push_back(gray125_fill);
auto &default_format = wb.create_format();
default_format.font(default_font, false);
default_format.border(default_border, false);
default_format.style("Normal");
auto default_font = font()
.name("Calibri")
.size(12)
.scheme("minor")
.family(2)
.color(theme_color(1));
wb.d_->stylesheet_.fonts.push_back(default_font);
wb.create_style("Normal").builtin_id(0)
.border(default_border, false)
.fill(default_fill, false)
.font(default_font, false)
.number_format(xlnt::number_format::general(), false);
wb.create_format()
.border(default_border, false)
.fill(default_fill, false)
.font(default_font, false)
.number_format(xlnt::number_format::general(), false)
.style("Normal");
wb.set_theme(theme());
@ -262,59 +315,59 @@ workbook workbook::empty_libre_office()
.hidden(false);
wb.d_->stylesheet_.protections.push_back(default_protection);
auto &normal_style = wb.create_style("Normal").builtin_id(0).custom(false);
normal_style.alignment(default_alignment, false);
normal_style.border(default_border, true);
normal_style.fill(default_fill, true);
normal_style.font(default_font, true);
normal_style.number_format(default_number_format, false);
normal_style.protection(default_protection, false);
wb.create_style("Normal").builtin_id(0).custom(false)
.alignment(default_alignment, false)
.border(default_border, true)
.fill(default_fill, true)
.font(default_font, true)
.number_format(default_number_format, false)
.protection(default_protection, false);
auto &comma_style = wb.create_style("Comma").builtin_id(3).custom(false);
comma_style.alignment(default_alignment, false);
comma_style.border(default_border, true);
comma_style.fill(default_fill, true);
comma_style.font(second_font, true);
comma_style.number_format(number_format::from_builtin_id(43), false);
comma_style.protection(default_protection, false);
wb.create_style("Comma").builtin_id(3).custom(false)
.alignment(default_alignment, false)
.border(default_border, true)
.fill(default_fill, true)
.font(second_font, true)
.number_format(number_format::from_builtin_id(43), false)
.protection(default_protection, false);
auto &comma0_style = wb.create_style("Comma [0]").builtin_id(6).custom(false);
comma0_style.alignment(default_alignment, false);
comma0_style.border(default_border, true);
comma0_style.fill(default_fill, true);
comma0_style.font(second_font, true);
comma0_style.number_format(number_format::from_builtin_id(41), false);
comma0_style.protection(default_protection, false);
wb.create_style("Comma [0]").builtin_id(6).custom(false)
.alignment(default_alignment, false)
.border(default_border, true)
.fill(default_fill, true)
.font(second_font, true)
.number_format(number_format::from_builtin_id(41), false)
.protection(default_protection, false);
auto &currency_style = wb.create_style("Currency").builtin_id(4).custom(false);
currency_style.alignment(default_alignment, false);
currency_style.border(default_border, true);
currency_style.fill(default_fill, true);
currency_style.font(second_font, true);
currency_style.number_format(number_format::from_builtin_id(44), false);
currency_style.protection(default_protection, false);
wb.create_style("Currency").builtin_id(4).custom(false)
.alignment(default_alignment, false)
.border(default_border, true)
.fill(default_fill, true)
.font(second_font, true)
.number_format(number_format::from_builtin_id(44), false)
.protection(default_protection, false);
auto &currency0_style = wb.create_style("Currency [0]").builtin_id(7).custom(false);
currency0_style.alignment(default_alignment, false);
currency0_style.border(default_border, true);
currency0_style.fill(default_fill, true);
currency0_style.font(second_font, true);
currency0_style.number_format(number_format::from_builtin_id(42), false);
currency0_style.protection(default_protection, false);
wb.create_style("Currency [0]").builtin_id(7).custom(false)
.alignment(default_alignment, false)
.border(default_border, true)
.fill(default_fill, true)
.font(second_font, true)
.number_format(number_format::from_builtin_id(42), false)
.protection(default_protection, false);
auto &percent_style = wb.create_style("Percent").builtin_id(5).custom(false);
percent_style.alignment(default_alignment, false);
percent_style.border(default_border, true);
percent_style.fill(default_fill, false);
percent_style.font(second_font, true);
percent_style.number_format(number_format::percentage(), false);
percent_style.protection(default_protection, false);
wb.create_style("Percent").builtin_id(5).custom(false)
.alignment(default_alignment, false)
.border(default_border, true)
.fill(default_fill, false)
.font(second_font, true)
.number_format(number_format::percentage(), false)
.protection(default_protection, false);
auto &format = wb.create_format();
format.number_format(default_number_format, true);
format.alignment(default_alignment, true);
format.protection(default_protection, true);
format.style("Normal");
wb.create_format()
.number_format(default_number_format, true)
.alignment(default_alignment, true)
.protection(default_protection, true)
.style("Normal");
wb.d_->has_file_version_ = true;
wb.d_->file_version_.app_name = "Calc";
@ -702,7 +755,8 @@ void workbook::load(const std::string &filename)
void workbook::load(const path &filename)
{
std::ifstream file_stream(filename.string(), std::ios::binary);
std::ifstream file_stream;
open_stream(file_stream, filename.string());
load(file_stream);
}
@ -713,7 +767,8 @@ void workbook::load(const std::string &filename, const std::string &password)
void workbook::load(const path &filename, const std::string &password)
{
std::ifstream file_stream(filename.string(), std::iostream::binary);
std::ifstream file_stream;
open_stream(file_stream, filename.string());
return load(file_stream, password);
}
@ -745,7 +800,8 @@ void workbook::save(const std::string &filename) const
void workbook::save(const path &filename) const
{
std::ofstream file_stream(filename.string(), std::ios::binary);
std::ofstream file_stream;
open_stream(file_stream, filename.string());
save(file_stream);
}
@ -758,13 +814,29 @@ void workbook::save(std::ostream &stream) const
#ifdef WIN32
void workbook::save(const std::wstring &filename)
{
std::ofstream file_stream(filename, std::ios::binary);
std::ofstream file_stream;
open_stream(file_stream, filename);
save(file_stream);
}
void workbook::save(const std::wstring &filename, const std::string &password)
{
std::ofstream file_stream;
open_stream(file_stream, filename);
save(file_stream, password);
}
void workbook::load(const std::wstring &filename)
{
std::ifstream file_stream(filename, std::ios::binary);
std::ifstream file_stream;
open_stream(file_stream, filename);
load(file_stream);
}
void workbook::load(const std::wstring &filename, const std::string &password)
{
std::ifstream file_stream;
open_stream(file_stream, filename);
load(file_stream);
}
#endif
@ -1002,7 +1074,7 @@ std::vector<named_range> workbook::get_named_ranges() const
return named_ranges;
}
format &workbook::create_format()
format workbook::create_format()
{
register_stylesheet_in_manifest();
return d_->stylesheet_.create_format();
@ -1015,13 +1087,11 @@ bool workbook::has_style(const std::string &name) const
void workbook::clear_styles()
{
d_->stylesheet_.styles.clear();
apply_to_cells([](cell c) { c.clear_style(); });
}
void workbook::clear_formats()
{
d_->stylesheet_.formats.clear();
apply_to_cells([](cell c) { c.clear_format(); });
}
@ -1029,22 +1099,25 @@ void workbook::apply_to_cells(std::function<void(cell)> f)
{
for (auto ws : *this)
{
for (auto r : ws.iter_cells(true))
for (auto row = ws.get_lowest_row(); row <= ws.get_highest_row(); ++row)
{
for (auto c : r)
for (auto column = ws.get_lowest_column(); column <= ws.get_highest_column(); ++column)
{
f.operator()(c);
if (ws.has_cell(cell_reference(column, row)))
{
f.operator()(ws.get_cell(cell_reference(column, row)));
}
}
}
}
}
format &workbook::get_format(std::size_t format_index)
format workbook::get_format(std::size_t format_index)
{
return d_->stylesheet_.get_format(format_index);
}
const format &workbook::get_format(std::size_t format_index) const
const format workbook::get_format(std::size_t format_index) const
{
return d_->stylesheet_.get_format(format_index);
}
@ -1113,19 +1186,19 @@ const std::vector<std::uint8_t> &workbook::get_thumbnail() const
return d_->thumbnail_;
}
style &workbook::create_style(const std::string &name)
style workbook::create_style(const std::string &name)
{
return d_->stylesheet_.create_style().name(name);
return d_->stylesheet_.create_style(name);
}
style &workbook::get_style(const std::string &name)
style workbook::style(const std::string &name)
{
return d_->stylesheet_.get_style(name);
return d_->stylesheet_.style(name);
}
const style &workbook::get_style(const std::string &name) const
const style workbook::style(const std::string &name) const
{
return d_->stylesheet_.get_style(name);
return d_->stylesheet_.style(name);
}
std::string workbook::get_application() const

2
third-party/botan vendored

@ -1 +1 @@
Subproject commit dad94a550613733d8c75b2fbd8db47048dfdaf13
Subproject commit 73c2605f50e6192bf6cb560c51d32bc53b4c5597