mirror of
https://github.com/tfussell/xlnt.git
synced 2024-03-22 13:11:17 +08:00
clang-format all source files, fix broken test helpers--lots of cleanup necessary as a result [ci skip]
This commit is contained in:
parent
6c32563d18
commit
c8f2ca204b
|
@ -27,7 +27,7 @@ BraceWrapping:
|
||||||
BeforeElse: true
|
BeforeElse: true
|
||||||
BreakBeforeBinaryOperators: NonAssignment
|
BreakBeforeBinaryOperators: NonAssignment
|
||||||
BreakBeforeBraces: Custom
|
BreakBeforeBraces: Custom
|
||||||
ColumnLimit: 120
|
ColumnLimit: 0
|
||||||
ConstructorInitializerAllOnOneLineOrOnePerLine: true
|
ConstructorInitializerAllOnOneLineOrOnePerLine: true
|
||||||
Cpp11BracedListStyle: true
|
Cpp11BracedListStyle: true
|
||||||
DerivePointerAlignment: false
|
DerivePointerAlignment: false
|
||||||
|
|
|
@ -469,6 +469,9 @@ public:
|
||||||
/// </summary>
|
/// </summary>
|
||||||
void comment(const class comment &new_comment);
|
void comment(const class comment &new_comment);
|
||||||
|
|
||||||
|
double width() const;
|
||||||
|
double height() const;
|
||||||
|
|
||||||
// operators
|
// operators
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
@ -37,6 +37,7 @@ class fill;
|
||||||
class font;
|
class font;
|
||||||
class number_format;
|
class number_format;
|
||||||
class protection;
|
class protection;
|
||||||
|
class style;
|
||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
|
||||||
|
@ -208,7 +209,7 @@ public:
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
format style(const xlnt::style &new_style);
|
format style(const class style &new_style);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
///
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include <xlnt/xlnt_config.hpp>
|
#include <xlnt/xlnt_config.hpp>
|
||||||
|
#include <xlnt/utils/optional.hpp>
|
||||||
|
|
||||||
namespace xlnt {
|
namespace xlnt {
|
||||||
|
|
||||||
|
|
37
include/xlnt/workbook/calculation_properties.hpp
Normal file
37
include/xlnt/workbook/calculation_properties.hpp
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
// Copyright (c) 2016 Thomas Fussell
|
||||||
|
//
|
||||||
|
// 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>
|
||||||
|
|
||||||
|
namespace xlnt {
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
class XLNT_API calculation_properties
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace xlnt
|
|
@ -41,6 +41,7 @@ enum class relationship_type;
|
||||||
|
|
||||||
class alignment;
|
class alignment;
|
||||||
class border;
|
class border;
|
||||||
|
class calculation_properties;
|
||||||
class cell;
|
class cell;
|
||||||
class cell_style;
|
class cell_style;
|
||||||
class color;
|
class color;
|
||||||
|
@ -633,14 +634,31 @@ public:
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
void thumbnail(
|
void thumbnail(const std::vector<std::uint8_t> &thumbnail,
|
||||||
const std::vector<std::uint8_t> &thumbnail, const std::string &extension, const std::string &content_type);
|
const std::string &extension, const std::string &content_type);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
const std::vector<std::uint8_t> &thumbnail() const;
|
const std::vector<std::uint8_t> &thumbnail() const;
|
||||||
|
|
||||||
|
// calculation properties
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
bool has_calculation_properties() const;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
class calculation_properties calculation_properties() const;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
void calculation_properties(const class calculation_properties &props);
|
||||||
|
|
||||||
// operators
|
// operators
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
@ -73,96 +73,99 @@ class XLNT_API worksheet
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
/// Iterate over a non-const worksheet with an iterator of this type.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
using iterator = range_iterator;
|
using iterator = range_iterator;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
/// Iterate over a non-const worksheet with an iterator of this type.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
using const_iterator = const_range_iterator;
|
using const_iterator = const_range_iterator;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
/// Iterate in reverse over a non-const worksheet with an iterator of this type.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
using reverse_iterator = std::reverse_iterator<iterator>;
|
using reverse_iterator = std::reverse_iterator<iterator>;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
/// Iterate in reverse order over a const worksheet with an iterator of this type.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
|
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
/// Construct a null worksheet. No methods should be called on such a worksheet.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
worksheet();
|
worksheet();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
/// Copy constructor. This worksheet will point to the same memory as rhs's worksheet.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
worksheet(const worksheet &rhs);
|
worksheet(const worksheet &rhs);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
/// Returns a reference to the workbook this worksheet is owned by.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
class workbook &workbook();
|
class workbook &workbook();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
/// Returns a reference to the workbook this worksheet is owned by.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
const class workbook &workbook() const;
|
const class workbook &workbook() const;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
/// Deletes data held in the worksheet that does not affect the internal data or display.
|
||||||
|
/// For example, unreference styles and empty cells will be removed.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
void garbage_collect();
|
void garbage_collect();
|
||||||
|
|
||||||
// identification
|
// identification
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
/// Returns the unique numeric identifier of this worksheet. This will sometimes but not necessarily
|
||||||
|
/// be the index of the worksheet in the workbook.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
std::size_t id() const;
|
std::size_t id() const;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
/// Set the unique numeric identifier. The id defaults to the lowest unused id in the workbook
|
||||||
|
/// so this should not be called without a good reason.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
void id(std::size_t id);
|
void id(std::size_t id);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
/// Returns the title of this sheet.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
std::string title() const;
|
std::string title() const;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
/// Sets the title of this sheet.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
void title(const std::string &title);
|
void title(const std::string &title);
|
||||||
|
|
||||||
// freeze panes
|
// freeze panes
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
/// Returns the top left corner of the region above and to the left of which panes are frozen.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
cell_reference frozen_panes() const;
|
cell_reference frozen_panes() const;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
/// Freeze panes above and to the left of top_left_cell.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
void freeze_panes(cell top_left_cell);
|
void freeze_panes(cell top_left_cell);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
/// Freeze panes above and to the left of top_left_coordinate.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
void freeze_panes(const cell_reference &top_left_coordinate);
|
void freeze_panes(const cell_reference &top_left_coordinate);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
/// Remove frozen panes. The data in those panes will be unaffected--this affects only the view.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
void unfreeze_panes();
|
void unfreeze_panes();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
/// Returns true if this sheet has a frozen row, frozen column, or both.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
bool has_frozen_panes() const;
|
bool has_frozen_panes() const;
|
||||||
|
|
||||||
|
@ -260,6 +263,12 @@ public:
|
||||||
/// </summary>
|
/// </summary>
|
||||||
void add_column_properties(column_t column, const class column_properties &props);
|
void add_column_properties(column_t column, const class column_properties &props);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Calculate the width of the given column. This will be the default column width if
|
||||||
|
/// a custom width is not set on this column's column_properties.
|
||||||
|
/// </summary>
|
||||||
|
double column_width(column_t column) const;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -280,6 +289,12 @@ public:
|
||||||
/// </summary>
|
/// </summary>
|
||||||
void add_row_properties(row_t row, const class row_properties &props);
|
void add_row_properties(row_t row, const class row_properties &props);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Calculate the height of the given row. This will be the default row height if
|
||||||
|
/// a custom height is not set on this row's row_properties.
|
||||||
|
/// </summary>
|
||||||
|
double row_height(row_t row) const;
|
||||||
|
|
||||||
// positioning
|
// positioning
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -686,10 +701,33 @@ public:
|
||||||
/// </summary>
|
/// </summary>
|
||||||
void add_view(const sheet_view &new_view);
|
void add_view(const sheet_view &new_view);
|
||||||
|
|
||||||
std::vector<row_t> &row_breaks();
|
// page breaks
|
||||||
const std::vector<row_t> &row_breaks() const;
|
|
||||||
std::vector<column_t> &column_breaks();
|
/// <summary>
|
||||||
const std::vector<column_t> &column_breaks() const;
|
/// Remove all manual column and row page breaks (represented as dashed
|
||||||
|
/// blue lines in the page view in Excel).
|
||||||
|
/// </summary>
|
||||||
|
void clear_page_breaks();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns vector where each element represents a row which will break a page below it.
|
||||||
|
/// </summary>
|
||||||
|
const std::vector<row_t> &page_break_rows() const;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Add a page break at the given row.
|
||||||
|
/// </summary>
|
||||||
|
void page_break_at_row(row_t row);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns vector where each element represents a column which will break a page to the right.
|
||||||
|
/// </summary>
|
||||||
|
const std::vector<column_t> &page_break_columns() const;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Add a page break at the given column.
|
||||||
|
/// </summary>
|
||||||
|
void page_break_at_column(column_t column);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class cell;
|
friend class cell;
|
||||||
|
|
|
@ -57,11 +57,12 @@ namespace {
|
||||||
|
|
||||||
std::pair<bool, long double> cast_numeric(const std::string &s)
|
std::pair<bool, long double> cast_numeric(const std::string &s)
|
||||||
{
|
{
|
||||||
const char *str = s.c_str();
|
auto str_end = static_cast<char *>(nullptr);
|
||||||
char *str_end = nullptr;
|
auto result = std::strtold(s.c_str(), &str_end);
|
||||||
auto result = std::strtold(str, &str_end);
|
|
||||||
if (str_end != str + s.size()) return {false, 0};
|
return (str_end != s.c_str() + s.size())
|
||||||
return {true, result};
|
? std::make_pair(false, 0.0L)
|
||||||
|
: std::make_pair(true, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<bool, long double> cast_percentage(const std::string &s)
|
std::pair<bool, long double> cast_percentage(const std::string &s)
|
||||||
|
@ -149,16 +150,14 @@ namespace xlnt {
|
||||||
|
|
||||||
const std::unordered_map<std::string, int> &cell::error_codes()
|
const std::unordered_map<std::string, int> &cell::error_codes()
|
||||||
{
|
{
|
||||||
static const auto *codes = new std::unordered_map<std::string, int>
|
static const auto *codes = new std::unordered_map<std::string, int>{
|
||||||
{
|
|
||||||
{"#NULL!", 0},
|
{"#NULL!", 0},
|
||||||
{"#DIV/0!", 1},
|
{"#DIV/0!", 1},
|
||||||
{"#VALUE!", 2},
|
{"#VALUE!", 2},
|
||||||
{"#REF!", 3},
|
{"#REF!", 3},
|
||||||
{"#NAME?", 4},
|
{"#NAME?", 4},
|
||||||
{"#NUM!", 5},
|
{"#NUM!", 5},
|
||||||
{"#N/A!", 6}
|
{"#N/A!", 6}};
|
||||||
};
|
|
||||||
|
|
||||||
return *codes;
|
return *codes;
|
||||||
}
|
}
|
||||||
|
@ -188,7 +187,8 @@ std::string cell::check_string(const std::string &to_check)
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
cell::cell(detail::cell_impl *d) : d_(d)
|
cell::cell(detail::cell_impl *d)
|
||||||
|
: d_(d)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -546,56 +546,23 @@ const workbook &cell::workbook() const
|
||||||
return worksheet().workbook();
|
return worksheet().workbook();
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: this shares a lot of code with worksheet::point_pos, try to reduce repetion
|
|
||||||
std::pair<int, int> cell::anchor() const
|
std::pair<int, int> cell::anchor() const
|
||||||
{
|
{
|
||||||
static const auto DefaultColumnWidth = 51.85L;
|
int left = 0;
|
||||||
static const auto DefaultRowHeight = 15.0L;
|
|
||||||
|
|
||||||
auto points_to_pixels = [](
|
for (column_t column_index = 1; column_index <= d_->column_ - 1; column_index++)
|
||||||
long double value, long double dpi) { return static_cast<int>(std::ceil(value * dpi / 72)); };
|
|
||||||
|
|
||||||
auto left_columns = d_->column_ - 1;
|
|
||||||
int left_anchor = 0;
|
|
||||||
auto default_width = points_to_pixels(DefaultColumnWidth, 96.0L);
|
|
||||||
|
|
||||||
for (column_t column_index = 1; column_index <= left_columns; column_index++)
|
|
||||||
{
|
{
|
||||||
if (worksheet().has_column_properties(column_index))
|
left += worksheet().cell(column_index, row()).width();
|
||||||
{
|
|
||||||
auto cdw = worksheet().column_properties(column_index).width;
|
|
||||||
|
|
||||||
if (cdw > 0)
|
|
||||||
{
|
|
||||||
left_anchor += points_to_pixels(cdw, 96.0L);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
left_anchor += default_width;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto top_rows = d_->row_ - 1;
|
int top = 0;
|
||||||
int top_anchor = 0;
|
|
||||||
auto default_height = points_to_pixels(DefaultRowHeight, 96.0L);
|
|
||||||
|
|
||||||
for (row_t row_index = 1; row_index <= top_rows; row_index++)
|
for (row_t row_index = 1; row_index <= d_->row_ - 1; row_index++)
|
||||||
{
|
{
|
||||||
if (worksheet().has_row_properties(row_index))
|
top += worksheet().cell(column(), row_index).height();
|
||||||
{
|
|
||||||
auto rdh = worksheet().row_properties(row_index).height;
|
|
||||||
|
|
||||||
if (rdh > 0)
|
|
||||||
{
|
|
||||||
top_anchor += points_to_pixels(rdh, 96.0L);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
top_anchor += default_height;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return {left_anchor, top_anchor};
|
return {left, top};
|
||||||
}
|
}
|
||||||
|
|
||||||
cell::type cell::data_type() const
|
cell::type cell::data_type() const
|
||||||
|
@ -1024,32 +991,13 @@ void cell::comment(const std::string &text, const class font &comment_font, cons
|
||||||
comment(xlnt::comment(rich_comment_text, author));
|
comment(xlnt::comment(rich_comment_text, author));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void cell::comment(const class comment &new_comment)
|
void cell::comment(const class comment &new_comment)
|
||||||
{
|
{
|
||||||
d_->comment_.set(new_comment);
|
d_->comment_.set(new_comment);
|
||||||
|
|
||||||
// offset comment 5 pixels down and 5 pixels right of the top right corner of the cell
|
// offset comment 5 pixels down and 5 pixels right of the top right corner of the cell
|
||||||
auto cell_position = anchor();
|
auto cell_position = anchor();
|
||||||
|
cell_position.first += width() + 5;
|
||||||
// todo: make this cell_position.first += width() instead
|
|
||||||
if (worksheet().has_column_properties(column()))
|
|
||||||
{
|
|
||||||
cell_position.first += static_cast<int>(worksheet().column_properties(column()).width);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
static const auto DefaultColumnWidth = 51.85L;
|
|
||||||
|
|
||||||
auto points_to_pixels = [](long double value, long double dpi)
|
|
||||||
{
|
|
||||||
return static_cast<int>(std::ceil(value * dpi / 72));
|
|
||||||
};
|
|
||||||
|
|
||||||
cell_position.first += points_to_pixels(DefaultColumnWidth, 96.0L);
|
|
||||||
}
|
|
||||||
|
|
||||||
cell_position.first += 5;
|
|
||||||
cell_position.second += 5;
|
cell_position.second += 5;
|
||||||
|
|
||||||
d_->comment_.get().position(cell_position.first, cell_position.second);
|
d_->comment_.get().position(cell_position.first, cell_position.second);
|
||||||
|
@ -1058,4 +1006,14 @@ void cell::comment(const class comment &new_comment)
|
||||||
worksheet().register_comments_in_manifest();
|
worksheet().register_comments_in_manifest();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
double cell::width() const
|
||||||
|
{
|
||||||
|
return worksheet().column_width(column());
|
||||||
|
}
|
||||||
|
|
||||||
|
double cell::height() const
|
||||||
|
{
|
||||||
|
return worksheet().row_height(row());
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace xlnt
|
} // namespace xlnt
|
||||||
|
|
|
@ -41,18 +41,19 @@ cell_reference &cell_reference::make_absolute(bool absolute_column, bool absolut
|
||||||
{
|
{
|
||||||
column_absolute(absolute_column);
|
column_absolute(absolute_column);
|
||||||
row_absolute(absolute_row);
|
row_absolute(absolute_row);
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
cell_reference::cell_reference() : cell_reference(1, 1)
|
cell_reference::cell_reference()
|
||||||
|
: cell_reference(1, 1)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
cell_reference::cell_reference(const std::string &string)
|
cell_reference::cell_reference(const std::string &string)
|
||||||
{
|
{
|
||||||
auto split = split_reference(string, absolute_column_, absolute_row_);
|
auto split = split_reference(string, absolute_column_, absolute_row_);
|
||||||
|
|
||||||
column(split.first);
|
column(split.first);
|
||||||
row(split.second);
|
row(split.second);
|
||||||
}
|
}
|
||||||
|
@ -65,16 +66,13 @@ cell_reference::cell_reference(const char *reference_string)
|
||||||
cell_reference::cell_reference(column_t column_index, row_t row)
|
cell_reference::cell_reference(column_t column_index, row_t row)
|
||||||
: column_(column_index), row_(row), absolute_row_(false), absolute_column_(false)
|
: column_(column_index), row_(row), absolute_row_(false), absolute_column_(false)
|
||||||
{
|
{
|
||||||
if (row_ == 0
|
if (row_ == 0 || column_ == 0 || !(row_ <= constants::max_row()) || !(column_ <= constants::max_column()))
|
||||||
|| column_ == 0
|
|
||||||
|| !(row_ <= constants::max_row())
|
|
||||||
|| !(column_ <= constants::max_column()))
|
|
||||||
{
|
{
|
||||||
throw invalid_cell_reference(column_, row_);
|
throw invalid_cell_reference(column_, row_);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
range_reference cell_reference::operator, (const xlnt::cell_reference &other) const
|
range_reference cell_reference::operator,(const xlnt::cell_reference &other) const
|
||||||
{
|
{
|
||||||
return range_reference(*this, other);
|
return range_reference(*this, other);
|
||||||
}
|
}
|
||||||
|
@ -82,19 +80,19 @@ range_reference cell_reference::operator, (const xlnt::cell_reference &other) co
|
||||||
std::string cell_reference::to_string() const
|
std::string cell_reference::to_string() const
|
||||||
{
|
{
|
||||||
std::string string_representation;
|
std::string string_representation;
|
||||||
|
|
||||||
if (absolute_column_)
|
if (absolute_column_)
|
||||||
{
|
{
|
||||||
string_representation.append("$");
|
string_representation.append("$");
|
||||||
}
|
}
|
||||||
|
|
||||||
string_representation.append(column_.column_string());
|
string_representation.append(column_.column_string());
|
||||||
|
|
||||||
if (absolute_row_)
|
if (absolute_row_)
|
||||||
{
|
{
|
||||||
string_representation.append("$");
|
string_representation.append("$");
|
||||||
}
|
}
|
||||||
|
|
||||||
string_representation.append(std::to_string(row_));
|
string_representation.append(std::to_string(row_));
|
||||||
|
|
||||||
return string_representation;
|
return string_representation;
|
||||||
|
@ -111,8 +109,8 @@ std::pair<std::string, row_t> cell_reference::split_reference(const std::string
|
||||||
return split_reference(reference_string, ignore1, ignore2);
|
return split_reference(reference_string, ignore1, ignore2);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<std::string, row_t> cell_reference::split_reference(const std::string &reference_string,
|
std::pair<std::string, row_t> cell_reference::split_reference(
|
||||||
bool &absolute_column, bool &absolute_row)
|
const std::string &reference_string, bool &absolute_column, bool &absolute_row)
|
||||||
{
|
{
|
||||||
absolute_column = false;
|
absolute_column = false;
|
||||||
absolute_row = false;
|
absolute_row = false;
|
||||||
|
@ -183,7 +181,7 @@ std::pair<std::string, row_t> cell_reference::split_reference(const std::string
|
||||||
row_string = row_string.substr(1);
|
row_string = row_string.substr(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
return { column_string, std::stoi(row_string) };
|
return {column_string, std::stoi(row_string)};
|
||||||
}
|
}
|
||||||
|
|
||||||
bool cell_reference::column_absolute() const
|
bool cell_reference::column_absolute() const
|
||||||
|
@ -263,19 +261,16 @@ bool cell_reference::operator!=(const char *reference_string) const
|
||||||
|
|
||||||
cell_reference cell_reference::make_offset(int column_offset, int row_offset) const
|
cell_reference cell_reference::make_offset(int column_offset, int row_offset) const
|
||||||
{
|
{
|
||||||
//TODO: check for overflow/underflow
|
// TODO: check for overflow/underflow
|
||||||
auto relative_column = static_cast<column_t::index_t>(static_cast<int>(column_.index) + column_offset);
|
auto relative_column = static_cast<column_t::index_t>(static_cast<int>(column_.index) + column_offset);
|
||||||
auto relative_row = static_cast<row_t>(static_cast<int>(row_) + row_offset);
|
auto relative_row = static_cast<row_t>(static_cast<int>(row_) + row_offset);
|
||||||
return cell_reference(relative_column, relative_row);
|
return cell_reference(relative_column, relative_row);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool cell_reference::operator==(const cell_reference &comparand) const
|
bool cell_reference::operator==(const cell_reference &comparand) const
|
||||||
{
|
{
|
||||||
return comparand.column_ == column_ &&
|
return comparand.column_ == column_ && comparand.row_ == row_ && absolute_column_ == comparand.absolute_column_
|
||||||
comparand.row_ == row_ &&
|
&& absolute_row_ == comparand.absolute_row_;
|
||||||
absolute_column_ == comparand.absolute_column_ &&
|
|
||||||
absolute_row_ == comparand.absolute_row_;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace xlnt
|
} // namespace xlnt
|
||||||
|
|
|
@ -25,19 +25,18 @@
|
||||||
|
|
||||||
namespace xlnt {
|
namespace xlnt {
|
||||||
|
|
||||||
comment::comment() : comment("", "")
|
comment::comment()
|
||||||
|
: comment("", "")
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
comment::comment(const rich_text &text, const std::string &author)
|
comment::comment(const rich_text &text, const std::string &author)
|
||||||
: text_(text),
|
: text_(text), author_(author)
|
||||||
author_(author)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
comment::comment(const std::string &text, const std::string &author)
|
comment::comment(const std::string &text, const std::string &author)
|
||||||
: text_(),
|
: text_(), author_(author)
|
||||||
author_(author)
|
|
||||||
{
|
{
|
||||||
text_.plain_text(text);
|
text_.plain_text(text);
|
||||||
}
|
}
|
||||||
|
@ -88,17 +87,17 @@ int comment::left() const
|
||||||
{
|
{
|
||||||
return left_;
|
return left_;
|
||||||
}
|
}
|
||||||
|
|
||||||
int comment::top() const
|
int comment::top() const
|
||||||
{
|
{
|
||||||
return top_;
|
return top_;
|
||||||
}
|
}
|
||||||
|
|
||||||
int comment::width() const
|
int comment::width() const
|
||||||
{
|
{
|
||||||
return width_;
|
return width_;
|
||||||
}
|
}
|
||||||
|
|
||||||
int comment::height() const
|
int comment::height() const
|
||||||
{
|
{
|
||||||
return height_;
|
return height_;
|
||||||
|
|
|
@ -23,9 +23,9 @@
|
||||||
// @author: see AUTHORS file
|
// @author: see AUTHORS file
|
||||||
#include <locale>
|
#include <locale>
|
||||||
|
|
||||||
#include <detail/constants.hpp>
|
|
||||||
#include <xlnt/cell/index_types.hpp>
|
#include <xlnt/cell/index_types.hpp>
|
||||||
#include <xlnt/utils/exceptions.hpp>
|
#include <xlnt/utils/exceptions.hpp>
|
||||||
|
#include <detail/constants.hpp>
|
||||||
|
|
||||||
namespace xlnt {
|
namespace xlnt {
|
||||||
|
|
||||||
|
@ -89,98 +89,252 @@ std::string column_t::column_string_from_index(column_t::index_t column_index)
|
||||||
return column_letter;
|
return column_letter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
column_t::column_t()
|
||||||
|
: index(1)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
column_t::column_t() : index(1) {}
|
column_t::column_t(index_t column_index)
|
||||||
|
: index(column_index)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
column_t::column_t(index_t column_index) : index(column_index) {}
|
column_t::column_t(const std::string &column_string)
|
||||||
|
: index(column_index_from_string(column_string))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
column_t::column_t(const std::string &column_string) : index(column_index_from_string(column_string)) {}
|
column_t::column_t(const char *column_string)
|
||||||
|
: column_t(std::string(column_string))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
column_t::column_t(const char *column_string) : column_t(std::string(column_string)) {}
|
column_t::column_t(const column_t &other)
|
||||||
|
: column_t(other.index)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
column_t::column_t(const column_t &other) : column_t(other.index) {}
|
column_t::column_t(column_t &&other)
|
||||||
|
{
|
||||||
|
swap(*this, other);
|
||||||
|
}
|
||||||
|
|
||||||
column_t::column_t(column_t &&other) { swap(*this, other); }
|
std::string column_t::column_string() const
|
||||||
|
{
|
||||||
|
return column_string_from_index(index);
|
||||||
|
}
|
||||||
|
|
||||||
std::string column_t::column_string() const { return column_string_from_index(index); }
|
column_t &column_t::operator=(column_t rhs)
|
||||||
|
{
|
||||||
|
swap(*this, rhs);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
column_t &column_t::operator=(column_t rhs) { swap(*this, rhs); return *this; }
|
column_t &column_t::operator=(const std::string &rhs)
|
||||||
|
{
|
||||||
|
return *this = column_t(rhs);
|
||||||
|
}
|
||||||
|
|
||||||
column_t &column_t::operator=(const std::string &rhs) { return *this = column_t(rhs); }
|
column_t &column_t::operator=(const char *rhs)
|
||||||
|
{
|
||||||
|
return *this = column_t(rhs);
|
||||||
|
}
|
||||||
|
|
||||||
column_t &column_t::operator=(const char *rhs) { return *this = column_t(rhs); }
|
bool column_t::operator==(const column_t &other) const
|
||||||
|
{
|
||||||
|
return index == other.index;
|
||||||
|
}
|
||||||
|
|
||||||
bool column_t::operator==(const column_t &other) const { return index == other.index; }
|
bool column_t::operator!=(const column_t &other) const
|
||||||
|
{
|
||||||
|
return !(*this == other);
|
||||||
|
}
|
||||||
|
|
||||||
bool column_t::operator!=(const column_t &other) const { return !(*this == other); }
|
bool column_t::operator==(int other) const
|
||||||
|
{
|
||||||
|
return *this == column_t(static_cast<index_t>(other));
|
||||||
|
}
|
||||||
|
|
||||||
bool column_t::operator==(int other) const { return *this == column_t(static_cast<index_t>(other)); }
|
bool column_t::operator==(index_t other) const
|
||||||
|
{
|
||||||
|
return *this == column_t(other);
|
||||||
|
}
|
||||||
|
|
||||||
bool column_t::operator==(index_t other) const { return *this == column_t(other); }
|
bool column_t::operator==(const std::string &other) const
|
||||||
|
{
|
||||||
|
return *this == column_t(other);
|
||||||
|
}
|
||||||
|
|
||||||
bool column_t::operator==(const std::string &other) const { return *this == column_t(other); }
|
bool column_t::operator==(const char *other) const
|
||||||
|
{
|
||||||
|
return *this == column_t(other);
|
||||||
|
}
|
||||||
|
|
||||||
bool column_t::operator==(const char *other) const { return *this == column_t(other); }
|
bool column_t::operator!=(int other) const
|
||||||
|
{
|
||||||
|
return !(*this == other);
|
||||||
|
}
|
||||||
|
|
||||||
bool column_t::operator!=(int other) const { return !(*this == other); }
|
bool column_t::operator!=(index_t other) const
|
||||||
|
{
|
||||||
|
return !(*this == other);
|
||||||
|
}
|
||||||
|
|
||||||
bool column_t::operator!=(index_t other) const { return !(*this == other); }
|
bool column_t::operator!=(const std::string &other) const
|
||||||
|
{
|
||||||
|
return !(*this == other);
|
||||||
|
}
|
||||||
|
|
||||||
bool column_t::operator!=(const std::string &other) const { return !(*this == other); }
|
bool column_t::operator!=(const char *other) const
|
||||||
|
{
|
||||||
|
return !(*this == other);
|
||||||
|
}
|
||||||
|
|
||||||
bool column_t::operator!=(const char *other) const { return !(*this == other); }
|
bool column_t::operator>(const column_t &other) const
|
||||||
|
{
|
||||||
|
return index > other.index;
|
||||||
|
}
|
||||||
|
|
||||||
bool column_t::operator>(const column_t &other) const { return index > other.index; }
|
bool column_t::operator>=(const column_t &other) const
|
||||||
|
{
|
||||||
|
return index >= other.index;
|
||||||
|
}
|
||||||
|
|
||||||
bool column_t::operator>=(const column_t &other) const { return index >= other.index; }
|
bool column_t::operator<(const column_t &other) const
|
||||||
|
{
|
||||||
|
return index < other.index;
|
||||||
|
}
|
||||||
|
|
||||||
bool column_t::operator<(const column_t &other) const { return index < other.index; }
|
bool column_t::operator<=(const column_t &other) const
|
||||||
|
{
|
||||||
|
return index <= other.index;
|
||||||
|
}
|
||||||
|
|
||||||
bool column_t::operator<=(const column_t &other) const { return index <= other.index; }
|
bool column_t::operator>(const column_t::index_t &other) const
|
||||||
|
{
|
||||||
|
return index > other;
|
||||||
|
}
|
||||||
|
|
||||||
bool column_t::operator>(const column_t::index_t &other) const { return index > other; }
|
bool column_t::operator>=(const column_t::index_t &other) const
|
||||||
|
{
|
||||||
|
return index >= other;
|
||||||
|
}
|
||||||
|
|
||||||
bool column_t::operator>=(const column_t::index_t &other) const { return index >= other; }
|
bool column_t::operator<(const column_t::index_t &other) const
|
||||||
|
{
|
||||||
|
return index < other;
|
||||||
|
}
|
||||||
|
|
||||||
bool column_t::operator<(const column_t::index_t &other) const { return index < other; }
|
bool column_t::operator<=(const column_t::index_t &other) const
|
||||||
|
{
|
||||||
|
return index <= other;
|
||||||
|
}
|
||||||
|
|
||||||
bool column_t::operator<=(const column_t::index_t &other) const { return index <= other; }
|
column_t &column_t::operator++()
|
||||||
|
{
|
||||||
|
index++;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
column_t &column_t::operator++() { index++; return *this; }
|
column_t &column_t::operator--()
|
||||||
|
{
|
||||||
|
index--;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
column_t &column_t::operator--() { index--; return *this; }
|
column_t column_t::operator++(int)
|
||||||
|
{
|
||||||
|
column_t copy(index);
|
||||||
|
++(*this);
|
||||||
|
return copy;
|
||||||
|
}
|
||||||
|
|
||||||
column_t column_t::operator++(int) { column_t copy(index); ++(*this); return copy; }
|
column_t column_t::operator--(int)
|
||||||
|
{
|
||||||
|
column_t copy(index);
|
||||||
|
--(*this);
|
||||||
|
return copy;
|
||||||
|
}
|
||||||
|
|
||||||
column_t column_t::operator--(int) { column_t copy(index); --(*this); return copy; }
|
column_t operator+(column_t lhs, const column_t &rhs)
|
||||||
|
{
|
||||||
|
lhs += rhs;
|
||||||
|
return lhs;
|
||||||
|
}
|
||||||
|
|
||||||
column_t operator+(column_t lhs, const column_t& rhs) { lhs += rhs; return lhs; }
|
column_t operator-(column_t lhs, const column_t &rhs)
|
||||||
|
{
|
||||||
|
lhs -= rhs;
|
||||||
|
return lhs;
|
||||||
|
}
|
||||||
|
|
||||||
column_t operator-(column_t lhs, const column_t& rhs) { lhs -= rhs; return lhs; }
|
column_t operator*(column_t lhs, const column_t &rhs)
|
||||||
|
{
|
||||||
|
lhs *= rhs;
|
||||||
|
return lhs;
|
||||||
|
}
|
||||||
|
|
||||||
column_t operator*(column_t lhs, const column_t& rhs) { lhs *= rhs; return lhs; }
|
column_t operator/(column_t lhs, const column_t &rhs)
|
||||||
|
{
|
||||||
|
lhs /= rhs;
|
||||||
|
return lhs;
|
||||||
|
}
|
||||||
|
|
||||||
column_t operator/(column_t lhs, const column_t& rhs) { lhs /= rhs; return lhs; }
|
column_t operator%(column_t lhs, const column_t &rhs)
|
||||||
|
{
|
||||||
|
lhs %= rhs;
|
||||||
|
return lhs;
|
||||||
|
}
|
||||||
|
|
||||||
column_t operator%(column_t lhs, const column_t& rhs) { lhs %= rhs; return lhs; }
|
column_t &column_t::operator+=(const column_t &rhs)
|
||||||
|
{
|
||||||
|
index += rhs.index;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
column_t &column_t::operator+=(const column_t &rhs) { index += rhs.index; return *this; }
|
column_t &column_t::operator-=(const column_t &rhs)
|
||||||
|
{
|
||||||
|
index -= rhs.index;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
column_t &column_t::operator-=(const column_t &rhs) { index -= rhs.index; return *this; }
|
column_t &column_t::operator*=(const column_t &rhs)
|
||||||
|
{
|
||||||
|
index *= rhs.index;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
column_t &column_t::operator*=(const column_t &rhs) { index *= rhs.index; return *this; }
|
column_t &column_t::operator/=(const column_t &rhs)
|
||||||
|
{
|
||||||
|
index /= rhs.index;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
column_t &column_t::operator/=(const column_t &rhs) { index /= rhs.index; return *this; }
|
column_t &column_t::operator%=(const column_t &rhs)
|
||||||
|
{
|
||||||
|
index %= rhs.index;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
column_t &column_t::operator%=(const column_t &rhs) { index %= rhs.index; return *this; }
|
bool operator>(const column_t::index_t &left, const column_t &right)
|
||||||
|
{
|
||||||
|
return column_t(left) > right;
|
||||||
|
}
|
||||||
|
|
||||||
bool operator>(const column_t::index_t &left, const column_t &right) { return column_t(left) > right; }
|
bool operator>=(const column_t::index_t &left, const column_t &right)
|
||||||
|
{
|
||||||
|
return column_t(left) >= right;
|
||||||
|
}
|
||||||
|
|
||||||
bool operator>=(const column_t::index_t &left, const column_t &right) { return column_t(left) >= right; }
|
bool operator<(const column_t::index_t &left, const column_t &right)
|
||||||
|
{
|
||||||
|
return column_t(left) < right;
|
||||||
|
}
|
||||||
|
|
||||||
bool operator<(const column_t::index_t &left, const column_t &right) { return column_t(left) < right; }
|
bool operator<=(const column_t::index_t &left, const column_t &right)
|
||||||
|
{
|
||||||
bool operator<=(const column_t::index_t &left, const column_t &right) { return column_t(left) <= right; }
|
return column_t(left) <= right;
|
||||||
|
}
|
||||||
|
|
||||||
void swap(column_t &left, column_t &right)
|
void swap(column_t &left, column_t &right)
|
||||||
{
|
{
|
||||||
|
|
|
@ -29,12 +29,12 @@
|
||||||
namespace xlnt {
|
namespace xlnt {
|
||||||
|
|
||||||
rich_text::rich_text(const std::string &plain_text)
|
rich_text::rich_text(const std::string &plain_text)
|
||||||
: rich_text(rich_text_run{plain_text,{}})
|
: rich_text(rich_text_run{plain_text, {}})
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
rich_text::rich_text(const std::string &plain_text, const class font &text_font)
|
rich_text::rich_text(const std::string &plain_text, const class font &text_font)
|
||||||
: rich_text(rich_text_run{plain_text,text_font})
|
: rich_text(rich_text_run{plain_text, text_font})
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,7 +51,7 @@ void rich_text::clear()
|
||||||
void rich_text::plain_text(const std::string &s)
|
void rich_text::plain_text(const std::string &s)
|
||||||
{
|
{
|
||||||
clear();
|
clear();
|
||||||
add_run(rich_text_run{s,{}});
|
add_run(rich_text_run{s, {}});
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string rich_text::plain_text() const
|
std::string rich_text::plain_text() const
|
||||||
|
@ -73,12 +73,12 @@ void rich_text::add_run(const rich_text_run &t)
|
||||||
bool rich_text::operator==(const rich_text &rhs) const
|
bool rich_text::operator==(const rich_text &rhs) const
|
||||||
{
|
{
|
||||||
if (runs_.size() != rhs.runs_.size()) return false;
|
if (runs_.size() != rhs.runs_.size()) return false;
|
||||||
|
|
||||||
for (std::size_t i = 0; i < runs_.size(); i++)
|
for (std::size_t i = 0; i < runs_.size(); i++)
|
||||||
{
|
{
|
||||||
if (runs_[i]!= rhs.runs_[i]) return false;
|
if (runs_[i] != rhs.runs_[i]) return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,12 +29,7 @@ namespace xlnt {
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
|
||||||
cell_impl::cell_impl()
|
cell_impl::cell_impl()
|
||||||
: type_(cell_type::null),
|
: type_(cell_type::null), parent_(nullptr), column_(1), row_(1), is_merged_(false), value_numeric_(0)
|
||||||
parent_(nullptr),
|
|
||||||
column_(1),
|
|
||||||
row_(1),
|
|
||||||
is_merged_(false),
|
|
||||||
value_numeric_(0)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,9 +22,9 @@
|
||||||
// @author: see AUTHORS file
|
// @author: see AUTHORS file
|
||||||
#include <limits>
|
#include <limits>
|
||||||
|
|
||||||
#include <detail/constants.hpp>
|
|
||||||
#include <xlnt/xlnt_config.hpp>
|
#include <xlnt/xlnt_config.hpp>
|
||||||
#include <xlnt/utils/exceptions.hpp>
|
#include <xlnt/utils/exceptions.hpp>
|
||||||
|
#include <detail/constants.hpp>
|
||||||
|
|
||||||
namespace xlnt {
|
namespace xlnt {
|
||||||
|
|
||||||
|
@ -32,7 +32,7 @@ row_t constants::min_row()
|
||||||
{
|
{
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
row_t constants::max_row()
|
row_t constants::max_row()
|
||||||
{
|
{
|
||||||
return std::numeric_limits<row_t>::max();
|
return std::numeric_limits<row_t>::max();
|
||||||
|
@ -49,57 +49,95 @@ const column_t constants::max_column()
|
||||||
}
|
}
|
||||||
|
|
||||||
// constants
|
// constants
|
||||||
const path constants::package_properties() { return path("docProps"); }
|
const path constants::package_properties()
|
||||||
const path constants::package_xl() { return path("/xl"); }
|
{
|
||||||
const path constants::package_root_rels() { return path(std::string("_rels")); }
|
return path("docProps");
|
||||||
const path constants::package_theme() { return package_xl().append("theme"); }
|
}
|
||||||
const path constants::package_worksheets() { return package_xl().append("worksheets"); }
|
const path constants::package_xl()
|
||||||
const path constants::package_drawings() { return package_xl().append("drawings"); }
|
{
|
||||||
|
return path("/xl");
|
||||||
|
}
|
||||||
|
const path constants::package_root_rels()
|
||||||
|
{
|
||||||
|
return path(std::string("_rels"));
|
||||||
|
}
|
||||||
|
const path constants::package_theme()
|
||||||
|
{
|
||||||
|
return package_xl().append("theme");
|
||||||
|
}
|
||||||
|
const path constants::package_worksheets()
|
||||||
|
{
|
||||||
|
return package_xl().append("worksheets");
|
||||||
|
}
|
||||||
|
const path constants::package_drawings()
|
||||||
|
{
|
||||||
|
return package_xl().append("drawings");
|
||||||
|
}
|
||||||
|
|
||||||
const path constants::part_content_types() { return path("[Content_Types].xml"); }
|
const path constants::part_content_types()
|
||||||
const path constants::part_root_relationships() { return package_root_rels().append(".rels"); }
|
{
|
||||||
const path constants::part_core() { return package_properties().append("core.xml"); }
|
return path("[Content_Types].xml");
|
||||||
const path constants::part_app() { return package_properties().append("app.xml"); }
|
}
|
||||||
const path constants::part_workbook() { return package_xl().append("workbook.xml"); }
|
const path constants::part_root_relationships()
|
||||||
const path constants::part_styles() { return package_xl().append("styles.xml"); }
|
{
|
||||||
const path constants::part_theme() { return package_theme().append("theme1.xml"); }
|
return package_root_rels().append(".rels");
|
||||||
const path constants::part_shared_strings() { return package_xl().append("sharedStrings.xml"); }
|
}
|
||||||
|
const path constants::part_core()
|
||||||
|
{
|
||||||
|
return package_properties().append("core.xml");
|
||||||
|
}
|
||||||
|
const path constants::part_app()
|
||||||
|
{
|
||||||
|
return package_properties().append("app.xml");
|
||||||
|
}
|
||||||
|
const path constants::part_workbook()
|
||||||
|
{
|
||||||
|
return package_xl().append("workbook.xml");
|
||||||
|
}
|
||||||
|
const path constants::part_styles()
|
||||||
|
{
|
||||||
|
return package_xl().append("styles.xml");
|
||||||
|
}
|
||||||
|
const path constants::part_theme()
|
||||||
|
{
|
||||||
|
return package_theme().append("theme1.xml");
|
||||||
|
}
|
||||||
|
const path constants::part_shared_strings()
|
||||||
|
{
|
||||||
|
return package_xl().append("sharedStrings.xml");
|
||||||
|
}
|
||||||
|
|
||||||
const std::unordered_map<std::string, std::string> &constants::namespaces()
|
const std::unordered_map<std::string, std::string> &constants::namespaces()
|
||||||
{
|
{
|
||||||
static const std::unordered_map<std::string, std::string> *namespaces =
|
static const std::unordered_map<std::string, std::string> *namespaces =
|
||||||
new std::unordered_map<std::string, std::string>
|
new std::unordered_map<std::string, std::string>{
|
||||||
{
|
{"spreadsheetml", "http://schemas.openxmlformats.org/spreadsheetml/2006/main"},
|
||||||
{ "spreadsheetml", "http://schemas.openxmlformats.org/spreadsheetml/2006/main" },
|
{"content-types", "http://schemas.openxmlformats.org/package/2006/content-types"},
|
||||||
{ "content-types", "http://schemas.openxmlformats.org/package/2006/content-types" },
|
{"relationships", "http://schemas.openxmlformats.org/package/2006/relationships"},
|
||||||
{ "relationships", "http://schemas.openxmlformats.org/package/2006/relationships" },
|
{"drawingml", "http://schemas.openxmlformats.org/drawingml/2006/main"},
|
||||||
{ "drawingml", "http://schemas.openxmlformats.org/drawingml/2006/main" },
|
{"workbook", "http://schemas.openxmlformats.org/spreadsheetml/2006/main"},
|
||||||
{ "workbook", "http://schemas.openxmlformats.org/spreadsheetml/2006/main" },
|
{"core-properties", "http://schemas.openxmlformats.org/package/2006/metadata/core-properties"},
|
||||||
{ "core-properties", "http://schemas.openxmlformats.org/package/2006/metadata/core-properties" },
|
{"extended-properties", "http://schemas.openxmlformats.org/officeDocument/2006/extended-properties"},
|
||||||
{ "extended-properties", "http://schemas.openxmlformats.org/officeDocument/2006/extended-properties" },
|
{"custom-properties", "http://schemas.openxmlformats.org/officeDocument/2006/customProperties"},
|
||||||
{ "custom-properties", "http://schemas.openxmlformats.org/officeDocument/2006/customProperties" },
|
|
||||||
|
|
||||||
{ "encryption", "http://schemas.microsoft.com/office/2006/encryption" },
|
{"encryption", "http://schemas.microsoft.com/office/2006/encryption"},
|
||||||
{ "encryption-password", "http://schemas.microsoft.com/office/2006/keyEncryptor/password" },
|
{"encryption-password", "http://schemas.microsoft.com/office/2006/keyEncryptor/password"},
|
||||||
{ "encryption-certificate", "http://schemas.microsoft.com/office/2006/keyEncryptor/certificate" },
|
{"encryption-certificate", "http://schemas.microsoft.com/office/2006/keyEncryptor/certificate"},
|
||||||
|
|
||||||
{ "dc", "http://purl.org/dc/elements/1.1/" },
|
{"dc", "http://purl.org/dc/elements/1.1/"}, {"dcterms", "http://purl.org/dc/terms/"},
|
||||||
{ "dcterms", "http://purl.org/dc/terms/" },
|
{"dcmitype", "http://purl.org/dc/dcmitype/"},
|
||||||
{ "dcmitype", "http://purl.org/dc/dcmitype/" },
|
{"mc", "http://schemas.openxmlformats.org/markup-compatibility/2006"},
|
||||||
{ "mc", "http://schemas.openxmlformats.org/markup-compatibility/2006" },
|
{"mx", "http://schemas.microsoft.com/office/mac/excel/2008/main"},
|
||||||
{ "mx", "http://schemas.microsoft.com/office/mac/excel/2008/main" },
|
{"r", "http://schemas.openxmlformats.org/officeDocument/2006/relationships"},
|
||||||
{ "r", "http://schemas.openxmlformats.org/officeDocument/2006/relationships" },
|
{"thm15", "http://schemas.microsoft.com/office/thememl/2012/main"},
|
||||||
{ "thm15", "http://schemas.microsoft.com/office/thememl/2012/main" },
|
{"vt", "http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes"},
|
||||||
{ "vt", "http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes" },
|
{"x14", "http://schemas.microsoft.com/office/spreadsheetml/2009/9/main"},
|
||||||
{ "x14", "http://schemas.microsoft.com/office/spreadsheetml/2009/9/main" },
|
{"x14ac", "http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac"},
|
||||||
{ "x14ac", "http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac" },
|
{"x15", "http://schemas.microsoft.com/office/spreadsheetml/2010/11/main"},
|
||||||
{ "x15", "http://schemas.microsoft.com/office/spreadsheetml/2010/11/main" },
|
{"x15ac", "http://schemas.microsoft.com/office/spreadsheetml/2010/11/ac"},
|
||||||
{ "x15ac", "http://schemas.microsoft.com/office/spreadsheetml/2010/11/ac" },
|
{"xml", "http://www.w3.org/XML/1998/namespace"}, {"xsi", "http://www.w3.org/2001/XMLSchema-instance"},
|
||||||
{ "xml", "http://www.w3.org/XML/1998/namespace" },
|
|
||||||
{ "xsi", "http://www.w3.org/2001/XMLSchema-instance" },
|
|
||||||
|
|
||||||
{ "loext", "http://schemas.libreoffice.org/" }
|
{"loext", "http://schemas.libreoffice.org/"}};
|
||||||
};
|
|
||||||
|
|
||||||
return *namespaces;
|
return *namespaces;
|
||||||
}
|
}
|
||||||
|
@ -115,5 +153,4 @@ const std::string &constants::namespace_(const std::string &id)
|
||||||
|
|
||||||
return match->second;
|
return match->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,50 +10,54 @@ std::string to_string(font::underline_style style)
|
||||||
{
|
{
|
||||||
switch (style)
|
switch (style)
|
||||||
{
|
{
|
||||||
case font::underline_style::double_: return "double";
|
case font::underline_style::double_:
|
||||||
case font::underline_style::double_accounting: return "doubleAccounting";
|
return "double";
|
||||||
case font::underline_style::single: return "single";
|
case font::underline_style::double_accounting:
|
||||||
case font::underline_style::single_accounting: return "singleAccounting";
|
return "doubleAccounting";
|
||||||
case font::underline_style::none: return "none";
|
case font::underline_style::single:
|
||||||
|
return "single";
|
||||||
|
case font::underline_style::single_accounting:
|
||||||
|
return "singleAccounting";
|
||||||
|
case font::underline_style::none:
|
||||||
|
return "none";
|
||||||
}
|
}
|
||||||
|
|
||||||
default_case("single");
|
default_case("single");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns the string representation of the relationship type.
|
/// Returns the string representation of the relationship type.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
std::string to_string(relationship_type t)
|
std::string to_string(relationship_type t)
|
||||||
{
|
{
|
||||||
switch (t)
|
switch (t)
|
||||||
{
|
{
|
||||||
case relationship_type::office_document:
|
case relationship_type::office_document:
|
||||||
return "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument";
|
return "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument";
|
||||||
case relationship_type::thumbnail:
|
case relationship_type::thumbnail:
|
||||||
return "http://schemas.openxmlformats.org/package/2006/relationships/metadata/thumbnail";
|
return "http://schemas.openxmlformats.org/package/2006/relationships/metadata/thumbnail";
|
||||||
case relationship_type::calculation_chain:
|
case relationship_type::calculation_chain:
|
||||||
return "http://purl.oclc.org/ooxml/officeDocument/relationships/calcChain";
|
return "http://purl.oclc.org/ooxml/officeDocument/relationships/calcChain";
|
||||||
case relationship_type::extended_properties:
|
case relationship_type::extended_properties:
|
||||||
return "http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties";
|
return "http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties";
|
||||||
case relationship_type::core_properties:
|
case relationship_type::core_properties:
|
||||||
return "http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties";
|
return "http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties";
|
||||||
case relationship_type::worksheet:
|
case relationship_type::worksheet:
|
||||||
return "http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet";
|
return "http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet";
|
||||||
case relationship_type::shared_string_table:
|
case relationship_type::shared_string_table:
|
||||||
return "http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings";
|
return "http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings";
|
||||||
case relationship_type::stylesheet:
|
case relationship_type::stylesheet:
|
||||||
return "http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles";
|
return "http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles";
|
||||||
case relationship_type::theme:
|
case relationship_type::theme:
|
||||||
return "http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme";
|
return "http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme";
|
||||||
case relationship_type::hyperlink:
|
case relationship_type::hyperlink:
|
||||||
return "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink";
|
return "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink";
|
||||||
case relationship_type::chartsheet:
|
case relationship_type::chartsheet:
|
||||||
return "http://schemas.openxmlformats.org/officeDocument/2006/relationships/chartsheet";
|
return "http://schemas.openxmlformats.org/officeDocument/2006/relationships/chartsheet";
|
||||||
case relationship_type::comments:
|
case relationship_type::comments:
|
||||||
return "http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments";
|
return "http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments";
|
||||||
case relationship_type::vml_drawing:
|
case relationship_type::vml_drawing:
|
||||||
return "http://schemas.openxmlformats.org/officeDocument/2006/relationships/vmlDrawing";
|
return "http://schemas.openxmlformats.org/officeDocument/2006/relationships/vmlDrawing";
|
||||||
case relationship_type::unknown:
|
case relationship_type::unknown:
|
||||||
return "unknown";
|
return "unknown";
|
||||||
case relationship_type::custom_properties:
|
case relationship_type::custom_properties:
|
||||||
|
@ -98,110 +102,163 @@ std::string to_string(relationship_type t)
|
||||||
return "volatile-dependencies";
|
return "volatile-dependencies";
|
||||||
case relationship_type::image:
|
case relationship_type::image:
|
||||||
return "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image";
|
return "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image";
|
||||||
}
|
}
|
||||||
|
|
||||||
default_case("unknown");
|
default_case("unknown");
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string to_string(pattern_fill_type fill_type)
|
std::string to_string(pattern_fill_type fill_type)
|
||||||
{
|
{
|
||||||
switch (fill_type)
|
switch (fill_type)
|
||||||
{
|
{
|
||||||
case pattern_fill_type::darkdown: return "darkdown";
|
case pattern_fill_type::darkdown:
|
||||||
case pattern_fill_type::darkgray: return "darkgray";
|
return "darkdown";
|
||||||
case pattern_fill_type::darkgrid: return "darkgrid";
|
case pattern_fill_type::darkgray:
|
||||||
case pattern_fill_type::darkhorizontal: return "darkhorizontal";
|
return "darkgray";
|
||||||
case pattern_fill_type::darktrellis: return "darkhorizontal";
|
case pattern_fill_type::darkgrid:
|
||||||
case pattern_fill_type::darkup: return "darkup";
|
return "darkgrid";
|
||||||
case pattern_fill_type::darkvertical: return "darkvertical";
|
case pattern_fill_type::darkhorizontal:
|
||||||
case pattern_fill_type::gray0625: return "gray0625";
|
return "darkhorizontal";
|
||||||
case pattern_fill_type::gray125: return "gray125";
|
case pattern_fill_type::darktrellis:
|
||||||
case pattern_fill_type::lightdown: return "lightdown";
|
return "darkhorizontal";
|
||||||
case pattern_fill_type::lightgray: return "lightgray";
|
case pattern_fill_type::darkup:
|
||||||
case pattern_fill_type::lightgrid: return "lightgrid";
|
return "darkup";
|
||||||
case pattern_fill_type::lighthorizontal: return "lighthorizontal";
|
case pattern_fill_type::darkvertical:
|
||||||
case pattern_fill_type::lighttrellis: return "lighttrellis";
|
return "darkvertical";
|
||||||
case pattern_fill_type::lightup: return "lightup";
|
case pattern_fill_type::gray0625:
|
||||||
case pattern_fill_type::lightvertical: return "lightvertical";
|
return "gray0625";
|
||||||
case pattern_fill_type::mediumgray: return "mediumgray";
|
case pattern_fill_type::gray125:
|
||||||
case pattern_fill_type::solid: return "solid";
|
return "gray125";
|
||||||
case pattern_fill_type::none: return "none";
|
case pattern_fill_type::lightdown:
|
||||||
}
|
return "lightdown";
|
||||||
|
case pattern_fill_type::lightgray:
|
||||||
|
return "lightgray";
|
||||||
|
case pattern_fill_type::lightgrid:
|
||||||
|
return "lightgrid";
|
||||||
|
case pattern_fill_type::lighthorizontal:
|
||||||
|
return "lighthorizontal";
|
||||||
|
case pattern_fill_type::lighttrellis:
|
||||||
|
return "lighttrellis";
|
||||||
|
case pattern_fill_type::lightup:
|
||||||
|
return "lightup";
|
||||||
|
case pattern_fill_type::lightvertical:
|
||||||
|
return "lightvertical";
|
||||||
|
case pattern_fill_type::mediumgray:
|
||||||
|
return "mediumgray";
|
||||||
|
case pattern_fill_type::solid:
|
||||||
|
return "solid";
|
||||||
|
case pattern_fill_type::none:
|
||||||
|
return "none";
|
||||||
|
}
|
||||||
|
|
||||||
default_case("none");
|
default_case("none");
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string to_string(gradient_fill_type fill_type)
|
std::string to_string(gradient_fill_type fill_type)
|
||||||
{
|
{
|
||||||
return fill_type == gradient_fill_type::linear ? "linear" : "path";
|
return fill_type == gradient_fill_type::linear ? "linear" : "path";
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string to_string(border_style style)
|
std::string to_string(border_style style)
|
||||||
{
|
{
|
||||||
switch (style)
|
switch (style)
|
||||||
{
|
{
|
||||||
case border_style::dashdot: return "dashdot";
|
case border_style::dashdot:
|
||||||
case border_style::dashdotdot: return "dashdotdot";
|
return "dashdot";
|
||||||
case border_style::dashed: return "dashed";
|
case border_style::dashdotdot:
|
||||||
case border_style::dotted: return "dotted";
|
return "dashdotdot";
|
||||||
case border_style::double_: return "double";
|
case border_style::dashed:
|
||||||
case border_style::hair: return "hair";
|
return "dashed";
|
||||||
case border_style::medium: return "medium";
|
case border_style::dotted:
|
||||||
case border_style::mediumdashdot: return "mediumdashdot";
|
return "dotted";
|
||||||
case border_style::mediumdashdotdot: return "mediumdashdotdot";
|
case border_style::double_:
|
||||||
case border_style::mediumdashed: return "mediumdashed";
|
return "double";
|
||||||
case border_style::slantdashdot: return "slantdashdot";
|
case border_style::hair:
|
||||||
case border_style::thick: return "thick";
|
return "hair";
|
||||||
case border_style::thin: return "thin";
|
case border_style::medium:
|
||||||
case border_style::none: return "none";
|
return "medium";
|
||||||
}
|
case border_style::mediumdashdot:
|
||||||
|
return "mediumdashdot";
|
||||||
|
case border_style::mediumdashdotdot:
|
||||||
|
return "mediumdashdotdot";
|
||||||
|
case border_style::mediumdashed:
|
||||||
|
return "mediumdashed";
|
||||||
|
case border_style::slantdashdot:
|
||||||
|
return "slantdashdot";
|
||||||
|
case border_style::thick:
|
||||||
|
return "thick";
|
||||||
|
case border_style::thin:
|
||||||
|
return "thin";
|
||||||
|
case border_style::none:
|
||||||
|
return "none";
|
||||||
|
}
|
||||||
|
|
||||||
default_case("none");
|
default_case("none");
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string to_string(vertical_alignment alignment)
|
std::string to_string(vertical_alignment alignment)
|
||||||
{
|
{
|
||||||
switch (alignment)
|
switch (alignment)
|
||||||
{
|
{
|
||||||
case vertical_alignment::top: return "top";
|
case vertical_alignment::top:
|
||||||
case vertical_alignment::center: return "center";
|
return "top";
|
||||||
case vertical_alignment::bottom: return "bottom";
|
case vertical_alignment::center:
|
||||||
case vertical_alignment::justify: return "justify";
|
return "center";
|
||||||
case vertical_alignment::distributed: return "distributed";
|
case vertical_alignment::bottom:
|
||||||
}
|
return "bottom";
|
||||||
|
case vertical_alignment::justify:
|
||||||
|
return "justify";
|
||||||
|
case vertical_alignment::distributed:
|
||||||
|
return "distributed";
|
||||||
|
}
|
||||||
|
|
||||||
default_case("top");
|
default_case("top");
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string to_string(horizontal_alignment alignment)
|
std::string to_string(horizontal_alignment alignment)
|
||||||
{
|
{
|
||||||
switch (alignment)
|
switch (alignment)
|
||||||
{
|
{
|
||||||
case horizontal_alignment::general: return "general";
|
case horizontal_alignment::general:
|
||||||
case horizontal_alignment::left: return "left";
|
return "general";
|
||||||
case horizontal_alignment::center: return "center";
|
case horizontal_alignment::left:
|
||||||
case horizontal_alignment::right: return "right";
|
return "left";
|
||||||
case horizontal_alignment::fill: return "fill";
|
case horizontal_alignment::center:
|
||||||
case horizontal_alignment::justify: return "justify";
|
return "center";
|
||||||
case horizontal_alignment::center_continuous: return "centerContinuous";
|
case horizontal_alignment::right:
|
||||||
case horizontal_alignment::distributed: return "distributed";
|
return "right";
|
||||||
}
|
case horizontal_alignment::fill:
|
||||||
|
return "fill";
|
||||||
|
case horizontal_alignment::justify:
|
||||||
|
return "justify";
|
||||||
|
case horizontal_alignment::center_continuous:
|
||||||
|
return "centerContinuous";
|
||||||
|
case horizontal_alignment::distributed:
|
||||||
|
return "distributed";
|
||||||
|
}
|
||||||
|
|
||||||
default_case("general");
|
default_case("general");
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string to_string(border_side side)
|
std::string to_string(border_side side)
|
||||||
{
|
{
|
||||||
switch (side)
|
switch (side)
|
||||||
{
|
{
|
||||||
case border_side::bottom: return "bottom";
|
case border_side::bottom:
|
||||||
case border_side::top: return "top";
|
return "bottom";
|
||||||
case border_side::start: return "left";
|
case border_side::top:
|
||||||
case border_side::end: return "right";
|
return "top";
|
||||||
case border_side::horizontal: return "horizontal";
|
case border_side::start:
|
||||||
case border_side::vertical: return "vertical";
|
return "left";
|
||||||
case border_side::diagonal: return "diagonal";
|
case border_side::end:
|
||||||
}
|
return "right";
|
||||||
|
case border_side::horizontal:
|
||||||
|
return "horizontal";
|
||||||
|
case border_side::vertical:
|
||||||
|
return "vertical";
|
||||||
|
case border_side::diagonal:
|
||||||
|
return "diagonal";
|
||||||
|
}
|
||||||
|
|
||||||
default_case("top");
|
default_case("top");
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,129 +24,48 @@
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
|
||||||
|
#include <xlnt/utils/exceptions.hpp>
|
||||||
#include <detail/default_case.hpp>
|
#include <detail/default_case.hpp>
|
||||||
#include <detail/number_formatter.hpp>
|
#include <detail/number_formatter.hpp>
|
||||||
#include <xlnt/utils/exceptions.hpp>
|
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
const std::unordered_map<int, std::string> known_locales()
|
const std::unordered_map<int, std::string> known_locales()
|
||||||
{
|
{
|
||||||
static const std::unordered_map<int, std::string> *all =
|
static const std::unordered_map<int, std::string> *all = new std::unordered_map<int, std::string>(
|
||||||
new std::unordered_map<int, std::string>(
|
{{0x401, "Arabic - Saudi Arabia"}, {0x402, "Bulgarian"}, {0x403, "Catalan"}, {0x404, "Chinese - Taiwan"},
|
||||||
{
|
{0x405, "Czech"}, {0x406, "Danish"}, {0x407, "German - Germany"}, {0x408, "Greek"},
|
||||||
{ 0x401, "Arabic - Saudi Arabia" },
|
{0x409, "English - United States"}, {0x410, "Italian - Italy"}, {0x411, "Japanese"}, {0x412, "Korean"},
|
||||||
{ 0x402, "Bulgarian" },
|
{0x413, "Dutch - Netherlands"}, {0x414, "Norwegian - Bokml"}, {0x415, "Polish"},
|
||||||
{ 0x403, "Catalan" },
|
{0x416, "Portuguese - Brazil"}, {0x417, "Raeto-Romance"}, {0x418, "Romanian - Romania"}, {0x419, "Russian"},
|
||||||
{ 0x404, "Chinese - Taiwan" },
|
{0x420, "Urdu"}, {0x421, "Indonesian"}, {0x422, "Ukrainian"}, {0x423, "Belarusian"}, {0x424, "Slovenian"},
|
||||||
{ 0x405, "Czech" },
|
{0x425, "Estonian"}, {0x426, "Latvian"}, {0x427, "Lithuanian"}, {0x428, "Tajik"},
|
||||||
{ 0x406, "Danish" },
|
{0x429, "Farsi - Persian"}, {0x430, "Sesotho (Sutu)"}, {0x431, "Tsonga"}, {0x432, "Setsuana"},
|
||||||
{ 0x407, "German - Germany" },
|
{0x433, "Venda"}, {0x434, "Xhosa"}, {0x435, "Zulu"}, {0x436, "Afrikaans"}, {0x437, "Georgian"},
|
||||||
{ 0x408, "Greek" },
|
{0x438, "Faroese"}, {0x439, "Hindi"}, {0x440, "Kyrgyz - Cyrillic"}, {0x441, "Swahili"}, {0x442, "Turkmen"},
|
||||||
{ 0x409, "English - United States" },
|
{0x443, "Uzbek - Latin"}, {0x444, "Tatar"}, {0x445, "Bengali - India"}, {0x446, "Punjabi"},
|
||||||
{ 0x410, "Italian - Italy" },
|
{0x447, "Gujarati"}, {0x448, "Oriya"}, {0x449, "Tamil"}, {0x450, "Mongolian"}, {0x451, "Tibetan"},
|
||||||
{ 0x411, "Japanese" },
|
{0x452, "Welsh"}, {0x453, "Khmer"}, {0x454, "Lao"}, {0x455, "Burmese"}, {0x456, "Galician"},
|
||||||
{ 0x412, "Korean" },
|
{0x457, "Konkani"}, {0x458, "Manipuri"}, {0x459, "Sindhi"}, {0x460, "Kashmiri"}, {0x461, "Nepali"},
|
||||||
{ 0x413, "Dutch - Netherlands" },
|
{0x462, "Frisian - Netherlands"}, {0x464, "Filipino"}, {0x465, "Divehi; Dhivehi; Maldivian"},
|
||||||
{ 0x414, "Norwegian - Bokml" },
|
{0x466, "Edo"}, {0x470, "Igbo - Nigeria"}, {0x474, "Guarani - Paraguay"}, {0x476, "Latin"},
|
||||||
{ 0x415, "Polish" },
|
{0x477, "Somali"}, {0x481, "Maori"}, {0x801, "Arabic - Iraq"}, {0x804, "Chinese - China"},
|
||||||
{ 0x416, "Portuguese - Brazil" },
|
{0x807, "German - Switzerland"}, {0x809, "English - Great Britain"}, {0x810, "Italian - Switzerland"},
|
||||||
{ 0x417, "Raeto-Romance" },
|
{0x813, "Dutch - Belgium"}, {0x814, "Norwegian - Nynorsk"}, {0x816, "Portuguese - Portugal"},
|
||||||
{ 0x418, "Romanian - Romania" },
|
{0x818, "Romanian - Moldova"}, {0x819, "Russian - Moldova"}, {0x843, "Uzbek - Cyrillic"},
|
||||||
{ 0x419, "Russian" },
|
{0x845, "Bengali - Bangladesh"}, {0x850, "Mongolian"}, {0x1001, "Arabic - Libya"},
|
||||||
{ 0x420, "Urdu" },
|
{0x1004, "Chinese - Singapore"}, {0x1007, "German - Luxembourg"}, {0x1009, "English - Canada"},
|
||||||
{ 0x421, "Indonesian" },
|
{0x1401, "Arabic - Algeria"}, {0x1404, "Chinese - Macau SAR"}, {0x1407, "German - Liechtenstein"},
|
||||||
{ 0x422, "Ukrainian" },
|
{0x1409, "English - New Zealand"}, {0x1801, "Arabic - Morocco"}, {0x1809, "English - Ireland"},
|
||||||
{ 0x423, "Belarusian" },
|
{0x2001, "Arabic - Oman"}, {0x2009, "English - Jamaica"}, {0x2401, "Arabic - Yemen"},
|
||||||
{ 0x424, "Slovenian" },
|
{0x2409, "English - Caribbean"}, {0x2801, "Arabic - Syria"}, {0x2809, "English - Belize"},
|
||||||
{ 0x425, "Estonian" },
|
{0x3001, "Arabic - Lebanon"}, {0x3009, "English - Zimbabwe"}, {0x3401, "Arabic - Kuwait"},
|
||||||
{ 0x426, "Latvian" },
|
{0x3409, "English - Phillippines"}, {0x3801, "Arabic - United Arab Emirates"}, {0x4001, "Arabic - Qatar"}});
|
||||||
{ 0x427, "Lithuanian" },
|
|
||||||
{ 0x428, "Tajik" },
|
|
||||||
{ 0x429, "Farsi - Persian" },
|
|
||||||
{ 0x430, "Sesotho (Sutu)" },
|
|
||||||
{ 0x431, "Tsonga" },
|
|
||||||
{ 0x432, "Setsuana" },
|
|
||||||
{ 0x433, "Venda" },
|
|
||||||
{ 0x434, "Xhosa" },
|
|
||||||
{ 0x435, "Zulu" },
|
|
||||||
{ 0x436, "Afrikaans" },
|
|
||||||
{ 0x437, "Georgian" },
|
|
||||||
{ 0x438, "Faroese" },
|
|
||||||
{ 0x439, "Hindi" },
|
|
||||||
{ 0x440, "Kyrgyz - Cyrillic" },
|
|
||||||
{ 0x441, "Swahili" },
|
|
||||||
{ 0x442, "Turkmen" },
|
|
||||||
{ 0x443, "Uzbek - Latin" },
|
|
||||||
{ 0x444, "Tatar" },
|
|
||||||
{ 0x445, "Bengali - India" },
|
|
||||||
{ 0x446, "Punjabi" },
|
|
||||||
{ 0x447, "Gujarati" },
|
|
||||||
{ 0x448, "Oriya" },
|
|
||||||
{ 0x449, "Tamil" },
|
|
||||||
{ 0x450, "Mongolian" },
|
|
||||||
{ 0x451, "Tibetan" },
|
|
||||||
{ 0x452, "Welsh" },
|
|
||||||
{ 0x453, "Khmer" },
|
|
||||||
{ 0x454, "Lao" },
|
|
||||||
{ 0x455, "Burmese" },
|
|
||||||
{ 0x456, "Galician" },
|
|
||||||
{ 0x457, "Konkani" },
|
|
||||||
{ 0x458, "Manipuri" },
|
|
||||||
{ 0x459, "Sindhi" },
|
|
||||||
{ 0x460, "Kashmiri" },
|
|
||||||
{ 0x461, "Nepali" },
|
|
||||||
{ 0x462, "Frisian - Netherlands" },
|
|
||||||
{ 0x464, "Filipino" },
|
|
||||||
{ 0x465, "Divehi; Dhivehi; Maldivian" },
|
|
||||||
{ 0x466, "Edo" },
|
|
||||||
{ 0x470, "Igbo - Nigeria" },
|
|
||||||
{ 0x474, "Guarani - Paraguay" },
|
|
||||||
{ 0x476, "Latin" },
|
|
||||||
{ 0x477, "Somali" },
|
|
||||||
{ 0x481, "Maori" },
|
|
||||||
{ 0x801, "Arabic - Iraq" },
|
|
||||||
{ 0x804, "Chinese - China" },
|
|
||||||
{ 0x807, "German - Switzerland" },
|
|
||||||
{ 0x809, "English - Great Britain" },
|
|
||||||
{ 0x810, "Italian - Switzerland" },
|
|
||||||
{ 0x813, "Dutch - Belgium" },
|
|
||||||
{ 0x814, "Norwegian - Nynorsk" },
|
|
||||||
{ 0x816, "Portuguese - Portugal" },
|
|
||||||
{ 0x818, "Romanian - Moldova" },
|
|
||||||
{ 0x819, "Russian - Moldova" },
|
|
||||||
{ 0x843, "Uzbek - Cyrillic" },
|
|
||||||
{ 0x845, "Bengali - Bangladesh" },
|
|
||||||
{ 0x850, "Mongolian" },
|
|
||||||
{ 0x1001, "Arabic - Libya" },
|
|
||||||
{ 0x1004, "Chinese - Singapore" },
|
|
||||||
{ 0x1007, "German - Luxembourg" },
|
|
||||||
{ 0x1009, "English - Canada" },
|
|
||||||
{ 0x1401, "Arabic - Algeria" },
|
|
||||||
{ 0x1404, "Chinese - Macau SAR" },
|
|
||||||
{ 0x1407, "German - Liechtenstein" },
|
|
||||||
{ 0x1409, "English - New Zealand" },
|
|
||||||
{ 0x1801, "Arabic - Morocco" },
|
|
||||||
{ 0x1809, "English - Ireland" },
|
|
||||||
{ 0x2001, "Arabic - Oman" },
|
|
||||||
{ 0x2009, "English - Jamaica" },
|
|
||||||
{ 0x2401, "Arabic - Yemen" },
|
|
||||||
{ 0x2409, "English - Caribbean" },
|
|
||||||
{ 0x2801, "Arabic - Syria" },
|
|
||||||
{ 0x2809, "English - Belize" },
|
|
||||||
{ 0x3001, "Arabic - Lebanon" },
|
|
||||||
{ 0x3009, "English - Zimbabwe" },
|
|
||||||
{ 0x3401, "Arabic - Kuwait" },
|
|
||||||
{ 0x3409, "English - Phillippines" },
|
|
||||||
{ 0x3801, "Arabic - United Arab Emirates" },
|
|
||||||
{ 0x4001, "Arabic - Qatar" }
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
return *all;
|
return *all;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[ noreturn ]] void unhandled_case_error()
|
[[noreturn]] void unhandled_case_error()
|
||||||
{
|
{
|
||||||
throw xlnt::exception("unhandled");
|
throw xlnt::exception("unhandled");
|
||||||
}
|
}
|
||||||
|
@ -178,7 +97,7 @@ bool format_condition::satisfied_by(long double number) const
|
||||||
return number < value;
|
return number < value;
|
||||||
case condition_type::not_equal:
|
case condition_type::not_equal:
|
||||||
return std::fabs(number - value) != 0.0L;
|
return std::fabs(number - value) != 0.0L;
|
||||||
case condition_type::equal:
|
case condition_type::equal:
|
||||||
return std::fabs(number - value) == 0.0L;
|
return std::fabs(number - value) == 0.0L;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -219,10 +138,7 @@ void number_format_parser::parse()
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case number_format_token::token_type::color:
|
case number_format_token::token_type::color:
|
||||||
if (section.has_color
|
if (section.has_color || section.has_condition || section.has_locale || !section.parts.empty())
|
||||||
|| section.has_condition
|
|
||||||
|| section.has_locale
|
|
||||||
|| !section.parts.empty())
|
|
||||||
{
|
{
|
||||||
throw std::runtime_error("color should be the first part of a format");
|
throw std::runtime_error("color should be the first part of a format");
|
||||||
}
|
}
|
||||||
|
@ -249,7 +165,7 @@ void number_format_parser::parse()
|
||||||
section.parts.push_back(part);
|
section.parts.push_back(part);
|
||||||
part = template_part();
|
part = template_part();
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -299,7 +215,7 @@ void number_format_parser::parse()
|
||||||
section.condition.type = format_condition::condition_type::equal;
|
section.condition.type = format_condition::condition_type::equal;
|
||||||
value = token.string.substr(1);
|
value = token.string.substr(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
section.condition.value = std::stold(value);
|
section.condition.value = std::stold(value);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -311,7 +227,7 @@ void number_format_parser::parse()
|
||||||
part = template_part();
|
part = template_part();
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case number_format_token::token_type::fill:
|
case number_format_token::token_type::fill:
|
||||||
part.type = template_part::template_type::fill;
|
part.type = template_part::template_type::fill;
|
||||||
part.string = token.string;
|
part.string = token.string;
|
||||||
|
@ -387,7 +303,7 @@ void number_format_parser::parse()
|
||||||
part.type = template_part::template_type::month_letter;
|
part.type = template_part::template_type::month_letter;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
unhandled_case(true);
|
unhandled_case(true);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -412,7 +328,7 @@ void number_format_parser::parse()
|
||||||
part.type = template_part::template_type::day_name;
|
part.type = template_part::template_type::day_name;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
unhandled_case(true);
|
unhandled_case(true);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -427,7 +343,7 @@ void number_format_parser::parse()
|
||||||
part.type = template_part::template_type::year_long;
|
part.type = template_part::template_type::year_long;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
unhandled_case(true);
|
unhandled_case(true);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -442,7 +358,7 @@ void number_format_parser::parse()
|
||||||
part.type = template_part::template_type::hour_leading_zero;
|
part.type = template_part::template_type::hour_leading_zero;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
unhandled_case(true);
|
unhandled_case(true);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -457,7 +373,7 @@ void number_format_parser::parse()
|
||||||
part.type = template_part::template_type::second_leading_zero;
|
part.type = template_part::template_type::second_leading_zero;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
unhandled_case(true);
|
unhandled_case(true);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -474,7 +390,7 @@ void number_format_parser::parse()
|
||||||
part.type = template_part::template_type::a_p;
|
part.type = template_part::template_type::a_p;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
unhandled_case(true);
|
unhandled_case(true);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -485,9 +401,9 @@ void number_format_parser::parse()
|
||||||
|
|
||||||
section.parts.push_back(part);
|
section.parts.push_back(part);
|
||||||
part = template_part();
|
part = template_part();
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case number_format_token::token_type::end:
|
case number_format_token::token_type::end:
|
||||||
codes_.push_back(section);
|
codes_.push_back(section);
|
||||||
finalize();
|
finalize();
|
||||||
|
@ -519,7 +435,7 @@ void number_format_parser::finalize()
|
||||||
bool fraction = false;
|
bool fraction = false;
|
||||||
std::size_t fraction_denominator_index = 0;
|
std::size_t fraction_denominator_index = 0;
|
||||||
std::size_t fraction_numerator_index = 0;
|
std::size_t fraction_numerator_index = 0;
|
||||||
|
|
||||||
bool seconds = false;
|
bool seconds = false;
|
||||||
bool fractional_seconds = false;
|
bool fractional_seconds = false;
|
||||||
std::size_t seconds_index = 0;
|
std::size_t seconds_index = 0;
|
||||||
|
@ -527,10 +443,8 @@ void number_format_parser::finalize()
|
||||||
for (std::size_t i = 0; i < code.parts.size(); ++i)
|
for (std::size_t i = 0; i < code.parts.size(); ++i)
|
||||||
{
|
{
|
||||||
const auto &part = code.parts[i];
|
const auto &part = code.parts[i];
|
||||||
|
|
||||||
if (i > 0
|
if (i > 0 && i + 1 < code.parts.size() && part.type == template_part::template_type::text
|
||||||
&& i + 1 < code.parts.size()
|
|
||||||
&& part.type == template_part::template_type::text
|
|
||||||
&& part.string == "/"
|
&& part.string == "/"
|
||||||
&& code.parts[i - 1].placeholders.type == format_placeholders::placeholders_type::integer_part
|
&& code.parts[i - 1].placeholders.type == format_placeholders::placeholders_type::integer_part
|
||||||
&& code.parts[i + 1].placeholders.type == format_placeholders::placeholders_type::integer_part)
|
&& code.parts[i + 1].placeholders.type == format_placeholders::placeholders_type::integer_part)
|
||||||
|
@ -560,7 +474,7 @@ void number_format_parser::finalize()
|
||||||
{
|
{
|
||||||
percentage = true;
|
percentage = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (part.type == template_part::template_type::second
|
if (part.type == template_part::template_type::second
|
||||||
|| part.type == template_part::template_type::second_leading_zero)
|
|| part.type == template_part::template_type::second_leading_zero)
|
||||||
{
|
{
|
||||||
|
@ -573,7 +487,7 @@ void number_format_parser::finalize()
|
||||||
fractional_seconds = true;
|
fractional_seconds = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO this block needs improvement
|
// TODO this block needs improvement
|
||||||
if (part.type == template_part::template_type::month_number
|
if (part.type == template_part::template_type::month_number
|
||||||
|| part.type == template_part::template_type::month_number_leading_zero)
|
|| part.type == template_part::template_type::month_number_leading_zero)
|
||||||
{
|
{
|
||||||
|
@ -583,11 +497,10 @@ void number_format_parser::finalize()
|
||||||
const auto &after_next = code.parts[i + 2];
|
const auto &after_next = code.parts[i + 2];
|
||||||
|
|
||||||
if ((next.type == template_part::template_type::second
|
if ((next.type == template_part::template_type::second
|
||||||
|| next.type == template_part::template_type::second_leading_zero)
|
|| next.type == template_part::template_type::second_leading_zero)
|
||||||
|| (next.type == template_part::template_type::text
|
|| (next.type == template_part::template_type::text && next.string == ":"
|
||||||
&& next.string == ":"
|
&& (after_next.type == template_part::template_type::second
|
||||||
&& (after_next.type == template_part::template_type::second ||
|
|| after_next.type == template_part::template_type::second_leading_zero)))
|
||||||
after_next.type == template_part::template_type::second_leading_zero)))
|
|
||||||
{
|
{
|
||||||
fix = true;
|
fix = true;
|
||||||
leading_zero = part.type == template_part::template_type::month_number_leading_zero;
|
leading_zero = part.type == template_part::template_type::month_number_leading_zero;
|
||||||
|
@ -600,10 +513,9 @@ void number_format_parser::finalize()
|
||||||
const auto &previous = code.parts[i - 1];
|
const auto &previous = code.parts[i - 1];
|
||||||
const auto &before_previous = code.parts[i - 2];
|
const auto &before_previous = code.parts[i - 2];
|
||||||
|
|
||||||
if (previous.type == template_part::template_type::text
|
if (previous.type == template_part::template_type::text && previous.string == ":"
|
||||||
&& previous.string == ":"
|
|
||||||
&& (before_previous.type == template_part::template_type::hour_leading_zero
|
&& (before_previous.type == template_part::template_type::hour_leading_zero
|
||||||
|| before_previous.type == template_part::template_type::hour))
|
|| before_previous.type == template_part::template_type::hour))
|
||||||
{
|
{
|
||||||
fix = true;
|
fix = true;
|
||||||
leading_zero = part.type == template_part::template_type::month_number_leading_zero;
|
leading_zero = part.type == template_part::template_type::month_number_leading_zero;
|
||||||
|
@ -612,25 +524,23 @@ void number_format_parser::finalize()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fix)
|
if (fix)
|
||||||
{
|
{
|
||||||
code.parts[minutes_index].type = leading_zero ?
|
code.parts[minutes_index].type =
|
||||||
template_part::template_type::minute_leading_zero :
|
leading_zero ? template_part::template_type::minute_leading_zero : template_part::template_type::minute;
|
||||||
template_part::template_type::minute;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (integer_part && !fractional_part)
|
if (integer_part && !fractional_part)
|
||||||
{
|
{
|
||||||
code.parts[integer_part_index].placeholders.type =
|
code.parts[integer_part_index].placeholders.type = format_placeholders::placeholders_type::integer_only;
|
||||||
format_placeholders::placeholders_type::integer_only;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (integer_part && fractional_part && percentage)
|
if (integer_part && fractional_part && percentage)
|
||||||
{
|
{
|
||||||
code.parts[integer_part_index].placeholders.percentage = true;
|
code.parts[integer_part_index].placeholders.percentage = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (exponent)
|
if (exponent)
|
||||||
{
|
{
|
||||||
const auto &next = code.parts[exponent_index + 1];
|
const auto &next = code.parts[exponent_index + 1];
|
||||||
|
@ -644,25 +554,23 @@ void number_format_parser::finalize()
|
||||||
code.parts[i].placeholders.scientific = true;
|
code.parts[i].placeholders.scientific = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fraction)
|
if (fraction)
|
||||||
{
|
{
|
||||||
code.parts[fraction_numerator_index].placeholders.type =
|
code.parts[fraction_numerator_index].placeholders.type =
|
||||||
format_placeholders::placeholders_type::fraction_numerator;
|
format_placeholders::placeholders_type::fraction_numerator;
|
||||||
code.parts[fraction_denominator_index].placeholders.type =
|
code.parts[fraction_denominator_index].placeholders.type =
|
||||||
format_placeholders::placeholders_type::fraction_denominator;
|
format_placeholders::placeholders_type::fraction_denominator;
|
||||||
|
|
||||||
for (std::size_t i = 0; i < code.parts.size(); ++i)
|
for (std::size_t i = 0; i < code.parts.size(); ++i)
|
||||||
{
|
{
|
||||||
if (code.parts[i].placeholders.type ==
|
if (code.parts[i].placeholders.type == format_placeholders::placeholders_type::integer_part)
|
||||||
format_placeholders::placeholders_type::integer_part)
|
|
||||||
{
|
{
|
||||||
code.parts[i].placeholders.type =
|
code.parts[i].placeholders.type = format_placeholders::placeholders_type::fraction_integer;
|
||||||
format_placeholders::placeholders_type::fraction_integer;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fractional_seconds)
|
if (fractional_seconds)
|
||||||
{
|
{
|
||||||
if (code.parts[seconds_index].type == template_part::template_type::second)
|
if (code.parts[seconds_index].type == template_part::template_type::second)
|
||||||
|
@ -707,8 +615,7 @@ number_format_token number_format_parser::parse_next_token()
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
token.string.push_back(format_string_[position_++]);
|
token.string.push_back(format_string_[position_++]);
|
||||||
}
|
} while (position_ < format_string_.size() && format_string_[position_] != ']');
|
||||||
while (position_ < format_string_.size() && format_string_[position_] != ']');
|
|
||||||
|
|
||||||
if (token.string[0] == '<' || token.string[0] == '>' || token.string[0] == '=')
|
if (token.string[0] == '<' || token.string[0] == '>' || token.string[0] == '=')
|
||||||
{
|
{
|
||||||
|
@ -718,10 +625,9 @@ number_format_token number_format_parser::parse_next_token()
|
||||||
{
|
{
|
||||||
token.type = number_format_token::token_type::locale;
|
token.type = number_format_token::token_type::locale;
|
||||||
}
|
}
|
||||||
else if (token.string.size() <= 2 &&
|
else if (token.string.size() <= 2
|
||||||
((token.string == "h" || token.string == "hh") ||
|
&& ((token.string == "h" || token.string == "hh") || (token.string == "m" || token.string == "mm")
|
||||||
(token.string == "m" || token.string == "mm") ||
|
|| (token.string == "s" || token.string == "ss")))
|
||||||
(token.string == "s" || token.string == "ss")))
|
|
||||||
{
|
{
|
||||||
token.type = number_format_token::token_type::datetime;
|
token.type = number_format_token::token_type::datetime;
|
||||||
token.string = "[" + token.string + "]";
|
token.string = "[" + token.string + "]";
|
||||||
|
@ -776,8 +682,7 @@ number_format_token number_format_parser::parse_next_token()
|
||||||
{
|
{
|
||||||
token.string.push_back(current_char);
|
token.string.push_back(current_char);
|
||||||
current_char = format_string_[position_++];
|
current_char = format_string_[position_++];
|
||||||
}
|
} while (current_char == '0' || current_char == '#' || current_char == '?' || current_char == ',');
|
||||||
while (current_char == '0' || current_char == '#' || current_char == '?' || current_char == ',');
|
|
||||||
|
|
||||||
--position_;
|
--position_;
|
||||||
|
|
||||||
|
@ -788,7 +693,7 @@ number_format_token number_format_parser::parse_next_token()
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'y':
|
case 'y':
|
||||||
case 'm':
|
case 'm':
|
||||||
case 'd':
|
case 'd':
|
||||||
|
@ -796,7 +701,7 @@ number_format_token number_format_parser::parse_next_token()
|
||||||
case 's':
|
case 's':
|
||||||
token.type = number_format_token::token_type::datetime;
|
token.type = number_format_token::token_type::datetime;
|
||||||
token.string.push_back(current_char);
|
token.string.push_back(current_char);
|
||||||
|
|
||||||
while (format_string_[position_] == current_char)
|
while (format_string_[position_] == current_char)
|
||||||
{
|
{
|
||||||
token.string.push_back(current_char);
|
token.string.push_back(current_char);
|
||||||
|
@ -853,7 +758,7 @@ number_format_token number_format_parser::parse_next_token()
|
||||||
case ';':
|
case ';':
|
||||||
token.type = number_format_token::token_type::end_section;
|
token.type = number_format_token::token_type::end_section;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case '(':
|
case '(':
|
||||||
token.type = number_format_token::token_type::text;
|
token.type = number_format_token::token_type::text;
|
||||||
token.string.push_back(current_char);
|
token.string.push_back(current_char);
|
||||||
|
@ -895,17 +800,17 @@ number_format_token number_format_parser::parse_next_token()
|
||||||
token.string.push_back(current_char);
|
token.string.push_back(current_char);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case '@':
|
case '@':
|
||||||
token.type = number_format_token::token_type::number;
|
token.type = number_format_token::token_type::number;
|
||||||
token.string.push_back(current_char);
|
token.string.push_back(current_char);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'E':
|
case 'E':
|
||||||
token.type = number_format_token::token_type::number;
|
token.type = number_format_token::token_type::number;
|
||||||
token.string.push_back(current_char);
|
token.string.push_back(current_char);
|
||||||
current_char = format_string_[position_++];
|
current_char = format_string_[position_++];
|
||||||
|
|
||||||
if (current_char == '+' || current_char == '-')
|
if (current_char == '+' || current_char == '-')
|
||||||
{
|
{
|
||||||
token.string.push_back(current_char);
|
token.string.push_back(current_char);
|
||||||
|
@ -930,9 +835,7 @@ void number_format_parser::validate()
|
||||||
|
|
||||||
if (codes_.size() > 2)
|
if (codes_.size() > 2)
|
||||||
{
|
{
|
||||||
if (codes_[0].has_condition
|
if (codes_[0].has_condition && codes_[1].has_condition && codes_[2].has_condition)
|
||||||
&& codes_[1].has_condition
|
|
||||||
&& codes_[2].has_condition)
|
|
||||||
{
|
{
|
||||||
throw std::runtime_error("format should have a maximum of two codes with conditions");
|
throw std::runtime_error("format should have a maximum of two codes with conditions");
|
||||||
}
|
}
|
||||||
|
@ -959,9 +862,8 @@ format_placeholders number_format_parser::parse_placeholders(const std::string &
|
||||||
}
|
}
|
||||||
else if (placeholders_string.front() == 'E')
|
else if (placeholders_string.front() == 'E')
|
||||||
{
|
{
|
||||||
p.type = placeholders_string[1] == '+'
|
p.type = placeholders_string[1] == '+' ? format_placeholders::placeholders_type::scientific_exponent_plus
|
||||||
? format_placeholders::placeholders_type::scientific_exponent_plus
|
: format_placeholders::placeholders_type::scientific_exponent_minus;
|
||||||
: format_placeholders::placeholders_type::scientific_exponent_minus;
|
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -997,7 +899,7 @@ format_placeholders number_format_parser::parse_placeholders(const std::string &
|
||||||
comma_indices.push_back(i);
|
comma_indices.push_back(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!comma_indices.empty())
|
if (!comma_indices.empty())
|
||||||
{
|
{
|
||||||
std::size_t i = placeholders_string.size() - 1;
|
std::size_t i = placeholders_string.size() - 1;
|
||||||
|
@ -1008,10 +910,10 @@ format_placeholders number_format_parser::parse_placeholders(const std::string &
|
||||||
--i;
|
--i;
|
||||||
comma_indices.pop_back();
|
comma_indices.pop_back();
|
||||||
}
|
}
|
||||||
|
|
||||||
p.use_comma_separator = !comma_indices.empty();
|
p.use_comma_separator = !comma_indices.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1046,7 +948,7 @@ format_color number_format_parser::color_from_string(const std::string &color)
|
||||||
{
|
{
|
||||||
return format_color::blue;
|
return format_color::blue;
|
||||||
}
|
}
|
||||||
|
|
||||||
unhandled_case(true);
|
unhandled_case(true);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -1055,7 +957,7 @@ format_color number_format_parser::color_from_string(const std::string &color)
|
||||||
{
|
{
|
||||||
return format_color::green;
|
return format_color::green;
|
||||||
}
|
}
|
||||||
|
|
||||||
unhandled_case(true);
|
unhandled_case(true);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -1064,7 +966,7 @@ format_color number_format_parser::color_from_string(const std::string &color)
|
||||||
{
|
{
|
||||||
return format_color::white;
|
return format_color::white;
|
||||||
}
|
}
|
||||||
|
|
||||||
unhandled_case(true);
|
unhandled_case(true);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -1073,7 +975,7 @@ format_color number_format_parser::color_from_string(const std::string &color)
|
||||||
{
|
{
|
||||||
return format_color::magenta;
|
return format_color::magenta;
|
||||||
}
|
}
|
||||||
|
|
||||||
unhandled_case(true);
|
unhandled_case(true);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -1082,7 +984,7 @@ format_color number_format_parser::color_from_string(const std::string &color)
|
||||||
{
|
{
|
||||||
return format_color::yellow;
|
return format_color::yellow;
|
||||||
}
|
}
|
||||||
|
|
||||||
unhandled_case(true);
|
unhandled_case(true);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -1091,14 +993,14 @@ format_color number_format_parser::color_from_string(const std::string &color)
|
||||||
{
|
{
|
||||||
return format_color::red;
|
return format_color::red;
|
||||||
}
|
}
|
||||||
|
|
||||||
unhandled_case(true);
|
unhandled_case(true);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
unhandled_case(true);
|
unhandled_case(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
unhandled_case_error();
|
unhandled_case_error();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1124,7 +1026,7 @@ std::pair<format_locale, std::string> number_format_parser::locale_from_string(c
|
||||||
{
|
{
|
||||||
throw std::runtime_error("bad locale: " + locale_string);
|
throw std::runtime_error("bad locale: " + locale_string);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto c : country_code_string)
|
for (auto c : country_code_string)
|
||||||
{
|
{
|
||||||
if (!((c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f') || (c >= '0' && c <= '9')))
|
if (!((c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f') || (c >= '0' && c <= '9')))
|
||||||
|
@ -1148,8 +1050,7 @@ std::pair<format_locale, std::string> number_format_parser::locale_from_string(c
|
||||||
}
|
}
|
||||||
|
|
||||||
number_formatter::number_formatter(const std::string &format_string, xlnt::calendar calendar)
|
number_formatter::number_formatter(const std::string &format_string, xlnt::calendar calendar)
|
||||||
: parser_(format_string),
|
: parser_(format_string), calendar_(calendar)
|
||||||
calendar_(calendar)
|
|
||||||
{
|
{
|
||||||
parser_.parse();
|
parser_.parse();
|
||||||
format_ = parser_.result();
|
format_ = parser_.result();
|
||||||
|
@ -1168,21 +1069,20 @@ std::string number_formatter::format_number(long double number)
|
||||||
{
|
{
|
||||||
return std::string(11, '#');
|
return std::string(11, '#');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!format_[1].has_condition
|
if (!format_[1].has_condition || format_[1].condition.satisfied_by(number))
|
||||||
|| format_[1].condition.satisfied_by(number))
|
|
||||||
{
|
{
|
||||||
return format_number(format_[1], number);
|
return format_number(format_[1], number);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (format_.size() == 2)
|
if (format_.size() == 2)
|
||||||
{
|
{
|
||||||
return std::string(11, '#');
|
return std::string(11, '#');
|
||||||
}
|
}
|
||||||
|
|
||||||
return format_number(format_[2], number);
|
return format_number(format_[2], number);
|
||||||
}
|
}
|
||||||
|
|
||||||
// no conditions, format based on sign:
|
// no conditions, format based on sign:
|
||||||
|
|
||||||
// 1 section, use for all
|
// 1 section, use for all
|
||||||
|
@ -1274,22 +1174,22 @@ std::string number_formatter::fill_placeholders(const format_placeholders &p, lo
|
||||||
|| p.type == format_placeholders::placeholders_type::fraction_integer)
|
|| p.type == format_placeholders::placeholders_type::fraction_integer)
|
||||||
{
|
{
|
||||||
result = std::to_string(integer_part);
|
result = std::to_string(integer_part);
|
||||||
|
|
||||||
while (result.size() < p.num_zeros)
|
while (result.size() < p.num_zeros)
|
||||||
{
|
{
|
||||||
result = "0" + result;
|
result = "0" + result;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (result.size() < p.num_zeros + p.num_spaces)
|
while (result.size() < p.num_zeros + p.num_spaces)
|
||||||
{
|
{
|
||||||
result = " " + result;
|
result = " " + result;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (p.use_comma_separator)
|
if (p.use_comma_separator)
|
||||||
{
|
{
|
||||||
std::vector<char> digits(result.rbegin(), result.rend());
|
std::vector<char> digits(result.rbegin(), result.rend());
|
||||||
std::string temp;
|
std::string temp;
|
||||||
|
|
||||||
for (std::size_t i = 0; i < digits.size(); i++)
|
for (std::size_t i = 0; i < digits.size(); i++)
|
||||||
{
|
{
|
||||||
temp.push_back(digits[i]);
|
temp.push_back(digits[i]);
|
||||||
|
@ -1299,7 +1199,7 @@ std::string number_formatter::fill_placeholders(const format_placeholders &p, lo
|
||||||
temp.push_back(',');
|
temp.push_back(',');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
result = std::string(temp.rbegin(), temp.rend());
|
result = std::string(temp.rbegin(), temp.rend());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1312,7 +1212,8 @@ std::string number_formatter::fill_placeholders(const format_placeholders &p, lo
|
||||||
{
|
{
|
||||||
auto fractional_part = number - integer_part;
|
auto fractional_part = number - integer_part;
|
||||||
result = std::fabs(fractional_part) < std::numeric_limits<long double>::min()
|
result = std::fabs(fractional_part) < std::numeric_limits<long double>::min()
|
||||||
? std::string(".") : std::to_string(fractional_part).substr(1);
|
? std::string(".")
|
||||||
|
: std::to_string(fractional_part).substr(1);
|
||||||
|
|
||||||
while (result.back() == '0' || result.size() > (p.num_zeros + p.num_optionals + p.num_spaces + 1))
|
while (result.back() == '0' || result.size() > (p.num_zeros + p.num_optionals + p.num_spaces + 1))
|
||||||
{
|
{
|
||||||
|
@ -1339,11 +1240,10 @@ std::string number_formatter::fill_placeholders(const format_placeholders &p, lo
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string number_formatter::fill_scientific_placeholders(const format_placeholders &integer_part,
|
std::string number_formatter::fill_scientific_placeholders(const format_placeholders &integer_part,
|
||||||
const format_placeholders &fractional_part, const format_placeholders &exponent_part,
|
const format_placeholders &fractional_part, const format_placeholders &exponent_part, long double number)
|
||||||
long double number)
|
|
||||||
{
|
{
|
||||||
std::size_t logarithm = 0;
|
std::size_t logarithm = 0;
|
||||||
|
|
||||||
if (number != 0.L)
|
if (number != 0.L)
|
||||||
{
|
{
|
||||||
logarithm = static_cast<std::size_t>(std::log10(number));
|
logarithm = static_cast<std::size_t>(std::log10(number));
|
||||||
|
@ -1355,7 +1255,7 @@ std::string number_formatter::fill_scientific_placeholders(const format_placehol
|
||||||
}
|
}
|
||||||
|
|
||||||
number /= std::pow(10.L, logarithm);
|
number /= std::pow(10.L, logarithm);
|
||||||
|
|
||||||
auto integer = static_cast<int>(number);
|
auto integer = static_cast<int>(number);
|
||||||
auto fraction = number - integer;
|
auto fraction = number - integer;
|
||||||
|
|
||||||
|
@ -1392,7 +1292,7 @@ std::string number_formatter::fill_scientific_placeholders(const format_placehol
|
||||||
return integer_string + fractional_string + exponent_string;
|
return integer_string + fractional_string + exponent_string;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string number_formatter::fill_fraction_placeholders(const format_placeholders &/*numerator*/,
|
std::string number_formatter::fill_fraction_placeholders(const format_placeholders & /*numerator*/,
|
||||||
const format_placeholders &denominator, long double number, bool /*improper*/)
|
const format_placeholders &denominator, long double number, bool /*improper*/)
|
||||||
{
|
{
|
||||||
auto fractional_part = number - static_cast<int>(number);
|
auto fractional_part = number - static_cast<int>(number);
|
||||||
|
@ -1407,7 +1307,7 @@ std::string number_formatter::fill_fraction_placeholders(const format_placeholde
|
||||||
|
|
||||||
fractional_part = static_cast<int>(fractional_part);
|
fractional_part = static_cast<int>(fractional_part);
|
||||||
auto denominator_digits = denominator.num_zeros + denominator.num_optionals + denominator.num_spaces;
|
auto denominator_digits = denominator.num_zeros + denominator.num_optionals + denominator.num_spaces;
|
||||||
// auto denominator_digits = static_cast<std::size_t>(std::ceil(std::log10(fractional_part)));
|
// auto denominator_digits = static_cast<std::size_t>(std::ceil(std::log10(fractional_part)));
|
||||||
|
|
||||||
auto lower = static_cast<int>(std::pow(10, denominator_digits - 1));
|
auto lower = static_cast<int>(std::pow(10, denominator_digits - 1));
|
||||||
auto upper = static_cast<int>(std::pow(10, denominator_digits));
|
auto upper = static_cast<int>(std::pow(10, denominator_digits));
|
||||||
|
@ -1419,7 +1319,7 @@ std::string number_formatter::fill_fraction_placeholders(const format_placeholde
|
||||||
auto numerator_full = original_fractional_part * i;
|
auto numerator_full = original_fractional_part * i;
|
||||||
auto numerator_rounded = static_cast<int>(std::round(numerator_full));
|
auto numerator_rounded = static_cast<int>(std::round(numerator_full));
|
||||||
auto difference = std::fabs(original_fractional_part - (numerator_rounded / static_cast<long double>(i)));
|
auto difference = std::fabs(original_fractional_part - (numerator_rounded / static_cast<long double>(i)));
|
||||||
|
|
||||||
if (difference < best_difference)
|
if (difference < best_difference)
|
||||||
{
|
{
|
||||||
best_difference = difference;
|
best_difference = difference;
|
||||||
|
@ -1433,35 +1333,12 @@ std::string number_formatter::fill_fraction_placeholders(const format_placeholde
|
||||||
|
|
||||||
std::string number_formatter::format_number(const format_code &format, long double number)
|
std::string number_formatter::format_number(const format_code &format, long double number)
|
||||||
{
|
{
|
||||||
static const std::vector<std::string> *month_names =
|
static const std::vector<std::string> *month_names = new std::vector<std::string>{"January", "February", "March",
|
||||||
new std::vector<std::string>
|
"April", "May", "June", "July", "August", "September", "October", "November", "December"};
|
||||||
{
|
|
||||||
"January",
|
|
||||||
"February",
|
|
||||||
"March",
|
|
||||||
"April",
|
|
||||||
"May",
|
|
||||||
"June",
|
|
||||||
"July",
|
|
||||||
"August",
|
|
||||||
"September",
|
|
||||||
"October",
|
|
||||||
"November",
|
|
||||||
"December"
|
|
||||||
};
|
|
||||||
|
|
||||||
static const std::vector<std::string> *day_names =
|
static const std::vector<std::string> *day_names =
|
||||||
new std::vector<std::string>
|
new std::vector<std::string>{"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
|
||||||
{
|
|
||||||
"Sunday",
|
|
||||||
"Monday",
|
|
||||||
"Tuesday",
|
|
||||||
"Wednesday",
|
|
||||||
"Thursday",
|
|
||||||
"Friday",
|
|
||||||
"Saturday"
|
|
||||||
};
|
|
||||||
|
|
||||||
std::string result;
|
std::string result;
|
||||||
|
|
||||||
if (number < 0)
|
if (number < 0)
|
||||||
|
@ -1498,7 +1375,7 @@ std::string number_formatter::format_number(const format_code &format, long doub
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool improper_fraction = true;
|
bool improper_fraction = true;
|
||||||
std::size_t fill_index = 0;
|
std::size_t fill_index = 0;
|
||||||
bool fill = false;
|
bool fill = false;
|
||||||
|
@ -1527,7 +1404,8 @@ std::string number_formatter::format_number(const format_code &format, long doub
|
||||||
if (part.placeholders.type == format_placeholders::placeholders_type::fractional_part
|
if (part.placeholders.type == format_placeholders::placeholders_type::fractional_part
|
||||||
&& (format.is_datetime || format.is_timedelta))
|
&& (format.is_datetime || format.is_timedelta))
|
||||||
{
|
{
|
||||||
auto digits = std::min(static_cast<std::size_t>(6), part.placeholders.num_zeros + part.placeholders.num_optionals);
|
auto digits = std::min(
|
||||||
|
static_cast<std::size_t>(6), part.placeholders.num_zeros + part.placeholders.num_optionals);
|
||||||
auto denominator = static_cast<int>(std::pow(10.0, digits));
|
auto denominator = static_cast<int>(std::pow(10.0, digits));
|
||||||
auto fractional_seconds = dt.microsecond / 1.0E6L * denominator;
|
auto fractional_seconds = dt.microsecond / 1.0E6L * denominator;
|
||||||
fractional_seconds = std::round(fractional_seconds) / denominator;
|
fractional_seconds = std::round(fractional_seconds) / denominator;
|
||||||
|
@ -1550,9 +1428,11 @@ std::string number_formatter::format_number(const format_code &format, long doub
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
result.append(fill_fraction_placeholders(part.placeholders, format.parts[i].placeholders, number, improper_fraction));
|
result.append(fill_fraction_placeholders(
|
||||||
|
part.placeholders, format.parts[i].placeholders, number, improper_fraction));
|
||||||
}
|
}
|
||||||
else if (part.placeholders.scientific && part.placeholders.type == format_placeholders::placeholders_type::integer_part)
|
else if (part.placeholders.scientific
|
||||||
|
&& part.placeholders.type == format_placeholders::placeholders_type::integer_part)
|
||||||
{
|
{
|
||||||
auto integer_part = part.placeholders;
|
auto integer_part = part.placeholders;
|
||||||
++i;
|
++i;
|
||||||
|
@ -1683,7 +1563,8 @@ std::string number_formatter::format_number(const format_code &format, long doub
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case template_part::template_type::elapsed_seconds:
|
case template_part::template_type::elapsed_seconds:
|
||||||
result.append(std::to_string(24 * 60 * 60 * static_cast<int>(number) + (60 * 60 * dt.hour) + (60 * dt.minute) + dt.second));
|
result.append(std::to_string(
|
||||||
|
24 * 60 * 60 * static_cast<int>(number) + (60 * 60 * dt.hour) + (60 * dt.minute) + dt.second));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case template_part::template_type::month_letter:
|
case template_part::template_type::month_letter:
|
||||||
|
@ -1699,9 +1580,9 @@ std::string number_formatter::format_number(const format_code &format, long doub
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::size_t width = 11;
|
const std::size_t width = 11;
|
||||||
|
|
||||||
if (fill && result.size() < width)
|
if (fill && result.size() < width)
|
||||||
{
|
{
|
||||||
auto remaining = width - result.size();
|
auto remaining = width - result.size();
|
||||||
|
@ -1739,32 +1620,58 @@ std::string number_formatter::format_text(const format_code &format, const std::
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case template_part::template_type::fill: break;
|
case template_part::template_type::fill:
|
||||||
case template_part::template_type::space: break;
|
break;
|
||||||
case template_part::template_type::month_number: break;
|
case template_part::template_type::space:
|
||||||
case template_part::template_type::month_number_leading_zero: break;
|
break;
|
||||||
case template_part::template_type::month_abbreviation: break;
|
case template_part::template_type::month_number:
|
||||||
case template_part::template_type::month_name: break;
|
break;
|
||||||
case template_part::template_type::month_letter: break;
|
case template_part::template_type::month_number_leading_zero:
|
||||||
case template_part::template_type::day_number: break;
|
break;
|
||||||
case template_part::template_type::day_number_leading_zero: break;
|
case template_part::template_type::month_abbreviation:
|
||||||
case template_part::template_type::day_abbreviation: break;
|
break;
|
||||||
case template_part::template_type::day_name: break;
|
case template_part::template_type::month_name:
|
||||||
case template_part::template_type::year_short: break;
|
break;
|
||||||
case template_part::template_type::year_long: break;
|
case template_part::template_type::month_letter:
|
||||||
case template_part::template_type::hour: break;
|
break;
|
||||||
case template_part::template_type::hour_leading_zero: break;
|
case template_part::template_type::day_number:
|
||||||
case template_part::template_type::minute: break;
|
break;
|
||||||
case template_part::template_type::minute_leading_zero: break;
|
case template_part::template_type::day_number_leading_zero:
|
||||||
case template_part::template_type::second: break;
|
break;
|
||||||
case template_part::template_type::second_fractional: break;
|
case template_part::template_type::day_abbreviation:
|
||||||
case template_part::template_type::second_leading_zero: break;
|
break;
|
||||||
case template_part::template_type::second_leading_zero_fractional: break;
|
case template_part::template_type::day_name:
|
||||||
case template_part::template_type::am_pm: break;
|
break;
|
||||||
case template_part::template_type::a_p: break;
|
case template_part::template_type::year_short:
|
||||||
case template_part::template_type::elapsed_hours: break;
|
break;
|
||||||
case template_part::template_type::elapsed_minutes: break;
|
case template_part::template_type::year_long:
|
||||||
case template_part::template_type::elapsed_seconds: break;
|
break;
|
||||||
|
case template_part::template_type::hour:
|
||||||
|
break;
|
||||||
|
case template_part::template_type::hour_leading_zero:
|
||||||
|
break;
|
||||||
|
case template_part::template_type::minute:
|
||||||
|
break;
|
||||||
|
case template_part::template_type::minute_leading_zero:
|
||||||
|
break;
|
||||||
|
case template_part::template_type::second:
|
||||||
|
break;
|
||||||
|
case template_part::template_type::second_fractional:
|
||||||
|
break;
|
||||||
|
case template_part::template_type::second_leading_zero:
|
||||||
|
break;
|
||||||
|
case template_part::template_type::second_leading_zero_fractional:
|
||||||
|
break;
|
||||||
|
case template_part::template_type::am_pm:
|
||||||
|
break;
|
||||||
|
case template_part::template_type::a_p:
|
||||||
|
break;
|
||||||
|
case template_part::template_type::elapsed_hours:
|
||||||
|
break;
|
||||||
|
case template_part::template_type::elapsed_minutes:
|
||||||
|
break;
|
||||||
|
case template_part::template_type::elapsed_seconds:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -31,6 +31,7 @@
|
||||||
#include <detail/worksheet_impl.hpp>
|
#include <detail/worksheet_impl.hpp>
|
||||||
#include <xlnt/packaging/manifest.hpp>
|
#include <xlnt/packaging/manifest.hpp>
|
||||||
#include <xlnt/utils/datetime.hpp>
|
#include <xlnt/utils/datetime.hpp>
|
||||||
|
#include <xlnt/workbook/calculation_properties.hpp>
|
||||||
#include <xlnt/workbook/theme.hpp>
|
#include <xlnt/workbook/theme.hpp>
|
||||||
#include <xlnt/workbook/workbook_view.hpp>
|
#include <xlnt/workbook/workbook_view.hpp>
|
||||||
#include <xlnt/worksheet/range.hpp>
|
#include <xlnt/worksheet/range.hpp>
|
||||||
|
@ -44,7 +45,7 @@ struct worksheet_impl;
|
||||||
|
|
||||||
struct workbook_impl
|
struct workbook_impl
|
||||||
{
|
{
|
||||||
workbook_impl() : active_sheet_index_(0)
|
workbook_impl() : base_date_(calendar::windows_1900)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -111,6 +112,7 @@ struct workbook_impl
|
||||||
};
|
};
|
||||||
|
|
||||||
optional<file_version_t> file_version_;
|
optional<file_version_t> file_version_;
|
||||||
|
optional<calculation_properties> calculation_properties_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
|
|
|
@ -24,18 +24,18 @@
|
||||||
#include <cctype>
|
#include <cctype>
|
||||||
#include <numeric> // for std::accumulate
|
#include <numeric> // for std::accumulate
|
||||||
|
|
||||||
#include <detail/constants.hpp>
|
|
||||||
#include <detail/custom_value_traits.hpp>
|
|
||||||
#include <detail/vector_streambuf.hpp>
|
|
||||||
#include <detail/workbook_impl.hpp>
|
|
||||||
#include <detail/xlsx_consumer.hpp>
|
|
||||||
#include <detail/zip.hpp>
|
|
||||||
#include <xlnt/cell/cell.hpp>
|
#include <xlnt/cell/cell.hpp>
|
||||||
#include <xlnt/packaging/manifest.hpp>
|
#include <xlnt/packaging/manifest.hpp>
|
||||||
#include <xlnt/utils/path.hpp>
|
#include <xlnt/utils/path.hpp>
|
||||||
#include <xlnt/workbook/const_worksheet_iterator.hpp>
|
#include <xlnt/workbook/const_worksheet_iterator.hpp>
|
||||||
#include <xlnt/workbook/workbook.hpp>
|
#include <xlnt/workbook/workbook.hpp>
|
||||||
#include <xlnt/worksheet/worksheet.hpp>
|
#include <xlnt/worksheet/worksheet.hpp>
|
||||||
|
#include <detail/constants.hpp>
|
||||||
|
#include <detail/custom_value_traits.hpp>
|
||||||
|
#include <detail/vector_streambuf.hpp>
|
||||||
|
#include <detail/workbook_impl.hpp>
|
||||||
|
#include <detail/xlsx_consumer.hpp>
|
||||||
|
#include <detail/zip.hpp>
|
||||||
|
|
||||||
namespace std {
|
namespace std {
|
||||||
|
|
||||||
|
@ -245,14 +245,8 @@ std::array<xlnt::optional<xlnt::rich_text>, 3> parse_header_footer(const std::st
|
||||||
tokens.push_back(token);
|
tokens.push_back(token);
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto parse_section = [&tokens,&result](hf_code code)
|
const auto parse_section = [&tokens, &result](hf_code code) {
|
||||||
{
|
std::vector<hf_code> end_codes{hf_code::left_section, hf_code::center_section, hf_code::right_section};
|
||||||
std::vector<hf_code> end_codes
|
|
||||||
{
|
|
||||||
hf_code::left_section,
|
|
||||||
hf_code::center_section,
|
|
||||||
hf_code::right_section
|
|
||||||
};
|
|
||||||
|
|
||||||
end_codes.erase(std::find(end_codes.begin(), end_codes.end(), code));
|
end_codes.erase(std::find(end_codes.begin(), end_codes.end(), code));
|
||||||
|
|
||||||
|
@ -387,39 +381,39 @@ std::array<xlnt::optional<xlnt::rich_text>, 3> parse_header_footer(const std::st
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case hf_code::text_font_name:
|
case hf_code::text_font_name:
|
||||||
|
{
|
||||||
|
auto comma_index = current_token.value.find(',');
|
||||||
|
auto font_name = current_token.value.substr(0, comma_index);
|
||||||
|
|
||||||
|
if (!current_run.second.is_set())
|
||||||
{
|
{
|
||||||
auto comma_index = current_token.value.find(',');
|
current_run.second = xlnt::font();
|
||||||
auto font_name = current_token.value.substr(0, comma_index);
|
|
||||||
|
|
||||||
if (!current_run.second.is_set())
|
|
||||||
{
|
|
||||||
current_run.second = xlnt::font();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (font_name != "-")
|
|
||||||
{
|
|
||||||
current_run.second.get().name(font_name);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (comma_index != std::string::npos)
|
|
||||||
{
|
|
||||||
auto font_type = current_token.value.substr(comma_index + 1);
|
|
||||||
|
|
||||||
if (font_type == "Bold")
|
|
||||||
{
|
|
||||||
current_run.second.get().bold(true);
|
|
||||||
}
|
|
||||||
else if (font_type == "Italic")
|
|
||||||
{
|
|
||||||
}
|
|
||||||
else if (font_type == "BoldItalic")
|
|
||||||
{
|
|
||||||
current_run.second.get().bold(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
if (font_name != "-")
|
||||||
|
{
|
||||||
|
current_run.second.get().name(font_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (comma_index != std::string::npos)
|
||||||
|
{
|
||||||
|
auto font_type = current_token.value.substr(comma_index + 1);
|
||||||
|
|
||||||
|
if (font_type == "Bold")
|
||||||
|
{
|
||||||
|
current_run.second.get().bold(true);
|
||||||
|
}
|
||||||
|
else if (font_type == "Italic")
|
||||||
|
{
|
||||||
|
}
|
||||||
|
else if (font_type == "BoldItalic")
|
||||||
|
{
|
||||||
|
current_run.second.get().bold(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
case hf_code::bold_font_style:
|
case hf_code::bold_font_style:
|
||||||
if (!current_run.second.is_set())
|
if (!current_run.second.is_set())
|
||||||
|
@ -445,8 +439,8 @@ std::array<xlnt::optional<xlnt::rich_text>, 3> parse_header_footer(const std::st
|
||||||
current_text.add_run(current_run);
|
current_text.add_run(current_run);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto location_index = static_cast<std::size_t>(code == hf_code::left_section ? 0
|
auto location_index =
|
||||||
: code == hf_code::center_section ? 1 : 2);
|
static_cast<std::size_t>(code == hf_code::left_section ? 0 : code == hf_code::center_section ? 1 : 2);
|
||||||
|
|
||||||
if (!current_text.plain_text().empty())
|
if (!current_text.plain_text().empty())
|
||||||
{
|
{
|
||||||
|
@ -501,7 +495,7 @@ bool is_true(const std::string &bool_string)
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Helper template function that returns true if element is in container.
|
/// Helper template function that returns true if element is in container.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
template<typename T>
|
template <typename T>
|
||||||
bool contains(const std::vector<T> &container, const T &element)
|
bool contains(const std::vector<T> &container, const T &element)
|
||||||
{
|
{
|
||||||
return std::find(container.begin(), container.end(), element) != container.end();
|
return std::find(container.begin(), container.end(), element) != container.end();
|
||||||
|
@ -513,7 +507,7 @@ bool contains(const std::vector<T> &container, const T &element)
|
||||||
class parsing_context
|
class parsing_context
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
parsing_context(xlnt::detail::ZipFileReader &archive, const std::string &filename)
|
parsing_context(xlnt::detail::zip_file_reader &archive, const std::string &filename)
|
||||||
: parser_(stream_, filename)
|
: parser_(stream_, filename)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -530,14 +524,13 @@ namespace xlnt {
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
|
||||||
xlsx_consumer::xlsx_consumer(workbook &target)
|
xlsx_consumer::xlsx_consumer(workbook &target)
|
||||||
: target_(target),
|
: target_(target), parser_(nullptr)
|
||||||
parser_(nullptr)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void xlsx_consumer::read(std::istream &source)
|
void xlsx_consumer::read(std::istream &source)
|
||||||
{
|
{
|
||||||
archive_.reset(new ZipFileReader(source));
|
archive_.reset(new zip_file_reader(source));
|
||||||
populate_workbook();
|
populate_workbook();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -548,15 +541,13 @@ xml::parser &xlsx_consumer::parser()
|
||||||
|
|
||||||
std::vector<relationship> xlsx_consumer::read_relationships(const path &part)
|
std::vector<relationship> xlsx_consumer::read_relationships(const path &part)
|
||||||
{
|
{
|
||||||
auto part_rels_path = part.parent()
|
auto part_rels_path = part.parent().append("_rels").append(part.filename() + ".rels").relative_to(path("/"));
|
||||||
.append("_rels")
|
|
||||||
.append(part.filename() + ".rels")
|
|
||||||
.relative_to(path("/"));
|
|
||||||
|
|
||||||
std::vector<xlnt::relationship> relationships;
|
std::vector<xlnt::relationship> relationships;
|
||||||
if (!archive_->has_file(part_rels_path.string())) return relationships;
|
if (!archive_->has_file(part_rels_path)) return relationships;
|
||||||
|
|
||||||
auto &rels_stream = archive_->open(part_rels_path.string());
|
auto rels_streambuf = archive_->open(part_rels_path);
|
||||||
|
std::istream rels_stream(rels_streambuf.get());
|
||||||
xml::parser parser(rels_stream, part_rels_path.string());
|
xml::parser parser(rels_stream, part_rels_path.string());
|
||||||
parser_ = &parser;
|
parser_ = &parser;
|
||||||
|
|
||||||
|
@ -577,33 +568,25 @@ std::vector<relationship> xlsx_consumer::read_relationships(const path &part)
|
||||||
target_mode = parser.attribute<xlnt::target_mode>("TargetMode");
|
target_mode = parser.attribute<xlnt::target_mode>("TargetMode");
|
||||||
}
|
}
|
||||||
|
|
||||||
relationships.emplace_back(parser.attribute("Id"),
|
relationships.emplace_back(parser.attribute("Id"), parser.attribute<xlnt::relationship_type>("Type"), source,
|
||||||
parser.attribute<xlnt::relationship_type>("Type"), source,
|
xlnt::uri(parser.attribute("Target")), target_mode);
|
||||||
xlnt::uri(parser.attribute("Target")),
|
|
||||||
target_mode);
|
|
||||||
|
|
||||||
expect_end_element(xml::qname(xmlns, "Relationship"));
|
expect_end_element(xml::qname(xmlns, "Relationship"));
|
||||||
}
|
}
|
||||||
|
|
||||||
expect_end_element(xml::qname(xmlns, "Relationships"));
|
expect_end_element(xml::qname(xmlns, "Relationships"));
|
||||||
|
|
||||||
parser_ = nullptr;
|
parser_ = nullptr;
|
||||||
|
|
||||||
return relationships;
|
return relationships;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void xlsx_consumer::read_part(const std::vector<relationship> &rel_chain)
|
void xlsx_consumer::read_part(const std::vector<relationship> &rel_chain)
|
||||||
{
|
{
|
||||||
// ignore namespace declarations except in parts of these types
|
// ignore namespace declarations except in parts of these types
|
||||||
const auto using_namespaces = std::vector<relationship_type>
|
const auto using_namespaces =
|
||||||
{
|
std::vector<relationship_type>{relationship_type::office_document, relationship_type::stylesheet,
|
||||||
relationship_type::office_document,
|
relationship_type::chartsheet, relationship_type::dialogsheet, relationship_type::worksheet};
|
||||||
relationship_type::stylesheet,
|
|
||||||
relationship_type::chartsheet,
|
|
||||||
relationship_type::dialogsheet,
|
|
||||||
relationship_type::worksheet
|
|
||||||
};
|
|
||||||
|
|
||||||
auto receive = xml::parser::receive_default;
|
auto receive = xml::parser::receive_default;
|
||||||
|
|
||||||
|
@ -614,8 +597,9 @@ void xlsx_consumer::read_part(const std::vector<relationship> &rel_chain)
|
||||||
|
|
||||||
const auto &manifest = target_.manifest();
|
const auto &manifest = target_.manifest();
|
||||||
auto part_path = manifest.canonicalize(rel_chain);
|
auto part_path = manifest.canonicalize(rel_chain);
|
||||||
auto &stream = archive_->open(part_path.string());
|
auto part_streambuf = archive_->open(part_path);
|
||||||
xml::parser parser(stream, part_path.string(), receive);
|
std::istream part_stream(part_streambuf.get());
|
||||||
|
xml::parser parser(part_stream, part_path.string(), receive);
|
||||||
parser_ = &parser;
|
parser_ = &parser;
|
||||||
|
|
||||||
switch (rel_chain.back().type())
|
switch (rel_chain.back().type())
|
||||||
|
@ -792,7 +776,9 @@ void xlsx_consumer::read_content_types()
|
||||||
|
|
||||||
static const auto &xmlns = constants::namespace_("content-types");
|
static const auto &xmlns = constants::namespace_("content-types");
|
||||||
|
|
||||||
xml::parser parser(archive_->open("[Content_Types].xml"), "[Content_Types].xml");
|
auto content_types_streambuf = archive_->open(path("[Content_Types].xml"));
|
||||||
|
std::istream content_types_stream(content_types_streambuf.get());
|
||||||
|
xml::parser parser(content_types_stream, "[Content_Types].xml");
|
||||||
parser_ = &parser;
|
parser_ = &parser;
|
||||||
|
|
||||||
expect_start_element(xml::qname(xmlns, "Types"), xml::content::complex);
|
expect_start_element(xml::qname(xmlns, "Types"), xml::content::complex);
|
||||||
|
@ -854,8 +840,8 @@ void xlsx_consumer::read_office_document(const std::string &content_type) // CT_
|
||||||
static const auto &xmlns_r = constants::namespace_("r");
|
static const auto &xmlns_r = constants::namespace_("r");
|
||||||
static const auto &xmlns_s = constants::namespace_("spreadsheetml");
|
static const auto &xmlns_s = constants::namespace_("spreadsheetml");
|
||||||
|
|
||||||
if (content_type != "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml" &&
|
if (content_type != "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml"
|
||||||
content_type != "application/vnd.openxmlformats-officedocument.spreadsheetml.template.main+xml")
|
&& content_type != "application/vnd.openxmlformats-officedocument.spreadsheetml.template.main+xml")
|
||||||
{
|
{
|
||||||
throw xlnt::invalid_file(content_type);
|
throw xlnt::invalid_file(content_type);
|
||||||
}
|
}
|
||||||
|
@ -904,12 +890,12 @@ void xlsx_consumer::read_office_document(const std::string &content_type) // CT_
|
||||||
{
|
{
|
||||||
if (parser().attribute_present("date1904"))
|
if (parser().attribute_present("date1904"))
|
||||||
{
|
{
|
||||||
target_.base_date(is_true(parser().attribute("date1904"))
|
target_.base_date(
|
||||||
? calendar::mac_1904 : calendar::windows_1900);
|
is_true(parser().attribute("date1904")) ? calendar::mac_1904 : calendar::windows_1900);
|
||||||
}
|
}
|
||||||
|
|
||||||
skip_attributes({"codeName", "defaultThemeVersion",
|
skip_attributes(
|
||||||
"backupFile", "showObjects", "filterPrivacy", "dateCompatibility"});
|
{"codeName", "defaultThemeVersion", "backupFile", "showObjects", "filterPrivacy", "dateCompatibility"});
|
||||||
}
|
}
|
||||||
else if (current_workbook_element == xml::qname(xmlns, "workbookProtection")) // CT_WorkbookProtection 0-1
|
else if (current_workbook_element == xml::qname(xmlns, "workbookProtection")) // CT_WorkbookProtection 0-1
|
||||||
{
|
{
|
||||||
|
@ -921,8 +907,8 @@ void xlsx_consumer::read_office_document(const std::string &content_type) // CT_
|
||||||
{
|
{
|
||||||
expect_start_element(xml::qname(xmlns, "workbookView"), xml::content::simple);
|
expect_start_element(xml::qname(xmlns, "workbookView"), xml::content::simple);
|
||||||
|
|
||||||
skip_attributes({"activeTab", "firstSheet", "showHorizontalScroll",
|
skip_attributes(
|
||||||
"showSheetTabs", "showVerticalScroll"});
|
{"activeTab", "firstSheet", "showHorizontalScroll", "showSheetTabs", "showVerticalScroll"});
|
||||||
|
|
||||||
workbook_view view;
|
workbook_view view;
|
||||||
view.x_window = parser().attribute<std::size_t>("xWindow");
|
view.x_window = parser().attribute<std::size_t>("xWindow");
|
||||||
|
@ -1141,9 +1127,9 @@ void xlsx_consumer::read_stylesheet()
|
||||||
|
|
||||||
target_.impl().stylesheet_ = detail::stylesheet();
|
target_.impl().stylesheet_ = detail::stylesheet();
|
||||||
auto &stylesheet = target_.impl().stylesheet_.get();
|
auto &stylesheet = target_.impl().stylesheet_.get();
|
||||||
|
|
||||||
//todo: should this really be defined here?
|
// todo: should this really be defined here?
|
||||||
//todo: maybe xlnt::style and xlnt::format can be used here instead now
|
// todo: maybe xlnt::style and xlnt::format can be used here instead now
|
||||||
struct formatting_record
|
struct formatting_record
|
||||||
{
|
{
|
||||||
std::pair<class alignment, bool> alignment = {{}, 0};
|
std::pair<class alignment, bool> alignment = {{}, 0};
|
||||||
|
@ -1503,8 +1489,8 @@ void xlsx_consumer::read_stylesheet()
|
||||||
throw xlnt::exception("counts don't match");
|
throw xlnt::exception("counts don't match");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (current_style_element == xml::qname(xmlns, "cellStyleXfs") ||
|
else if (current_style_element == xml::qname(xmlns, "cellStyleXfs")
|
||||||
current_style_element == xml::qname(xmlns, "cellXfs"))
|
|| current_style_element == xml::qname(xmlns, "cellXfs"))
|
||||||
{
|
{
|
||||||
auto in_style_records = current_style_element.name() == "cellStyleXfs";
|
auto in_style_records = current_style_element.name() == "cellStyleXfs";
|
||||||
auto count = parser().attribute<std::size_t>("count");
|
auto count = parser().attribute<std::size_t>("count");
|
||||||
|
@ -1513,42 +1499,35 @@ void xlsx_consumer::read_stylesheet()
|
||||||
{
|
{
|
||||||
expect_start_element(xml::qname(xmlns, "xf"), xml::content::complex);
|
expect_start_element(xml::qname(xmlns, "xf"), xml::content::complex);
|
||||||
|
|
||||||
auto &record = *(!in_style_records
|
auto &record = *(!in_style_records ? format_records.emplace(format_records.end())
|
||||||
? format_records.emplace(format_records.end())
|
: style_records.emplace(style_records.end()));
|
||||||
: style_records.emplace(style_records.end()));
|
|
||||||
|
|
||||||
auto apply_alignment_present = parser().attribute_present("applyAlignment");
|
auto apply_alignment_present = parser().attribute_present("applyAlignment");
|
||||||
auto alignment_applied = apply_alignment_present
|
auto alignment_applied = apply_alignment_present && is_true(parser().attribute("applyAlignment"));
|
||||||
&& is_true(parser().attribute("applyAlignment"));
|
|
||||||
record.alignment.second = alignment_applied;
|
record.alignment.second = alignment_applied;
|
||||||
|
|
||||||
auto border_applied = parser().attribute_present("applyBorder")
|
auto border_applied =
|
||||||
&& is_true(parser().attribute("applyBorder"));
|
parser().attribute_present("applyBorder") && is_true(parser().attribute("applyBorder"));
|
||||||
auto border_index = parser().attribute_present("borderId")
|
auto border_index =
|
||||||
? parser().attribute<std::size_t>("borderId") : 0;
|
parser().attribute_present("borderId") ? parser().attribute<std::size_t>("borderId") : 0;
|
||||||
record.border_id = {border_index, border_applied};
|
record.border_id = {border_index, border_applied};
|
||||||
|
|
||||||
auto fill_applied = parser().attribute_present("applyFill")
|
auto fill_applied = parser().attribute_present("applyFill") && is_true(parser().attribute("applyFill"));
|
||||||
&& is_true(parser().attribute("applyFill"));
|
auto fill_index = parser().attribute_present("fillId") ? parser().attribute<std::size_t>("fillId") : 0;
|
||||||
auto fill_index = parser().attribute_present("fillId")
|
|
||||||
? parser().attribute<std::size_t>("fillId") : 0;
|
|
||||||
record.fill_id = {fill_index, fill_applied};
|
record.fill_id = {fill_index, fill_applied};
|
||||||
|
|
||||||
auto font_applied = parser().attribute_present("applyFont")
|
auto font_applied = parser().attribute_present("applyFont") && is_true(parser().attribute("applyFont"));
|
||||||
&& is_true(parser().attribute("applyFont"));
|
auto font_index = parser().attribute_present("fontId") ? parser().attribute<std::size_t>("fontId") : 0;
|
||||||
auto font_index = parser().attribute_present("fontId")
|
|
||||||
? parser().attribute<std::size_t>("fontId") : 0;
|
|
||||||
record.font_id = {font_index, font_applied};
|
record.font_id = {font_index, font_applied};
|
||||||
|
|
||||||
auto number_format_applied = parser().attribute_present("applyNumberFormat")
|
auto number_format_applied =
|
||||||
&& is_true(parser().attribute("applyNumberFormat"));
|
parser().attribute_present("applyNumberFormat") && is_true(parser().attribute("applyNumberFormat"));
|
||||||
auto number_format_id = parser().attribute_present("numFmtId")
|
auto number_format_id =
|
||||||
? parser().attribute<std::size_t>("numFmtId") : 0;
|
parser().attribute_present("numFmtId") ? parser().attribute<std::size_t>("numFmtId") : 0;
|
||||||
record.number_format_id = {number_format_id, number_format_applied};
|
record.number_format_id = {number_format_id, number_format_applied};
|
||||||
|
|
||||||
auto apply_protection_present = parser().attribute_present("applyProtection");
|
auto apply_protection_present = parser().attribute_present("applyProtection");
|
||||||
auto protection_applied = apply_protection_present
|
auto protection_applied = apply_protection_present && is_true(parser().attribute("applyProtection"));
|
||||||
&& is_true(parser().attribute("applyProtection"));
|
|
||||||
record.protection.second = protection_applied;
|
record.protection.second = protection_applied;
|
||||||
|
|
||||||
if (parser().attribute_present("xfId") && parser().name() == "cellXfs")
|
if (parser().attribute_present("xfId") && parser().name() == "cellXfs")
|
||||||
|
@ -1617,8 +1596,8 @@ void xlsx_consumer::read_stylesheet()
|
||||||
expect_end_element(xml::qname(xmlns, "xf"));
|
expect_end_element(xml::qname(xmlns, "xf"));
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((in_style_records && count != style_records.size()) ||
|
if ((in_style_records && count != style_records.size())
|
||||||
(!in_style_records && count != format_records.size()))
|
|| (!in_style_records && count != format_records.size()))
|
||||||
{
|
{
|
||||||
throw xlnt::exception("counts don't match");
|
throw xlnt::exception("counts don't match");
|
||||||
}
|
}
|
||||||
|
@ -1632,7 +1611,7 @@ void xlsx_consumer::read_stylesheet()
|
||||||
{
|
{
|
||||||
auto current_element = expect_start_element(xml::content::complex);
|
auto current_element = expect_start_element(xml::content::complex);
|
||||||
skip_remaining_content(current_element);
|
skip_remaining_content(current_element);
|
||||||
|
|
||||||
++processed;
|
++processed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1703,8 +1682,7 @@ void xlsx_consumer::read_stylesheet()
|
||||||
|
|
||||||
expect_end_element(xml::qname(xmlns, "styleSheet"));
|
expect_end_element(xml::qname(xmlns, "styleSheet"));
|
||||||
|
|
||||||
auto lookup_number_format = [&](std::size_t number_format_id)
|
auto lookup_number_format = [&](std::size_t number_format_id) {
|
||||||
{
|
|
||||||
auto result = number_format::general();
|
auto result = number_format::general();
|
||||||
bool is_custom_number_format = false;
|
bool is_custom_number_format = false;
|
||||||
|
|
||||||
|
@ -1730,8 +1708,8 @@ void xlsx_consumer::read_stylesheet()
|
||||||
|
|
||||||
for (const auto &record : style_records)
|
for (const auto &record : style_records)
|
||||||
{
|
{
|
||||||
auto style_data_iter = std::find_if(style_datas.begin(), style_datas.end(),
|
auto style_data_iter = std::find_if(
|
||||||
[&xf_id](const style_data &s) { return s.record_id == xf_id; });
|
style_datas.begin(), style_datas.end(), [&xf_id](const style_data &s) { return s.record_id == xf_id; });
|
||||||
++xf_id;
|
++xf_id;
|
||||||
|
|
||||||
if (style_data_iter == style_datas.end()) continue;
|
if (style_data_iter == style_datas.end()) continue;
|
||||||
|
@ -1814,16 +1792,16 @@ void xlsx_consumer::read_worksheet(const std::string &rel_id)
|
||||||
static const auto &xmlns_x14ac = constants::namespace_("x14ac");
|
static const auto &xmlns_x14ac = constants::namespace_("x14ac");
|
||||||
static const auto &xmlns_r = constants::namespace_("r");
|
static const auto &xmlns_r = constants::namespace_("r");
|
||||||
|
|
||||||
auto title = std::find_if(target_.d_->sheet_title_rel_id_map_.begin(),
|
auto title = std::find_if(target_.d_->sheet_title_rel_id_map_.begin(), target_.d_->sheet_title_rel_id_map_.end(),
|
||||||
target_.d_->sheet_title_rel_id_map_.end(),
|
[&](const std::pair<std::string, std::string> &p) {
|
||||||
[&](const std::pair<std::string, std::string> &p) { return p.second == rel_id; })->first;
|
return p.second == rel_id;
|
||||||
|
})->first;
|
||||||
|
|
||||||
auto id = sheet_title_id_map_[title];
|
auto id = sheet_title_id_map_[title];
|
||||||
auto index = sheet_title_index_map_[title];
|
auto index = sheet_title_index_map_[title];
|
||||||
|
|
||||||
auto insertion_iter = target_.d_->worksheets_.begin();
|
auto insertion_iter = target_.d_->worksheets_.begin();
|
||||||
while (insertion_iter != target_.d_->worksheets_.end()
|
while (insertion_iter != target_.d_->worksheets_.end() && sheet_title_index_map_[insertion_iter->title_] < index)
|
||||||
&& sheet_title_index_map_[insertion_iter->title_] < index)
|
|
||||||
{
|
{
|
||||||
++insertion_iter;
|
++insertion_iter;
|
||||||
}
|
}
|
||||||
|
@ -1915,22 +1893,22 @@ void xlsx_consumer::read_worksheet(const std::string &rel_id)
|
||||||
|
|
||||||
if (parser().attribute_present("view") && parser().attribute("view") != "normal")
|
if (parser().attribute_present("view") && parser().attribute("view") != "normal")
|
||||||
{
|
{
|
||||||
new_view.type(parser().attribute("view") == "pageBreakPreview" ?sheet_view_type::page_break_preview : sheet_view_type::page_layout);
|
new_view.type(parser().attribute("view") == "pageBreakPreview" ? sheet_view_type::page_break_preview
|
||||||
|
: sheet_view_type::page_layout);
|
||||||
}
|
}
|
||||||
|
|
||||||
skip_attributes({"windowProtection", "showFormulas", "showRowColHeaders", "showZeros",
|
skip_attributes({"windowProtection", "showFormulas", "showRowColHeaders", "showZeros", "rightToLeft",
|
||||||
"rightToLeft", "tabSelected", "showRuler", "showOutlineSymbols", "showWhiteSpace", "view",
|
"tabSelected", "showRuler", "showOutlineSymbols", "showWhiteSpace", "view", "topLeftCell",
|
||||||
"topLeftCell", "colorId", "zoomScale", "zoomScaleNormal", "zoomScaleSheetLayoutView",
|
"colorId", "zoomScale", "zoomScaleNormal", "zoomScaleSheetLayoutView", "zoomScalePageLayoutView"});
|
||||||
"zoomScalePageLayoutView"});
|
|
||||||
|
|
||||||
while (in_element(xml::qname(xmlns, "sheetView")))
|
while (in_element(xml::qname(xmlns, "sheetView")))
|
||||||
{
|
{
|
||||||
auto sheet_view_child_element = expect_start_element(xml::content::simple);
|
auto sheet_view_child_element = expect_start_element(xml::content::simple);
|
||||||
|
|
||||||
if (sheet_view_child_element == xml::qname(xmlns, "pane")) // CT_Pane 0-1
|
if (sheet_view_child_element == xml::qname(xmlns, "pane")) // CT_Pane 0-1
|
||||||
{
|
{
|
||||||
pane new_pane;
|
pane new_pane;
|
||||||
|
|
||||||
if (parser().attribute_present("topLeftCell"))
|
if (parser().attribute_present("topLeftCell"))
|
||||||
{
|
{
|
||||||
new_pane.top_left_cell = cell_reference(parser().attribute("topLeftCell"));
|
new_pane.top_left_cell = cell_reference(parser().attribute("topLeftCell"));
|
||||||
|
@ -2006,16 +1984,15 @@ void xlsx_consumer::read_worksheet(const std::string &rel_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
optional<std::size_t> column_style;
|
optional<std::size_t> column_style;
|
||||||
|
|
||||||
if (parser().attribute_present("style"))
|
if (parser().attribute_present("style"))
|
||||||
{
|
{
|
||||||
column_style = parser().attribute<std::size_t>("style");
|
column_style = parser().attribute<std::size_t>("style");
|
||||||
}
|
}
|
||||||
|
|
||||||
auto custom = parser().attribute_present("customWidth")
|
auto custom =
|
||||||
? is_true(parser().attribute("customWidth")) : false;
|
parser().attribute_present("customWidth") ? is_true(parser().attribute("customWidth")) : false;
|
||||||
auto hidden = parser().attribute_present("hidden")
|
auto hidden = parser().attribute_present("hidden") ? is_true(parser().attribute("hidden")) : false;
|
||||||
? is_true(parser().attribute("hidden")) : false;
|
|
||||||
|
|
||||||
expect_end_element(xml::qname(xmlns, "col"));
|
expect_end_element(xml::qname(xmlns, "col"));
|
||||||
|
|
||||||
|
@ -2062,8 +2039,8 @@ void xlsx_consumer::read_worksheet(const std::string &rel_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
skip_attributes({xml::qname(xmlns_x14ac, "dyDescent")});
|
skip_attributes({xml::qname(xmlns_x14ac, "dyDescent")});
|
||||||
skip_attributes({"customFormat", "s", "customFont", "outlineLevel",
|
skip_attributes({"customFormat", "s", "customFont", "outlineLevel", "collapsed", "thickTop", "thickBot",
|
||||||
"collapsed", "thickTop", "thickBot", "ph", "spans"});
|
"ph", "spans"});
|
||||||
|
|
||||||
while (in_element(xml::qname(xmlns, "row")))
|
while (in_element(xml::qname(xmlns, "row")))
|
||||||
{
|
{
|
||||||
|
@ -2086,7 +2063,7 @@ void xlsx_consumer::read_worksheet(const std::string &rel_id)
|
||||||
while (in_element(xml::qname(xmlns, "c")))
|
while (in_element(xml::qname(xmlns, "c")))
|
||||||
{
|
{
|
||||||
auto current_element = expect_start_element(xml::content::mixed);
|
auto current_element = expect_start_element(xml::content::mixed);
|
||||||
|
|
||||||
if (current_element == xml::qname(xmlns, "v")) // s:ST_Xstring
|
if (current_element == xml::qname(xmlns, "v")) // s:ST_Xstring
|
||||||
{
|
{
|
||||||
has_value = true;
|
has_value = true;
|
||||||
|
@ -2101,8 +2078,8 @@ void xlsx_consumer::read_worksheet(const std::string &rel_id)
|
||||||
has_shared_formula = parser().attribute("t") == "shared";
|
has_shared_formula = parser().attribute("t") == "shared";
|
||||||
}
|
}
|
||||||
|
|
||||||
skip_attributes({"aca", "ref", "dt2D", "dtr", "del1", "del2",
|
skip_attributes(
|
||||||
"r1", "r2", "ca", "si", "bx"});
|
{"aca", "ref", "dt2D", "dtr", "del1", "del2", "r1", "r2", "ca", "si", "bx"});
|
||||||
|
|
||||||
formula_value_string = read_text();
|
formula_value_string = read_text();
|
||||||
}
|
}
|
||||||
|
@ -2270,14 +2247,14 @@ void xlsx_consumer::read_worksheet(const std::string &rel_id)
|
||||||
{
|
{
|
||||||
header_footer hf;
|
header_footer hf;
|
||||||
|
|
||||||
hf.align_with_margins(!parser().attribute_present("alignWithMargins")
|
hf.align_with_margins(
|
||||||
|| is_true(parser().attribute("alignWithMargins")));
|
!parser().attribute_present("alignWithMargins") || is_true(parser().attribute("alignWithMargins")));
|
||||||
hf.scale_with_doc(!parser().attribute_present("alignWithMargins")
|
hf.scale_with_doc(
|
||||||
|| is_true(parser().attribute("alignWithMargins")));
|
!parser().attribute_present("alignWithMargins") || is_true(parser().attribute("alignWithMargins")));
|
||||||
auto different_odd_even = parser().attribute_present("differentOddEven")
|
auto different_odd_even =
|
||||||
&& is_true(parser().attribute("differentOddEven"));
|
parser().attribute_present("differentOddEven") && is_true(parser().attribute("differentOddEven"));
|
||||||
auto different_first = parser().attribute_present("differentFirst")
|
auto different_first =
|
||||||
&& is_true(parser().attribute("differentFirst"));
|
parser().attribute_present("differentFirst") && is_true(parser().attribute("differentFirst"));
|
||||||
|
|
||||||
optional<std::array<optional<rich_text>, 3>> odd_header;
|
optional<std::array<optional<rich_text>, 3>> odd_header;
|
||||||
optional<std::array<optional<rich_text>, 3>> odd_footer;
|
optional<std::array<optional<rich_text>, 3>> odd_footer;
|
||||||
|
@ -2325,19 +2302,18 @@ void xlsx_consumer::read_worksheet(const std::string &rel_id)
|
||||||
for (std::size_t i = 0; i < 3; ++i)
|
for (std::size_t i = 0; i < 3; ++i)
|
||||||
{
|
{
|
||||||
auto loc = i == 0 ? header_footer::location::left
|
auto loc = i == 0 ? header_footer::location::left
|
||||||
: i == 1 ? header_footer::location::center
|
: i == 1 ? header_footer::location::center : header_footer::location::right;
|
||||||
: header_footer::location::right;
|
|
||||||
|
|
||||||
if (different_odd_even)
|
if (different_odd_even)
|
||||||
{
|
{
|
||||||
if (odd_header.is_set() && odd_header.get().at(i).is_set()
|
if (odd_header.is_set() && odd_header.get().at(i).is_set() && even_header.is_set()
|
||||||
&& even_header.is_set() && even_header.get().at(i).is_set())
|
&& even_header.get().at(i).is_set())
|
||||||
{
|
{
|
||||||
hf.odd_even_header(loc, odd_header.get().at(i).get(), even_header.get().at(i).get());
|
hf.odd_even_header(loc, odd_header.get().at(i).get(), even_header.get().at(i).get());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (odd_footer.is_set() && odd_footer.get().at(i).is_set()
|
if (odd_footer.is_set() && odd_footer.get().at(i).is_set() && even_footer.is_set()
|
||||||
&& even_footer.is_set() && even_footer.get().at(i).is_set())
|
&& even_footer.get().at(i).is_set())
|
||||||
{
|
{
|
||||||
hf.odd_even_footer(loc, odd_footer.get().at(i).get(), even_footer.get().at(i).get());
|
hf.odd_even_footer(loc, odd_footer.get().at(i).get(), even_footer.get().at(i).get());
|
||||||
}
|
}
|
||||||
|
@ -2357,7 +2333,6 @@ void xlsx_consumer::read_worksheet(const std::string &rel_id)
|
||||||
|
|
||||||
if (different_first)
|
if (different_first)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2366,7 +2341,9 @@ void xlsx_consumer::read_worksheet(const std::string &rel_id)
|
||||||
else if (current_worksheet_element == xml::qname(xmlns, "rowBreaks")) // CT_PageBreak 0-1
|
else if (current_worksheet_element == xml::qname(xmlns, "rowBreaks")) // CT_PageBreak 0-1
|
||||||
{
|
{
|
||||||
auto count = parser().attribute_present("count") ? parser().attribute<std::size_t>("count") : 0;
|
auto count = parser().attribute_present("count") ? parser().attribute<std::size_t>("count") : 0;
|
||||||
auto manual_break_count = parser().attribute_present("manualBreakCount") ? parser().attribute<std::size_t>("manualBreakCount") : 0;
|
auto manual_break_count = parser().attribute_present("manualBreakCount")
|
||||||
|
? parser().attribute<std::size_t>("manualBreakCount")
|
||||||
|
: 0;
|
||||||
|
|
||||||
while (in_element(xml::qname(xmlns, "rowBreaks")))
|
while (in_element(xml::qname(xmlns, "rowBreaks")))
|
||||||
{
|
{
|
||||||
|
@ -2374,7 +2351,7 @@ void xlsx_consumer::read_worksheet(const std::string &rel_id)
|
||||||
|
|
||||||
if (parser().attribute_present("id"))
|
if (parser().attribute_present("id"))
|
||||||
{
|
{
|
||||||
ws.row_breaks().push_back(parser().attribute<row_t>("id"));
|
ws.page_break_at_row(parser().attribute<row_t>("id"));
|
||||||
--count;
|
--count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2382,7 +2359,7 @@ void xlsx_consumer::read_worksheet(const std::string &rel_id)
|
||||||
{
|
{
|
||||||
--manual_break_count;
|
--manual_break_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
skip_attributes({"min", "max", "pt"});
|
skip_attributes({"min", "max", "pt"});
|
||||||
expect_end_element(xml::qname(xmlns, "brk"));
|
expect_end_element(xml::qname(xmlns, "brk"));
|
||||||
}
|
}
|
||||||
|
@ -2390,7 +2367,9 @@ void xlsx_consumer::read_worksheet(const std::string &rel_id)
|
||||||
else if (current_worksheet_element == xml::qname(xmlns, "colBreaks")) // CT_PageBreak 0-1
|
else if (current_worksheet_element == xml::qname(xmlns, "colBreaks")) // CT_PageBreak 0-1
|
||||||
{
|
{
|
||||||
auto count = parser().attribute_present("count") ? parser().attribute<std::size_t>("count") : 0;
|
auto count = parser().attribute_present("count") ? parser().attribute<std::size_t>("count") : 0;
|
||||||
auto manual_break_count = parser().attribute_present("manualBreakCount") ? parser().attribute<std::size_t>("manualBreakCount") : 0;
|
auto manual_break_count = parser().attribute_present("manualBreakCount")
|
||||||
|
? parser().attribute<std::size_t>("manualBreakCount")
|
||||||
|
: 0;
|
||||||
|
|
||||||
while (in_element(xml::qname(xmlns, "colBreaks")))
|
while (in_element(xml::qname(xmlns, "colBreaks")))
|
||||||
{
|
{
|
||||||
|
@ -2398,7 +2377,7 @@ void xlsx_consumer::read_worksheet(const std::string &rel_id)
|
||||||
|
|
||||||
if (parser().attribute_present("id"))
|
if (parser().attribute_present("id"))
|
||||||
{
|
{
|
||||||
ws.column_breaks().push_back(parser().attribute<column_t::index_t>("id"));
|
ws.page_break_at_column(parser().attribute<column_t::index_t>("id"));
|
||||||
--count;
|
--count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2455,17 +2434,21 @@ void xlsx_consumer::read_worksheet(const std::string &rel_id)
|
||||||
{workbook_rel, sheet_rel, manifest.relationship(sheet_path, xlnt::relationship_type::comments)});
|
{workbook_rel, sheet_rel, manifest.relationship(sheet_path, xlnt::relationship_type::comments)});
|
||||||
|
|
||||||
auto receive = xml::parser::receive_default;
|
auto receive = xml::parser::receive_default;
|
||||||
xml::parser parser(archive_->open(comments_part.string()), comments_part.string(), receive);
|
auto comments_part_streambuf = archive_->open(comments_part);
|
||||||
|
std::istream comments_part_stream(comments_part_streambuf.get());
|
||||||
|
xml::parser parser(comments_part_stream, comments_part.string(), receive);
|
||||||
parser_ = &parser;
|
parser_ = &parser;
|
||||||
|
|
||||||
read_comments(ws);
|
read_comments(ws);
|
||||||
|
|
||||||
if (manifest.has_relationship(sheet_path, xlnt::relationship_type::vml_drawing))
|
if (manifest.has_relationship(sheet_path, xlnt::relationship_type::vml_drawing))
|
||||||
{
|
{
|
||||||
auto vml_drawings_part = manifest.canonicalize({workbook_rel, sheet_rel,
|
auto vml_drawings_part = manifest.canonicalize(
|
||||||
manifest.relationship(sheet_path, xlnt::relationship_type::vml_drawing)});
|
{workbook_rel, sheet_rel, manifest.relationship(sheet_path, xlnt::relationship_type::vml_drawing)});
|
||||||
|
|
||||||
xml::parser vml_parser(archive_->open(vml_drawings_part.string()), vml_drawings_part.string(), receive);
|
auto vml_drawings_part_streambuf = archive_->open(comments_part);
|
||||||
|
std::istream vml_drawings_part_stream(comments_part_streambuf.get());
|
||||||
|
xml::parser vml_parser(vml_drawings_part_stream, vml_drawings_part.string(), receive);
|
||||||
parser_ = &vml_parser;
|
parser_ = &vml_parser;
|
||||||
|
|
||||||
read_vml_drawings(ws);
|
read_vml_drawings(ws);
|
||||||
|
@ -2475,7 +2458,7 @@ void xlsx_consumer::read_worksheet(const std::string &rel_id)
|
||||||
|
|
||||||
// Sheet Relationship Target Parts
|
// Sheet Relationship Target Parts
|
||||||
|
|
||||||
void xlsx_consumer::read_vml_drawings(worksheet/*ws*/)
|
void xlsx_consumer::read_vml_drawings(worksheet /*ws*/)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2533,10 +2516,10 @@ void xlsx_consumer::read_unknown_relationships()
|
||||||
|
|
||||||
void xlsx_consumer::read_image(const xlnt::path &image_path)
|
void xlsx_consumer::read_image(const xlnt::path &image_path)
|
||||||
{
|
{
|
||||||
auto &in_stream = archive_->open(image_path.string());
|
auto image_streambuf = archive_->open(image_path);
|
||||||
vector_ostreambuf buffer(target_.d_->images_[image_path.string()]);
|
vector_ostreambuf buffer(target_.d_->images_[image_path.string()]);
|
||||||
std::ostream out_stream(&buffer);
|
std::ostream out_stream(&buffer);
|
||||||
out_stream << in_stream.rdbuf();
|
out_stream << image_streambuf.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string xlsx_consumer::read_text()
|
std::string xlsx_consumer::read_text()
|
||||||
|
@ -2648,8 +2631,7 @@ xml::qname xlsx_consumer::expect_start_element(xml::content content)
|
||||||
stack_.push_back(parser().qname());
|
stack_.push_back(parser().qname());
|
||||||
|
|
||||||
const auto xml_space = xml::qname(constants::namespace_("xml"), "space");
|
const auto xml_space = xml::qname(constants::namespace_("xml"), "space");
|
||||||
preserve_space_ = parser().attribute_present(xml_space)
|
preserve_space_ = parser().attribute_present(xml_space) ? parser().attribute(xml_space) == "preserve" : false;
|
||||||
? parser().attribute(xml_space) == "preserve" : false;
|
|
||||||
|
|
||||||
return stack_.back();
|
return stack_.back();
|
||||||
}
|
}
|
||||||
|
@ -2661,8 +2643,7 @@ void xlsx_consumer::expect_start_element(const xml::qname &name, xml::content co
|
||||||
stack_.push_back(name);
|
stack_.push_back(name);
|
||||||
|
|
||||||
const auto xml_space = xml::qname(constants::namespace_("xml"), "space");
|
const auto xml_space = xml::qname(constants::namespace_("xml"), "space");
|
||||||
preserve_space_ = parser().attribute_present(xml_space)
|
preserve_space_ = parser().attribute_present(xml_space) ? parser().attribute(xml_space) == "preserve" : false;
|
||||||
? parser().attribute(xml_space) == "preserve" : false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void xlsx_consumer::expect_end_element(const xml::qname &name)
|
void xlsx_consumer::expect_end_element(const xml::qname &name)
|
||||||
|
@ -2700,7 +2681,7 @@ rich_text xlsx_consumer::read_rich_text(const xml::qname &parent)
|
||||||
{
|
{
|
||||||
auto run_element = expect_start_element(xml::content::mixed);
|
auto run_element = expect_start_element(xml::content::mixed);
|
||||||
auto run_text = read_text();
|
auto run_text = read_text();
|
||||||
|
|
||||||
if (run_element == xml::qname(xmlns, "rPr"))
|
if (run_element == xml::qname(xmlns, "rPr"))
|
||||||
{
|
{
|
||||||
while (in_element(xml::qname(xmlns, "rPr")))
|
while (in_element(xml::qname(xmlns, "rPr")))
|
||||||
|
@ -2731,7 +2712,8 @@ rich_text xlsx_consumer::read_rich_text(const xml::qname &parent)
|
||||||
}
|
}
|
||||||
else if (current_run_property_element == xml::qname(xmlns, "b"))
|
else if (current_run_property_element == xml::qname(xmlns, "b"))
|
||||||
{
|
{
|
||||||
run.second.get().bold(parser().attribute_present("val") ? is_true(parser().attribute("val")) : true);
|
run.second.get().bold(
|
||||||
|
parser().attribute_present("val") ? is_true(parser().attribute("val")) : true);
|
||||||
}
|
}
|
||||||
else if (current_run_property_element == xml::qname(xmlns, "u"))
|
else if (current_run_property_element == xml::qname(xmlns, "u"))
|
||||||
{
|
{
|
||||||
|
@ -2766,7 +2748,7 @@ rich_text xlsx_consumer::read_rich_text(const xml::qname &parent)
|
||||||
expect_end_element(run_element);
|
expect_end_element(run_element);
|
||||||
read_text();
|
read_text();
|
||||||
}
|
}
|
||||||
|
|
||||||
t.add_run(run);
|
t.add_run(run);
|
||||||
}
|
}
|
||||||
else if (text_element == xml::qname(xmlns, "rPh"))
|
else if (text_element == xml::qname(xmlns, "rPh"))
|
||||||
|
@ -2789,7 +2771,6 @@ rich_text xlsx_consumer::read_rich_text(const xml::qname &parent)
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
xlnt::color xlsx_consumer::read_color()
|
xlnt::color xlsx_consumer::read_color()
|
||||||
{
|
{
|
||||||
xlnt::color result;
|
xlnt::color result;
|
||||||
|
|
|
@ -45,7 +45,7 @@ class worksheet;
|
||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
|
||||||
class ZipFileReader;
|
class zip_file_reader;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Handles writing a workbook into an XLSX file.
|
/// Handles writing a workbook into an XLSX file.
|
||||||
|
@ -338,7 +338,7 @@ private:
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The ZIP file containing the files that make up the OOXML package.
|
/// The ZIP file containing the files that make up the OOXML package.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
std::unique_ptr<ZipFileReader> archive_;
|
std::unique_ptr<zip_file_reader> archive_;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Map of sheet titles to relationship IDs.
|
/// Map of sheet titles to relationship IDs.
|
||||||
|
|
|
@ -23,6 +23,8 @@
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
|
|
||||||
|
#include <xlnt/utils/exceptions.hpp>
|
||||||
|
#include <xlnt/workbook/workbook.hpp>
|
||||||
#include <detail/constants.hpp>
|
#include <detail/constants.hpp>
|
||||||
#include <detail/include_cryptopp.hpp>
|
#include <detail/include_cryptopp.hpp>
|
||||||
#include <detail/include_libstudxml.hpp>
|
#include <detail/include_libstudxml.hpp>
|
||||||
|
@ -30,8 +32,6 @@
|
||||||
#include <detail/vector_streambuf.hpp>
|
#include <detail/vector_streambuf.hpp>
|
||||||
#include <detail/xlsx_consumer.hpp>
|
#include <detail/xlsx_consumer.hpp>
|
||||||
#include <detail/xlsx_producer.hpp>
|
#include <detail/xlsx_producer.hpp>
|
||||||
#include <xlnt/utils/exceptions.hpp>
|
|
||||||
#include <xlnt/workbook/workbook.hpp>
|
|
||||||
|
|
||||||
namespace xlnt {
|
namespace xlnt {
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
@ -60,34 +60,54 @@ struct value_traits<xlnt::detail::hash_algorithm>
|
||||||
{
|
{
|
||||||
static xlnt::detail::hash_algorithm parse(std::string hash_algorithm_string, const parser &)
|
static xlnt::detail::hash_algorithm parse(std::string hash_algorithm_string, const parser &)
|
||||||
{
|
{
|
||||||
if (hash_algorithm_string == "SHA1") return xlnt::detail::hash_algorithm::sha1;
|
if (hash_algorithm_string == "SHA1")
|
||||||
else if (hash_algorithm_string == "SHA256") return xlnt::detail::hash_algorithm::sha256;
|
return xlnt::detail::hash_algorithm::sha1;
|
||||||
else if (hash_algorithm_string == "SHA384") return xlnt::detail::hash_algorithm::sha384;
|
else if (hash_algorithm_string == "SHA256")
|
||||||
else if (hash_algorithm_string == "SHA512") return xlnt::detail::hash_algorithm::sha512;
|
return xlnt::detail::hash_algorithm::sha256;
|
||||||
else if (hash_algorithm_string == "MD5") return xlnt::detail::hash_algorithm::md5;
|
else if (hash_algorithm_string == "SHA384")
|
||||||
else if (hash_algorithm_string == "MD4") return xlnt::detail::hash_algorithm::md4;
|
return xlnt::detail::hash_algorithm::sha384;
|
||||||
else if (hash_algorithm_string == "MD2") return xlnt::detail::hash_algorithm::md2;
|
else if (hash_algorithm_string == "SHA512")
|
||||||
else if (hash_algorithm_string == "Ripemd128") return xlnt::detail::hash_algorithm::ripemd128;
|
return xlnt::detail::hash_algorithm::sha512;
|
||||||
else if (hash_algorithm_string == "Ripemd160") return xlnt::detail::hash_algorithm::ripemd160;
|
else if (hash_algorithm_string == "MD5")
|
||||||
else if (hash_algorithm_string == "Whirlpool") return xlnt::detail::hash_algorithm::whirlpool;
|
return xlnt::detail::hash_algorithm::md5;
|
||||||
throw xlnt::exception(hash_algorithm_string);
|
else if (hash_algorithm_string == "MD4")
|
||||||
|
return xlnt::detail::hash_algorithm::md4;
|
||||||
|
else if (hash_algorithm_string == "MD2")
|
||||||
|
return xlnt::detail::hash_algorithm::md2;
|
||||||
|
else if (hash_algorithm_string == "Ripemd128")
|
||||||
|
return xlnt::detail::hash_algorithm::ripemd128;
|
||||||
|
else if (hash_algorithm_string == "Ripemd160")
|
||||||
|
return xlnt::detail::hash_algorithm::ripemd160;
|
||||||
|
else if (hash_algorithm_string == "Whirlpool")
|
||||||
|
return xlnt::detail::hash_algorithm::whirlpool;
|
||||||
|
throw xlnt::exception(hash_algorithm_string);
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string serialize(xlnt::detail::hash_algorithm algorithm, const serializer &)
|
static std::string serialize(xlnt::detail::hash_algorithm algorithm, const serializer &)
|
||||||
{
|
{
|
||||||
switch (algorithm)
|
switch (algorithm)
|
||||||
{
|
{
|
||||||
case xlnt::detail::hash_algorithm::sha1: return "SHA1";
|
case xlnt::detail::hash_algorithm::sha1:
|
||||||
case xlnt::detail::hash_algorithm::sha256: return "SHA256";
|
return "SHA1";
|
||||||
case xlnt::detail::hash_algorithm::sha384: return "SHA384";
|
case xlnt::detail::hash_algorithm::sha256:
|
||||||
case xlnt::detail::hash_algorithm::sha512: return "SHA512";
|
return "SHA256";
|
||||||
case xlnt::detail::hash_algorithm::md5: return "MD5";
|
case xlnt::detail::hash_algorithm::sha384:
|
||||||
case xlnt::detail::hash_algorithm::md4: return "MD4";
|
return "SHA384";
|
||||||
case xlnt::detail::hash_algorithm::md2: return "MD2";
|
case xlnt::detail::hash_algorithm::sha512:
|
||||||
case xlnt::detail::hash_algorithm::ripemd128: return "Ripemd128";
|
return "SHA512";
|
||||||
case xlnt::detail::hash_algorithm::ripemd160: return "Ripemd160";
|
case xlnt::detail::hash_algorithm::md5:
|
||||||
case xlnt::detail::hash_algorithm::whirlpool: return "Whirlpool";
|
return "MD5";
|
||||||
}
|
case xlnt::detail::hash_algorithm::md4:
|
||||||
|
return "MD4";
|
||||||
|
case xlnt::detail::hash_algorithm::md2:
|
||||||
|
return "MD2";
|
||||||
|
case xlnt::detail::hash_algorithm::ripemd128:
|
||||||
|
return "Ripemd128";
|
||||||
|
case xlnt::detail::hash_algorithm::ripemd160:
|
||||||
|
return "Ripemd160";
|
||||||
|
case xlnt::detail::hash_algorithm::whirlpool:
|
||||||
|
return "Whirlpool";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}; // struct value_traits<>
|
}; // struct value_traits<>
|
||||||
|
|
||||||
|
@ -124,10 +144,8 @@ struct crypto_helper
|
||||||
decryption
|
decryption
|
||||||
};
|
};
|
||||||
|
|
||||||
static std::vector<std::uint8_t> aes(const std::vector<std::uint8_t> &key,
|
static std::vector<std::uint8_t> aes(const std::vector<std::uint8_t> &key, const std::vector<std::uint8_t> &iv,
|
||||||
const std::vector<std::uint8_t> &iv,
|
const std::vector<std::uint8_t> &source, cipher_chaining chaining, cipher_direction direction)
|
||||||
const std::vector<std::uint8_t> &source,
|
|
||||||
cipher_chaining chaining, cipher_direction direction)
|
|
||||||
{
|
{
|
||||||
std::vector<std::uint8_t> destination(source.size(), 0);
|
std::vector<std::uint8_t> destination(source.size(), 0);
|
||||||
|
|
||||||
|
@ -136,40 +154,40 @@ struct crypto_helper
|
||||||
CryptoPP::AES::Encryption aesEncryption(key.data(), key.size());
|
CryptoPP::AES::Encryption aesEncryption(key.data(), key.size());
|
||||||
CryptoPP::CBC_Mode_ExternalCipher::Encryption cbcEncryption(aesEncryption, iv.data());
|
CryptoPP::CBC_Mode_ExternalCipher::Encryption cbcEncryption(aesEncryption, iv.data());
|
||||||
|
|
||||||
CryptoPP::ArraySource as(source.data(), source.size(), true,
|
CryptoPP::ArraySource as(
|
||||||
new CryptoPP::StreamTransformationFilter(cbcEncryption,
|
source.data(), source.size(), true, new CryptoPP::StreamTransformationFilter(cbcEncryption,
|
||||||
new CryptoPP::ArraySink(destination.data(), destination.size()),
|
new CryptoPP::ArraySink(destination.data(), destination.size()),
|
||||||
CryptoPP::BlockPaddingSchemeDef::NO_PADDING));
|
CryptoPP::BlockPaddingSchemeDef::NO_PADDING));
|
||||||
}
|
}
|
||||||
else if (direction == cipher_direction::decryption && chaining == cipher_chaining::cbc)
|
else if (direction == cipher_direction::decryption && chaining == cipher_chaining::cbc)
|
||||||
{
|
{
|
||||||
CryptoPP::AES::Decryption aesDecryption(key.data(), key.size());
|
CryptoPP::AES::Decryption aesDecryption(key.data(), key.size());
|
||||||
CryptoPP::CBC_Mode_ExternalCipher::Decryption cbcDecryption(aesDecryption, iv.data());
|
CryptoPP::CBC_Mode_ExternalCipher::Decryption cbcDecryption(aesDecryption, iv.data());
|
||||||
|
|
||||||
CryptoPP::ArraySource as(source.data(), source.size(), true,
|
CryptoPP::ArraySource as(
|
||||||
new CryptoPP::StreamTransformationFilter(cbcDecryption,
|
source.data(), source.size(), true, new CryptoPP::StreamTransformationFilter(cbcDecryption,
|
||||||
new CryptoPP::ArraySink(destination.data(), destination.size()),
|
new CryptoPP::ArraySink(destination.data(), destination.size()),
|
||||||
CryptoPP::BlockPaddingSchemeDef::NO_PADDING));
|
CryptoPP::BlockPaddingSchemeDef::NO_PADDING));
|
||||||
}
|
}
|
||||||
else if (direction == cipher_direction::encryption && chaining == cipher_chaining::ecb)
|
else if (direction == cipher_direction::encryption && chaining == cipher_chaining::ecb)
|
||||||
{
|
{
|
||||||
CryptoPP::AES::Encryption aesEncryption(key.data(), key.size());
|
CryptoPP::AES::Encryption aesEncryption(key.data(), key.size());
|
||||||
CryptoPP::ECB_Mode_ExternalCipher::Encryption cbcEncryption(aesEncryption, iv.data());
|
CryptoPP::ECB_Mode_ExternalCipher::Encryption cbcEncryption(aesEncryption, iv.data());
|
||||||
|
|
||||||
CryptoPP::ArraySource as(source.data(), source.size(), true,
|
CryptoPP::ArraySource as(
|
||||||
new CryptoPP::StreamTransformationFilter(cbcEncryption,
|
source.data(), source.size(), true, new CryptoPP::StreamTransformationFilter(cbcEncryption,
|
||||||
new CryptoPP::ArraySink(destination.data(), destination.size()),
|
new CryptoPP::ArraySink(destination.data(), destination.size()),
|
||||||
CryptoPP::BlockPaddingSchemeDef::NO_PADDING));
|
CryptoPP::BlockPaddingSchemeDef::NO_PADDING));
|
||||||
}
|
}
|
||||||
else if (direction == cipher_direction::decryption && chaining == cipher_chaining::ecb)
|
else if (direction == cipher_direction::decryption && chaining == cipher_chaining::ecb)
|
||||||
{
|
{
|
||||||
CryptoPP::AES::Decryption aesDecryption(key.data(), key.size());
|
CryptoPP::AES::Decryption aesDecryption(key.data(), key.size());
|
||||||
CryptoPP::ECB_Mode_ExternalCipher::Decryption cbcDecryption(aesDecryption, iv.data());
|
CryptoPP::ECB_Mode_ExternalCipher::Decryption cbcDecryption(aesDecryption, iv.data());
|
||||||
|
|
||||||
CryptoPP::ArraySource as(source.data(), source.size(), true,
|
CryptoPP::ArraySource as(
|
||||||
new CryptoPP::StreamTransformationFilter(cbcDecryption,
|
source.data(), source.size(), true, new CryptoPP::StreamTransformationFilter(cbcDecryption,
|
||||||
new CryptoPP::ArraySink(destination.data(), destination.size()),
|
new CryptoPP::ArraySink(destination.data(), destination.size()),
|
||||||
CryptoPP::BlockPaddingSchemeDef::NO_PADDING));
|
CryptoPP::BlockPaddingSchemeDef::NO_PADDING));
|
||||||
}
|
}
|
||||||
|
|
||||||
return destination;
|
return destination;
|
||||||
|
@ -199,8 +217,7 @@ struct crypto_helper
|
||||||
return std::string(encoded.begin(), encoded.end());
|
return std::string(encoded.begin(), encoded.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::vector<std::uint8_t> hash(hash_algorithm algorithm,
|
static std::vector<std::uint8_t> hash(hash_algorithm algorithm, const std::vector<std::uint8_t> &input)
|
||||||
const std::vector<std::uint8_t> &input)
|
|
||||||
{
|
{
|
||||||
std::vector<std::uint8_t> digest;
|
std::vector<std::uint8_t> digest;
|
||||||
|
|
||||||
|
@ -229,7 +246,7 @@ struct crypto_helper
|
||||||
return bytes;
|
return bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template <typename T>
|
||||||
static auto read_int(std::size_t &index, const std::vector<std::uint8_t> &raw_data)
|
static auto read_int(std::size_t &index, const std::vector<std::uint8_t> &raw_data)
|
||||||
{
|
{
|
||||||
auto result = *reinterpret_cast<const T *>(&raw_data[index]);
|
auto result = *reinterpret_cast<const T *>(&raw_data[index]);
|
||||||
|
@ -263,8 +280,8 @@ struct crypto_helper
|
||||||
|
|
||||||
auto header_length = read_int<std::uint32_t>(offset, encryption_info);
|
auto header_length = read_int<std::uint32_t>(offset, encryption_info);
|
||||||
auto index_at_start = offset;
|
auto index_at_start = offset;
|
||||||
/*auto skip_flags = */read_int<std::uint32_t>(offset, encryption_info);
|
/*auto skip_flags = */ read_int<std::uint32_t>(offset, encryption_info);
|
||||||
/*auto size_extra = */read_int<std::uint32_t>(offset, encryption_info);
|
/*auto size_extra = */ read_int<std::uint32_t>(offset, encryption_info);
|
||||||
auto alg_id = read_int<std::uint32_t>(offset, encryption_info);
|
auto alg_id = read_int<std::uint32_t>(offset, encryption_info);
|
||||||
|
|
||||||
if (alg_id == 0 || alg_id == 0x0000660E || alg_id == 0x0000660F || alg_id == 0x00006610)
|
if (alg_id == 0 || alg_id == 0x0000660E || alg_id == 0x0000660F || alg_id == 0x00006610)
|
||||||
|
@ -281,7 +298,7 @@ struct crypto_helper
|
||||||
{
|
{
|
||||||
throw xlnt::exception("invalid hash algorithm");
|
throw xlnt::exception("invalid hash algorithm");
|
||||||
}
|
}
|
||||||
|
|
||||||
info.key_bits = read_int<std::uint32_t>(offset, encryption_info);
|
info.key_bits = read_int<std::uint32_t>(offset, encryption_info);
|
||||||
info.key_bytes = info.key_bits / 8;
|
info.key_bytes = info.key_bits / 8;
|
||||||
|
|
||||||
|
@ -300,7 +317,8 @@ struct crypto_helper
|
||||||
const auto csp_name_length = header_length - (offset - index_at_start);
|
const auto csp_name_length = header_length - (offset - index_at_start);
|
||||||
std::vector<std::uint16_t> csp_name_wide(
|
std::vector<std::uint16_t> csp_name_wide(
|
||||||
reinterpret_cast<const std::uint16_t *>(&*(encryption_info.begin() + static_cast<std::ptrdiff_t>(offset))),
|
reinterpret_cast<const std::uint16_t *>(&*(encryption_info.begin() + static_cast<std::ptrdiff_t>(offset))),
|
||||||
reinterpret_cast<const std::uint16_t *>(&*(encryption_info.begin() + static_cast<std::ptrdiff_t>(offset + csp_name_length))));
|
reinterpret_cast<const std::uint16_t *>(
|
||||||
|
&*(encryption_info.begin() + static_cast<std::ptrdiff_t>(offset + csp_name_length))));
|
||||||
std::string csp_name(csp_name_wide.begin(), csp_name_wide.end() - 1); // without trailing null
|
std::string csp_name(csp_name_wide.begin(), csp_name_wide.end() - 1); // without trailing null
|
||||||
if (csp_name != "Microsoft Enhanced RSA and AES Cryptographic Provider (Prototype)"
|
if (csp_name != "Microsoft Enhanced RSA and AES Cryptographic Provider (Prototype)"
|
||||||
&& csp_name != "Microsoft Enhanced RSA and AES Cryptographic Provider")
|
&& csp_name != "Microsoft Enhanced RSA and AES Cryptographic Provider")
|
||||||
|
@ -329,11 +347,8 @@ struct crypto_helper
|
||||||
// H_0 = H(salt + password)
|
// H_0 = H(salt + password)
|
||||||
auto salt_plus_password = salt;
|
auto salt_plus_password = salt;
|
||||||
std::vector<std::uint16_t> password_wide(password.begin(), password.end());
|
std::vector<std::uint16_t> password_wide(password.begin(), password.end());
|
||||||
std::for_each(password_wide.begin(), password_wide.end(),
|
std::for_each(password_wide.begin(), password_wide.end(), [&salt_plus_password](std::uint16_t c) {
|
||||||
[&salt_plus_password](std::uint16_t c)
|
salt_plus_password.insert(salt_plus_password.end(), reinterpret_cast<char *>(&c),
|
||||||
{
|
|
||||||
salt_plus_password.insert(salt_plus_password.end(),
|
|
||||||
reinterpret_cast<char *>(&c),
|
|
||||||
reinterpret_cast<char *>(&c) + sizeof(std::uint16_t));
|
reinterpret_cast<char *>(&c) + sizeof(std::uint16_t));
|
||||||
});
|
});
|
||||||
std::vector<std::uint8_t> h_0 = hash(info.hash, salt_plus_password);
|
std::vector<std::uint8_t> h_0 = hash(info.hash, salt_plus_password);
|
||||||
|
@ -352,8 +367,7 @@ struct crypto_helper
|
||||||
// H_final = H(H_n + block)
|
// H_final = H(H_n + block)
|
||||||
auto h_n_plus_block = h_n;
|
auto h_n_plus_block = h_n;
|
||||||
const std::uint32_t block_number = 0;
|
const std::uint32_t block_number = 0;
|
||||||
h_n_plus_block.insert(h_n_plus_block.end(),
|
h_n_plus_block.insert(h_n_plus_block.end(), reinterpret_cast<const std::uint8_t *>(&block_number),
|
||||||
reinterpret_cast<const std::uint8_t *>(&block_number),
|
|
||||||
reinterpret_cast<const std::uint8_t *>(&block_number) + sizeof(std::uint32_t));
|
reinterpret_cast<const std::uint8_t *>(&block_number) + sizeof(std::uint32_t));
|
||||||
auto h_final = hash(info.hash, h_n_plus_block);
|
auto h_final = hash(info.hash, h_n_plus_block);
|
||||||
|
|
||||||
|
@ -375,16 +389,17 @@ struct crypto_helper
|
||||||
|
|
||||||
auto X3 = X1;
|
auto X3 = X1;
|
||||||
X3.insert(X3.end(), X2.begin(), X2.end());
|
X3.insert(X3.end(), X2.begin(), X2.end());
|
||||||
|
|
||||||
auto key_derived = std::vector<std::uint8_t>(X3.begin(), X3.begin() + static_cast<std::ptrdiff_t>(info.key_bytes));
|
|
||||||
|
|
||||||
//todo: verify here
|
auto key_derived =
|
||||||
|
std::vector<std::uint8_t>(X3.begin(), X3.begin() + static_cast<std::ptrdiff_t>(info.key_bytes));
|
||||||
|
|
||||||
|
// todo: verify here
|
||||||
|
|
||||||
std::size_t package_offset = 0;
|
std::size_t package_offset = 0;
|
||||||
auto decrypted_size = static_cast<std::size_t>(read_int<std::uint64_t>(package_offset, encrypted_package));
|
auto decrypted_size = static_cast<std::size_t>(read_int<std::uint64_t>(package_offset, encrypted_package));
|
||||||
auto decrypted = aes(key_derived, {}, std::vector<std::uint8_t>(
|
auto decrypted =
|
||||||
encrypted_package.begin() + 8, encrypted_package.end()),
|
aes(key_derived, {}, std::vector<std::uint8_t>(encrypted_package.begin() + 8, encrypted_package.end()),
|
||||||
cipher_chaining::ecb, cipher_direction::decryption);
|
cipher_chaining::ecb, cipher_direction::decryption);
|
||||||
decrypted.resize(decrypted_size);
|
decrypted.resize(decrypted_size);
|
||||||
|
|
||||||
return decrypted;
|
return decrypted;
|
||||||
|
@ -420,7 +435,7 @@ struct crypto_helper
|
||||||
std::size_t hash_size;
|
std::size_t hash_size;
|
||||||
std::string cipher_algorithm;
|
std::string cipher_algorithm;
|
||||||
std::string cipher_chaining;
|
std::string cipher_chaining;
|
||||||
hash_algorithm hash;
|
hash_algorithm hash;
|
||||||
std::vector<std::uint8_t> salt_value;
|
std::vector<std::uint8_t> salt_value;
|
||||||
std::vector<std::uint8_t> verifier_hash_input;
|
std::vector<std::uint8_t> verifier_hash_input;
|
||||||
std::vector<std::uint8_t> verifier_hash_value;
|
std::vector<std::uint8_t> verifier_hash_value;
|
||||||
|
@ -430,9 +445,9 @@ struct crypto_helper
|
||||||
|
|
||||||
static agile_encryption_info generate_agile_encryption_info(const std::string &password)
|
static agile_encryption_info generate_agile_encryption_info(const std::string &password)
|
||||||
{
|
{
|
||||||
agile_encryption_info result;
|
agile_encryption_info result;
|
||||||
result.key_data.salt_value.assign(password.begin(), password.end());
|
result.key_data.salt_value.assign(password.begin(), password.end());
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::vector<std::uint8_t> write_agile_encryption_info(const std::string &password)
|
static std::vector<std::uint8_t> write_agile_encryption_info(const std::string &password)
|
||||||
|
@ -440,20 +455,20 @@ struct crypto_helper
|
||||||
static const auto &xmlns = xlnt::constants::namespace_("encryption");
|
static const auto &xmlns = xlnt::constants::namespace_("encryption");
|
||||||
static const auto &xmlns_p = xlnt::constants::namespace_("encryption-password");
|
static const auto &xmlns_p = xlnt::constants::namespace_("encryption-password");
|
||||||
|
|
||||||
std::vector<std::uint8_t> encryption_info;
|
std::vector<std::uint8_t> encryption_info;
|
||||||
xlnt::detail::vector_ostreambuf encryption_info_buffer(encryption_info);
|
xlnt::detail::vector_ostreambuf encryption_info_buffer(encryption_info);
|
||||||
std::ostream encryption_info_stream(&encryption_info_buffer);
|
std::ostream encryption_info_stream(&encryption_info_buffer);
|
||||||
xml::serializer serializer(encryption_info_stream, "EncryptionInfo");
|
xml::serializer serializer(encryption_info_stream, "EncryptionInfo");
|
||||||
|
|
||||||
agile_encryption_info result = generate_agile_encryption_info(password);
|
agile_encryption_info result = generate_agile_encryption_info(password);
|
||||||
|
|
||||||
serializer.start_element(xmlns, "encryption");
|
serializer.start_element(xmlns, "encryption");
|
||||||
|
|
||||||
serializer.start_element(xmlns, "keyData");
|
serializer.start_element(xmlns, "keyData");
|
||||||
serializer.attribute("saltSize", result.key_data.salt_size);
|
serializer.attribute("saltSize", result.key_data.salt_size);
|
||||||
serializer.attribute("blockSize", result.key_data.block_size);
|
serializer.attribute("blockSize", result.key_data.block_size);
|
||||||
serializer.attribute("keyBits", result.key_data.key_bits);
|
serializer.attribute("keyBits", result.key_data.key_bits);
|
||||||
serializer.attribute("hashSize", result.key_data.hash_size);
|
serializer.attribute("hashSize", result.key_data.hash_size);
|
||||||
serializer.attribute("cipherAlgorithm", result.key_data.cipher_algorithm);
|
serializer.attribute("cipherAlgorithm", result.key_data.cipher_algorithm);
|
||||||
serializer.attribute("cipherChaining", result.key_data.cipher_chaining);
|
serializer.attribute("cipherChaining", result.key_data.cipher_chaining);
|
||||||
serializer.attribute("hashAlgorithm", result.key_data.hash_algorithm);
|
serializer.attribute("hashAlgorithm", result.key_data.hash_algorithm);
|
||||||
|
@ -468,26 +483,26 @@ struct crypto_helper
|
||||||
serializer.start_element(xmlns, "keyEncryptors");
|
serializer.start_element(xmlns, "keyEncryptors");
|
||||||
serializer.start_element(xmlns, "keyEncryptor");
|
serializer.start_element(xmlns, "keyEncryptor");
|
||||||
serializer.attribute("uri", "");
|
serializer.attribute("uri", "");
|
||||||
serializer.start_element(xmlns_p, "encryptedKey");
|
serializer.start_element(xmlns_p, "encryptedKey");
|
||||||
serializer.attribute("spinCount", result.key_encryptor.spin_count);
|
serializer.attribute("spinCount", result.key_encryptor.spin_count);
|
||||||
serializer.attribute("saltSize", result.key_encryptor.salt_size);
|
serializer.attribute("saltSize", result.key_encryptor.salt_size);
|
||||||
serializer.attribute("blockSize", result.key_encryptor.block_size);
|
serializer.attribute("blockSize", result.key_encryptor.block_size);
|
||||||
serializer.attribute("keyBits", result.key_encryptor.key_bits);
|
serializer.attribute("keyBits", result.key_encryptor.key_bits);
|
||||||
serializer.attribute("hashSize", result.key_encryptor.hash_size);
|
serializer.attribute("hashSize", result.key_encryptor.hash_size);
|
||||||
serializer.attribute("cipherAlgorithm", result.key_encryptor.cipher_algorithm);
|
serializer.attribute("cipherAlgorithm", result.key_encryptor.cipher_algorithm);
|
||||||
serializer.attribute("cipherChaining", result.key_encryptor.cipher_chaining);
|
serializer.attribute("cipherChaining", result.key_encryptor.cipher_chaining);
|
||||||
serializer.attribute("hashAlgorithm", result.key_encryptor.hash);
|
serializer.attribute("hashAlgorithm", result.key_encryptor.hash);
|
||||||
serializer.attribute("saltValue", encode_base64(result.key_encryptor.salt_value));
|
serializer.attribute("saltValue", encode_base64(result.key_encryptor.salt_value));
|
||||||
serializer.attribute("encryptedVerifierHashInput", encode_base64(result.key_encryptor.verifier_hash_input));
|
serializer.attribute("encryptedVerifierHashInput", encode_base64(result.key_encryptor.verifier_hash_input));
|
||||||
serializer.attribute("encryptedVerifierHashValue", encode_base64(result.key_encryptor.verifier_hash_value));
|
serializer.attribute("encryptedVerifierHashValue", encode_base64(result.key_encryptor.verifier_hash_value));
|
||||||
serializer.attribute("encryptedKeyValue", encode_base64(result.key_encryptor.encrypted_key_value));
|
serializer.attribute("encryptedKeyValue", encode_base64(result.key_encryptor.encrypted_key_value));
|
||||||
serializer.end_element(xmlns_p, "encryptedKey");
|
serializer.end_element(xmlns_p, "encryptedKey");
|
||||||
serializer.end_element(xmlns, "keyEncryptor");
|
serializer.end_element(xmlns, "keyEncryptor");
|
||||||
serializer.end_element(xmlns, "keyEncryptors");
|
serializer.end_element(xmlns, "keyEncryptors");
|
||||||
|
|
||||||
serializer.end_element(xmlns, "encryption");
|
serializer.end_element(xmlns, "encryption");
|
||||||
|
|
||||||
return encryption_info;
|
return encryption_info;
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::vector<std::uint8_t> decrypt_xlsx_agile(const std::vector<std::uint8_t> &encryption_info,
|
static std::vector<std::uint8_t> decrypt_xlsx_agile(const std::vector<std::uint8_t> &encryption_info,
|
||||||
|
@ -495,7 +510,7 @@ struct crypto_helper
|
||||||
{
|
{
|
||||||
static const auto &xmlns = xlnt::constants::namespace_("encryption");
|
static const auto &xmlns = xlnt::constants::namespace_("encryption");
|
||||||
static const auto &xmlns_p = xlnt::constants::namespace_("encryption-password");
|
static const auto &xmlns_p = xlnt::constants::namespace_("encryption-password");
|
||||||
//static const auto &xmlns_c = xlnt::constants::namespace_("encryption-certificate");
|
// static const auto &xmlns_c = xlnt::constants::namespace_("encryption-certificate");
|
||||||
|
|
||||||
agile_encryption_info result;
|
agile_encryption_info result;
|
||||||
|
|
||||||
|
@ -558,8 +573,10 @@ struct crypto_helper
|
||||||
}
|
}
|
||||||
|
|
||||||
result.key_encryptor.salt_value = decode_base64(parser.attribute("saltValue"));
|
result.key_encryptor.salt_value = decode_base64(parser.attribute("saltValue"));
|
||||||
result.key_encryptor.verifier_hash_input = decode_base64(parser.attribute("encryptedVerifierHashInput"));
|
result.key_encryptor.verifier_hash_input =
|
||||||
result.key_encryptor.verifier_hash_value = decode_base64(parser.attribute("encryptedVerifierHashValue"));
|
decode_base64(parser.attribute("encryptedVerifierHashInput"));
|
||||||
|
result.key_encryptor.verifier_hash_value =
|
||||||
|
decode_base64(parser.attribute("encryptedVerifierHashValue"));
|
||||||
result.key_encryptor.encrypted_key_value = decode_base64(parser.attribute("encryptedKeyValue"));
|
result.key_encryptor.encrypted_key_value = decode_base64(parser.attribute("encryptedKeyValue"));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -580,18 +597,14 @@ struct crypto_helper
|
||||||
|
|
||||||
parser.next_expect(xml::parser::event_type::end_element, xmlns, "encryption");
|
parser.next_expect(xml::parser::event_type::end_element, xmlns, "encryption");
|
||||||
|
|
||||||
|
|
||||||
// begin key generation algorithm
|
// begin key generation algorithm
|
||||||
|
|
||||||
// H_0 = H(salt + password)
|
// H_0 = H(salt + password)
|
||||||
auto salt_plus_password = result.key_encryptor.salt_value;
|
auto salt_plus_password = result.key_encryptor.salt_value;
|
||||||
std::vector<std::uint16_t> password_wide(password.begin(), password.end());
|
std::vector<std::uint16_t> password_wide(password.begin(), password.end());
|
||||||
|
|
||||||
std::for_each(password_wide.begin(), password_wide.end(),
|
std::for_each(password_wide.begin(), password_wide.end(), [&salt_plus_password](std::uint16_t c) {
|
||||||
[&salt_plus_password](std::uint16_t c)
|
salt_plus_password.insert(salt_plus_password.end(), reinterpret_cast<char *>(&c),
|
||||||
{
|
|
||||||
salt_plus_password.insert(salt_plus_password.end(),
|
|
||||||
reinterpret_cast<char *>(&c),
|
|
||||||
reinterpret_cast<char *>(&c) + sizeof(std::uint16_t));
|
reinterpret_cast<char *>(&c) + sizeof(std::uint16_t));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -608,46 +621,39 @@ struct crypto_helper
|
||||||
h_n = hash(result.key_encryptor.hash, iterator_plus_h_n);
|
h_n = hash(result.key_encryptor.hash, iterator_plus_h_n);
|
||||||
std::copy(h_n.begin(), h_n.end(), iterator_plus_h_n.begin() + 4);
|
std::copy(h_n.begin(), h_n.end(), iterator_plus_h_n.begin() + 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const std::size_t block_size = 8;
|
static const std::size_t block_size = 8;
|
||||||
|
|
||||||
auto calculate_block = [&result](
|
auto calculate_block = [&result](const std::vector<std::uint8_t> &raw_key,
|
||||||
const std::vector<std::uint8_t> &raw_key,
|
const std::array<std::uint8_t, block_size> &block, const std::vector<std::uint8_t> &encrypted) {
|
||||||
const std::array<std::uint8_t, block_size> &block,
|
|
||||||
const std::vector<std::uint8_t> &encrypted)
|
|
||||||
{
|
|
||||||
auto combined = raw_key;
|
auto combined = raw_key;
|
||||||
combined.insert(combined.end(), block.begin(), block.end());
|
combined.insert(combined.end(), block.begin(), block.end());
|
||||||
auto key = hash(result.key_encryptor.hash, combined);
|
auto key = hash(result.key_encryptor.hash, combined);
|
||||||
key.resize(result.key_encryptor.key_bits / 8);
|
key.resize(result.key_encryptor.key_bits / 8);
|
||||||
return aes(key, result.key_encryptor.salt_value, encrypted,
|
return aes(
|
||||||
cipher_chaining::cbc, cipher_direction::decryption);
|
key, result.key_encryptor.salt_value, encrypted, cipher_chaining::cbc, cipher_direction::decryption);
|
||||||
};
|
};
|
||||||
|
|
||||||
const std::array<std::uint8_t, block_size> input_block_key
|
const std::array<std::uint8_t, block_size> input_block_key = {{0xfe, 0xa7, 0xd2, 0x76, 0x3b, 0x4b, 0x9e, 0x79}};
|
||||||
= { {0xfe, 0xa7, 0xd2, 0x76, 0x3b, 0x4b, 0x9e, 0x79} };
|
auto hash_input = calculate_block(h_n, input_block_key, result.key_encryptor.verifier_hash_input);
|
||||||
auto hash_input = calculate_block(h_n, input_block_key,
|
|
||||||
result.key_encryptor.verifier_hash_input);
|
|
||||||
auto calculated_verifier = hash(result.key_encryptor.hash, hash_input);
|
auto calculated_verifier = hash(result.key_encryptor.hash, hash_input);
|
||||||
|
|
||||||
const std::array<std::uint8_t, block_size> verifier_block_key
|
const std::array<std::uint8_t, block_size> verifier_block_key = {
|
||||||
= { {0xd7, 0xaa, 0x0f, 0x6d, 0x30, 0x61, 0x34, 0x4e} };
|
{0xd7, 0xaa, 0x0f, 0x6d, 0x30, 0x61, 0x34, 0x4e}};
|
||||||
auto expected_verifier = calculate_block(h_n, verifier_block_key,
|
auto expected_verifier = calculate_block(h_n, verifier_block_key, result.key_encryptor.verifier_hash_value);
|
||||||
result.key_encryptor.verifier_hash_value);
|
|
||||||
expected_verifier.resize(calculated_verifier.size());
|
expected_verifier.resize(calculated_verifier.size());
|
||||||
|
|
||||||
if (calculated_verifier.size() != expected_verifier.size()
|
if (calculated_verifier.size() != expected_verifier.size()
|
||||||
|| std::mismatch(calculated_verifier.begin(), calculated_verifier.end(),
|
|| std::mismatch(calculated_verifier.begin(), calculated_verifier.end(), expected_verifier.begin(),
|
||||||
expected_verifier.begin(), expected_verifier.end())
|
expected_verifier.end())
|
||||||
!= std::make_pair(calculated_verifier.end(), expected_verifier.end()))
|
!= std::make_pair(calculated_verifier.end(), expected_verifier.end()))
|
||||||
{
|
{
|
||||||
throw xlnt::exception("bad password");
|
throw xlnt::exception("bad password");
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::array<std::uint8_t, block_size> key_value_block_key
|
const std::array<std::uint8_t, block_size> key_value_block_key = {
|
||||||
= { {0x14, 0x6e, 0x0b, 0xe7, 0xab, 0xac, 0xd0, 0xd6} };
|
{0x14, 0x6e, 0x0b, 0xe7, 0xab, 0xac, 0xd0, 0xd6}};
|
||||||
auto key = calculate_block(h_n, key_value_block_key,
|
auto key = calculate_block(h_n, key_value_block_key, result.key_encryptor.encrypted_key_value);
|
||||||
result.key_encryptor.encrypted_key_value);
|
|
||||||
|
|
||||||
auto salt_size = result.key_data.salt_size;
|
auto salt_size = result.key_data.salt_size;
|
||||||
auto salt_with_block_key = result.key_data.salt_value;
|
auto salt_with_block_key = result.key_data.salt_value;
|
||||||
|
@ -667,15 +673,13 @@ struct crypto_helper
|
||||||
|
|
||||||
auto segment_begin = encrypted_package.begin() + static_cast<std::ptrdiff_t>(i);
|
auto segment_begin = encrypted_package.begin() + static_cast<std::ptrdiff_t>(i);
|
||||||
auto current_segment_length = std::min(segment_length, encrypted_package.size() - i);
|
auto current_segment_length = std::min(segment_length, encrypted_package.size() - i);
|
||||||
auto segment_end = encrypted_package.begin()
|
auto segment_end = encrypted_package.begin() + static_cast<std::ptrdiff_t>(i + current_segment_length);
|
||||||
+ static_cast<std::ptrdiff_t>(i + current_segment_length);
|
|
||||||
encrypted_segment.assign(segment_begin, segment_end);
|
encrypted_segment.assign(segment_begin, segment_end);
|
||||||
auto decrypted_segment = aes(key, iv, encrypted_segment,
|
auto decrypted_segment =
|
||||||
cipher_chaining::cbc, cipher_direction::decryption);
|
aes(key, iv, encrypted_segment, cipher_chaining::cbc, cipher_direction::decryption);
|
||||||
decrypted_segment.resize(current_segment_length);
|
decrypted_segment.resize(current_segment_length);
|
||||||
|
|
||||||
decrypted_package.insert(decrypted_package.end(),
|
decrypted_package.insert(decrypted_package.end(), decrypted_segment.begin(), decrypted_segment.end());
|
||||||
decrypted_segment.begin(), decrypted_segment.end());
|
|
||||||
|
|
||||||
++segment;
|
++segment;
|
||||||
}
|
}
|
||||||
|
@ -710,8 +714,7 @@ struct crypto_helper
|
||||||
auto encryption_flags = read_int<std::uint32_t>(index, encryption_info);
|
auto encryption_flags = read_int<std::uint32_t>(index, encryption_info);
|
||||||
|
|
||||||
// get rid of header
|
// get rid of header
|
||||||
encryption_info.erase(encryption_info.begin(),
|
encryption_info.erase(encryption_info.begin(), encryption_info.begin() + static_cast<std::ptrdiff_t>(index));
|
||||||
encryption_info.begin() + static_cast<std::ptrdiff_t>(index));
|
|
||||||
|
|
||||||
// version 4.4 is agile
|
// version 4.4 is agile
|
||||||
if (version_major == 4 && version_minor == 4)
|
if (version_major == 4 && version_minor == 4)
|
||||||
|
@ -725,8 +728,7 @@ struct crypto_helper
|
||||||
}
|
}
|
||||||
|
|
||||||
// not agile, only try to decrypt versions 3.2 and 4.2
|
// not agile, only try to decrypt versions 3.2 and 4.2
|
||||||
if (version_minor != 2
|
if (version_minor != 2 || (version_major != 2 && version_major != 3 && version_major != 4))
|
||||||
|| (version_major != 2 && version_major != 3 && version_major != 4))
|
|
||||||
{
|
{
|
||||||
throw xlnt::exception("unsupported encryption version");
|
throw xlnt::exception("unsupported encryption version");
|
||||||
}
|
}
|
||||||
|
@ -757,7 +759,7 @@ struct crypto_helper
|
||||||
throw xlnt::exception("empty file");
|
throw xlnt::exception("empty file");
|
||||||
}
|
}
|
||||||
|
|
||||||
generate_agile_encryption_info(password);
|
generate_agile_encryption_info(password);
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
@ -767,12 +769,11 @@ const std::size_t crypto_helper::segment_length = 4096;
|
||||||
|
|
||||||
void xlsx_consumer::read(std::istream &source, const std::string &password)
|
void xlsx_consumer::read(std::istream &source, const std::string &password)
|
||||||
{
|
{
|
||||||
std::vector<std::uint8_t> data((std::istreambuf_iterator<char>(source)),
|
std::vector<std::uint8_t> data((std::istreambuf_iterator<char>(source)), (std::istreambuf_iterator<char>()));
|
||||||
(std::istreambuf_iterator<char>()));
|
const auto decrypted = crypto_helper::decrypt_xlsx(data, password);
|
||||||
const auto decrypted = crypto_helper::decrypt_xlsx(data, password);
|
vector_istreambuf decrypted_buffer(decrypted);
|
||||||
vector_istreambuf decrypted_buffer(decrypted);
|
std::istream decrypted_stream(&decrypted_buffer);
|
||||||
std::istream decrypted_stream(&decrypted_buffer);
|
read(decrypted_stream);
|
||||||
read(decrypted_stream);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void xlsx_producer::write(std::ostream &destination, const std::string &password)
|
void xlsx_producer::write(std::ostream &destination, const std::string &password)
|
||||||
|
@ -787,7 +788,7 @@ void xlsx_producer::write(std::ostream &destination, const std::string &password
|
||||||
|
|
||||||
const auto encrypted = crypto_helper::encrypt_xlsx(decrypted, password);
|
const auto encrypted = crypto_helper::encrypt_xlsx(decrypted, password);
|
||||||
vector_istreambuf encrypted_buffer(encrypted);
|
vector_istreambuf encrypted_buffer(encrypted);
|
||||||
|
|
||||||
destination << &encrypted_buffer;
|
destination << &encrypted_buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -44,7 +44,7 @@ class worksheet;
|
||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
|
||||||
class ZipFileWriter;
|
class zip_file_writer;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Handles writing a workbook into an XLSX file.
|
/// Handles writing a workbook into an XLSX file.
|
||||||
|
@ -137,8 +137,10 @@ private:
|
||||||
/// </summary>
|
/// </summary>
|
||||||
const workbook &source_;
|
const workbook &source_;
|
||||||
|
|
||||||
ZipFileWriter *archive_;
|
zip_file_writer *archive_;
|
||||||
std::unique_ptr<xml::serializer> current_part_serializer_;
|
std::unique_ptr<xml::serializer> current_part_serializer_;
|
||||||
|
std::unique_ptr<std::streambuf> current_part_streambuf_;
|
||||||
|
std::ostream current_part_stream_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
|
|
|
@ -48,32 +48,30 @@ extern "C" {
|
||||||
#include <zlib.h>
|
#include <zlib.h>
|
||||||
}
|
}
|
||||||
|
|
||||||
#include <detail/zip.hpp>
|
|
||||||
#include <xlnt/utils/exceptions.hpp>
|
#include <xlnt/utils/exceptions.hpp>
|
||||||
|
#include <detail/zip.hpp>
|
||||||
|
|
||||||
namespace xlnt {
|
namespace {
|
||||||
namespace detail {
|
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
inline T read_int(std::istream &stream)
|
T read_int(std::istream &stream)
|
||||||
{
|
{
|
||||||
T value;
|
T value;
|
||||||
stream.read(reinterpret_cast<char *>(&value), sizeof(T));
|
stream.read(reinterpret_cast<char *>(&value), sizeof(T));
|
||||||
|
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
inline void write_int(std::ostream &stream, T value)
|
void write_int(std::ostream &stream, T value)
|
||||||
{
|
{
|
||||||
stream.write(reinterpret_cast<char *>(&value), sizeof(T));
|
stream.write(reinterpret_cast<char *>(&value), sizeof(T));
|
||||||
}
|
}
|
||||||
|
|
||||||
zip_file_header::zip_file_header()
|
xlnt::detail::zip_file_header read_header(std::istream &istream, const bool global)
|
||||||
{
|
{
|
||||||
}
|
xlnt::detail::zip_file_header header;
|
||||||
|
|
||||||
bool zip_file_header::read(std::istream &istream, const bool global)
|
|
||||||
{
|
|
||||||
auto sig = read_int<std::uint32_t>(istream);
|
auto sig = read_int<std::uint32_t>(istream);
|
||||||
|
|
||||||
// read and check for local/global magic
|
// read and check for local/global magic
|
||||||
|
@ -81,27 +79,25 @@ bool zip_file_header::read(std::istream &istream, const bool global)
|
||||||
{
|
{
|
||||||
if (sig != 0x02014b50)
|
if (sig != 0x02014b50)
|
||||||
{
|
{
|
||||||
std::cerr << "Did not find global header signature" << std::endl;
|
throw xlnt::exception("missing global header signature");
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
version = read_int<std::uint16_t>(istream);
|
header.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;
|
throw xlnt::exception("missing local header signature");
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read rest of header
|
// Read rest of header
|
||||||
version = read_int<std::uint16_t>(istream);
|
header.version = read_int<std::uint16_t>(istream);
|
||||||
flags = read_int<std::uint16_t>(istream);
|
header.flags = read_int<std::uint16_t>(istream);
|
||||||
compression_type = read_int<std::uint16_t>(istream);
|
header.compression_type = read_int<std::uint16_t>(istream);
|
||||||
stamp_date = read_int<std::uint16_t>(istream);
|
header.stamp_date = read_int<std::uint16_t>(istream);
|
||||||
stamp_time = read_int<std::uint16_t>(istream);
|
header.stamp_time = read_int<std::uint16_t>(istream);
|
||||||
crc = read_int<std::uint32_t>(istream);
|
header.crc = read_int<std::uint32_t>(istream);
|
||||||
compressed_size = read_int<std::uint32_t>(istream);
|
header.compressed_size = read_int<std::uint32_t>(istream);
|
||||||
uncompressed_size = read_int<std::uint32_t>(istream);
|
header.uncompressed_size = read_int<std::uint32_t>(istream);
|
||||||
|
|
||||||
auto filename_length = read_int<std::uint16_t>(istream);
|
auto filename_length = read_int<std::uint16_t>(istream);
|
||||||
auto extra_length = read_int<std::uint16_t>(istream);
|
auto extra_length = read_int<std::uint16_t>(istream);
|
||||||
|
@ -114,25 +110,25 @@ bool zip_file_header::read(std::istream &istream, const bool global)
|
||||||
/*std::uint16_t disk_number_start = */ 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::uint16_t int_file_attrib = */ read_int<std::uint16_t>(istream);
|
||||||
/*std::uint32_t ext_file_attrib = */ read_int<std::uint32_t>(istream);
|
/*std::uint32_t ext_file_attrib = */ read_int<std::uint32_t>(istream);
|
||||||
header_offset = read_int<std::uint32_t>(istream);
|
header.header_offset = read_int<std::uint32_t>(istream);
|
||||||
}
|
}
|
||||||
|
|
||||||
filename.resize(filename_length, '\0');
|
header.filename.resize(filename_length, '\0');
|
||||||
istream.read(&filename[0], filename_length);
|
istream.read(&header.filename[0], filename_length);
|
||||||
|
|
||||||
extra.resize(extra_length, 0);
|
header.extra.resize(extra_length, 0);
|
||||||
istream.read(reinterpret_cast<char *>(extra.data()), extra_length);
|
istream.read(reinterpret_cast<char *>(header.extra.data()), extra_length);
|
||||||
|
|
||||||
if (global)
|
if (global)
|
||||||
{
|
{
|
||||||
comment.resize(comment_length, '\0');
|
header.comment.resize(comment_length, '\0');
|
||||||
istream.read(&comment[0], comment_length);
|
istream.read(&header.comment[0], comment_length);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return header;
|
||||||
}
|
}
|
||||||
|
|
||||||
void zip_file_header::Write(std::ostream &ostream, const bool global) const
|
void write_header(const xlnt::detail::zip_file_header &header, std::ostream &ostream, const bool global)
|
||||||
{
|
{
|
||||||
if (global)
|
if (global)
|
||||||
{
|
{
|
||||||
|
@ -144,15 +140,15 @@ void zip_file_header::Write(std::ostream &ostream, const bool global) const
|
||||||
write_int(ostream, static_cast<unsigned int>(0x04034b50));
|
write_int(ostream, static_cast<unsigned int>(0x04034b50));
|
||||||
}
|
}
|
||||||
|
|
||||||
write_int(ostream, version);
|
write_int(ostream, header.version);
|
||||||
write_int(ostream, flags);
|
write_int(ostream, header.flags);
|
||||||
write_int(ostream, compression_type);
|
write_int(ostream, header.compression_type);
|
||||||
write_int(ostream, stamp_date);
|
write_int(ostream, header.stamp_date);
|
||||||
write_int(ostream, stamp_time);
|
write_int(ostream, header.stamp_time);
|
||||||
write_int(ostream, crc);
|
write_int(ostream, header.crc);
|
||||||
write_int(ostream, compressed_size);
|
write_int(ostream, header.compressed_size);
|
||||||
write_int(ostream, uncompressed_size);
|
write_int(ostream, header.uncompressed_size);
|
||||||
write_int(ostream, static_cast<unsigned short>(filename.length()));
|
write_int(ostream, static_cast<unsigned short>(header.filename.length()));
|
||||||
write_int(ostream, static_cast<unsigned short>(0)); // extra lengthx
|
write_int(ostream, static_cast<unsigned short>(0)); // extra lengthx
|
||||||
|
|
||||||
if (global)
|
if (global)
|
||||||
|
@ -161,18 +157,23 @@ void zip_file_header::Write(std::ostream &ostream, const bool global) const
|
||||||
write_int(ostream, static_cast<unsigned short>(0)); // disk# start
|
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 short>(0)); // internal file
|
||||||
write_int(ostream, static_cast<unsigned int>(0)); // ext final
|
write_int(ostream, static_cast<unsigned int>(0)); // ext final
|
||||||
write_int(ostream, static_cast<unsigned int>(header_offset)); // rel offset
|
write_int(ostream, static_cast<unsigned int>(header.header_offset)); // rel offset
|
||||||
}
|
}
|
||||||
|
|
||||||
for (unsigned int i = 0; i < filename.length(); i++)
|
for (auto c : header.filename)
|
||||||
{
|
{
|
||||||
write_int(ostream, filename.c_str()[i]);
|
write_int(ostream, c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
namespace xlnt {
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
static const std::size_t buffer_size = 512;
|
static const std::size_t buffer_size = 512;
|
||||||
|
|
||||||
class ZipStreambufDecompress : public std::streambuf
|
class zip_streambuf_decompress : public std::streambuf
|
||||||
{
|
{
|
||||||
std::istream &istream;
|
std::istream &istream;
|
||||||
|
|
||||||
|
@ -189,7 +190,7 @@ class ZipStreambufDecompress : public std::streambuf
|
||||||
static const unsigned short UNCOMPRESSED = 0;
|
static const unsigned short UNCOMPRESSED = 0;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ZipStreambufDecompress(std::istream &stream, zip_file_header central_header)
|
zip_streambuf_decompress(std::istream &stream, zip_file_header central_header)
|
||||||
: istream(stream), header(central_header), total_read(0), total_uncompressed(0), valid(true)
|
: istream(stream), header(central_header), total_read(0), total_uncompressed(0), valid(true)
|
||||||
{
|
{
|
||||||
strm.zalloc = Z_NULL;
|
strm.zalloc = Z_NULL;
|
||||||
|
@ -202,7 +203,8 @@ public:
|
||||||
setp(0, 0);
|
setp(0, 0);
|
||||||
|
|
||||||
// skip the header
|
// skip the header
|
||||||
valid = header.read(istream, false);
|
read_header(istream, false);
|
||||||
|
|
||||||
if (header.compression_type == DEFLATE)
|
if (header.compression_type == DEFLATE)
|
||||||
{
|
{
|
||||||
compressed_data = true;
|
compressed_data = true;
|
||||||
|
@ -236,7 +238,7 @@ public:
|
||||||
header = central_header;
|
header = central_header;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~ZipStreambufDecompress()
|
virtual ~zip_streambuf_decompress()
|
||||||
{
|
{
|
||||||
if (compressed_data && valid)
|
if (compressed_data && valid)
|
||||||
{
|
{
|
||||||
|
@ -258,7 +260,8 @@ public:
|
||||||
if (strm.avail_in == 0)
|
if (strm.avail_in == 0)
|
||||||
{
|
{
|
||||||
// buffer empty, read some more from file
|
// buffer empty, read some more from file
|
||||||
istream.read(in.data(), static_cast<std::streamsize>(std::min(buffer_size, header.compressed_size - total_read)));
|
istream.read(in.data(),
|
||||||
|
static_cast<std::streamsize>(std::min(buffer_size, header.compressed_size - total_read)));
|
||||||
strm.avail_in = static_cast<unsigned int>(istream.gcount());
|
strm.avail_in = static_cast<unsigned int>(istream.gcount());
|
||||||
total_read += strm.avail_in;
|
total_read += strm.avail_in;
|
||||||
strm.next_in = reinterpret_cast<Bytef *>(in.data());
|
strm.next_in = reinterpret_cast<Bytef *>(in.data());
|
||||||
|
@ -289,7 +292,8 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
// uncompressed, so just read
|
// uncompressed, so just read
|
||||||
istream.read(out.data() + 4, static_cast<std::streamsize>(std::min(buffer_size - 4, header.uncompressed_size - total_read)));
|
istream.read(out.data() + 4,
|
||||||
|
static_cast<std::streamsize>(std::min(buffer_size - 4, header.uncompressed_size - total_read)));
|
||||||
auto count = istream.gcount();
|
auto count = istream.gcount();
|
||||||
total_read += static_cast<std::size_t>(count);
|
total_read += static_cast<std::size_t>(count);
|
||||||
return static_cast<int>(count);
|
return static_cast<int>(count);
|
||||||
|
@ -301,7 +305,8 @@ public:
|
||||||
return traits_type::to_int_type(*gptr()); // if we already have data just use it
|
return traits_type::to_int_type(*gptr()); // if we already have data just use it
|
||||||
auto put_back_count = gptr() - eback();
|
auto put_back_count = gptr() - eback();
|
||||||
if (put_back_count > 4) put_back_count = 4;
|
if (put_back_count > 4) put_back_count = 4;
|
||||||
std::memmove(out.data() + (4 - put_back_count), gptr() - put_back_count, static_cast<std::size_t>(put_back_count));
|
std::memmove(
|
||||||
|
out.data() + (4 - put_back_count), gptr() - put_back_count, static_cast<std::size_t>(put_back_count));
|
||||||
int num = process();
|
int num = process();
|
||||||
setg(out.data() + 4 - put_back_count, out.data() + 4, out.data() + 4 + num);
|
setg(out.data() + 4 - put_back_count, out.data() + 4, out.data() + 4 + num);
|
||||||
if (num <= 0) return EOF;
|
if (num <= 0) return EOF;
|
||||||
|
@ -311,12 +316,12 @@ public:
|
||||||
virtual int overflow(int c = EOF);
|
virtual int overflow(int c = EOF);
|
||||||
};
|
};
|
||||||
|
|
||||||
int ZipStreambufDecompress::overflow(int)
|
int zip_streambuf_decompress::overflow(int)
|
||||||
{
|
{
|
||||||
throw xlnt::exception("writing to read-only buffer");
|
throw xlnt::exception("writing to read-only buffer");
|
||||||
}
|
}
|
||||||
|
|
||||||
class ZipStreambufCompress : public std::streambuf
|
class zip_streambuf_compress : public std::streambuf
|
||||||
{
|
{
|
||||||
std::ostream &ostream; // owned when header==0 (when not part of zip file)
|
std::ostream &ostream; // owned when header==0 (when not part of zip file)
|
||||||
|
|
||||||
|
@ -331,7 +336,7 @@ class ZipStreambufCompress : public std::streambuf
|
||||||
bool valid;
|
bool valid;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ZipStreambufCompress(zip_file_header *central_header, std::ostream &stream)
|
zip_streambuf_compress(zip_file_header *central_header, std::ostream &stream)
|
||||||
: ostream(stream), header(central_header), valid(true)
|
: ostream(stream), header(central_header), valid(true)
|
||||||
{
|
{
|
||||||
strm.zalloc = Z_NULL;
|
strm.zalloc = Z_NULL;
|
||||||
|
@ -341,7 +346,7 @@ public:
|
||||||
#pragma clang diagnostic push
|
#pragma clang diagnostic push
|
||||||
#pragma clang diagnostic ignored "-Wold-style-cast"
|
#pragma clang diagnostic ignored "-Wold-style-cast"
|
||||||
int ret = deflateInit2(&strm, Z_DEFAULT_COMPRESSION, Z_DEFLATED, -MAX_WBITS, 8, Z_DEFAULT_STRATEGY);
|
int ret = deflateInit2(&strm, Z_DEFAULT_COMPRESSION, Z_DEFLATED, -MAX_WBITS, 8, Z_DEFAULT_STRATEGY);
|
||||||
#pragma clang diagnostic pop
|
#pragma clang diagnostic pop
|
||||||
|
|
||||||
if (ret != Z_OK)
|
if (ret != Z_OK)
|
||||||
{
|
{
|
||||||
|
@ -357,13 +362,13 @@ public:
|
||||||
if (header)
|
if (header)
|
||||||
{
|
{
|
||||||
header->header_offset = static_cast<std::uint32_t>(stream.tellp());
|
header->header_offset = static_cast<std::uint32_t>(stream.tellp());
|
||||||
header->Write(ostream, false);
|
write_header(*header, ostream, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
uncompressed_size = crc = 0;
|
uncompressed_size = crc = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~ZipStreambufCompress()
|
virtual ~zip_streambuf_compress()
|
||||||
{
|
{
|
||||||
if (valid)
|
if (valid)
|
||||||
{
|
{
|
||||||
|
@ -375,7 +380,7 @@ public:
|
||||||
header->uncompressed_size = uncompressed_size;
|
header->uncompressed_size = uncompressed_size;
|
||||||
header->crc = crc;
|
header->crc = crc;
|
||||||
ostream.seekp(header->header_offset);
|
ostream.seekp(header->header_offset);
|
||||||
header->Write(ostream, false);
|
write_header(*header, ostream, false);
|
||||||
ostream.seekp(final_position);
|
ostream.seekp(final_position);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -439,7 +444,7 @@ protected:
|
||||||
virtual int overflow(int c = EOF);
|
virtual int overflow(int c = EOF);
|
||||||
};
|
};
|
||||||
|
|
||||||
int ZipStreambufCompress::overflow(int c)
|
int zip_streambuf_compress::overflow(int c)
|
||||||
{
|
{
|
||||||
if (c != EOF)
|
if (c != EOF)
|
||||||
{
|
{
|
||||||
|
@ -450,71 +455,48 @@ int ZipStreambufCompress::overflow(int c)
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
zip_file_istream::zip_file_istream(std::unique_ptr<std::streambuf> &&buffer)
|
zip_file_writer::zip_file_writer(std::ostream &stream)
|
||||||
: std::istream(&*buffer)
|
: destination_stream_(stream)
|
||||||
{
|
{
|
||||||
buf.swap(buffer);
|
if (!destination_stream_)
|
||||||
|
{
|
||||||
|
throw xlnt::exception("bad zip stream");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
zip_file_istream::~zip_file_istream()
|
zip_file_writer::~zip_file_writer()
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
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) : tarstream_(stream)
|
|
||||||
{
|
|
||||||
if (!tarstream_) throw std::runtime_error("ZIP: Invalid file handle");
|
|
||||||
}
|
|
||||||
|
|
||||||
ZipFileWriter::~ZipFileWriter()
|
|
||||||
{
|
{
|
||||||
// Write all file headers
|
// Write all file headers
|
||||||
std::ios::streampos final_position = tarstream_.tellp();
|
std::ios::streampos final_position = destination_stream_.tellp();
|
||||||
|
|
||||||
for (unsigned int i = 0; i < file_headers_.size(); i++)
|
for (const auto &header : file_headers_)
|
||||||
{
|
{
|
||||||
file_headers_[i].Write(tarstream_, true);
|
write_header(header, destination_stream_, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::ios::streampos central_end = tarstream_.tellp();
|
std::ios::streampos central_end = destination_stream_.tellp();
|
||||||
|
|
||||||
// Write end of central
|
// Write end of central
|
||||||
write_int(tarstream_, static_cast<std::uint32_t>(0x06054b50)); // end of central
|
write_int(destination_stream_, static_cast<std::uint32_t>(0x06054b50)); // end of central
|
||||||
write_int(tarstream_, static_cast<std::uint16_t>(0)); // this disk number
|
write_int(destination_stream_, static_cast<std::uint16_t>(0)); // this disk number
|
||||||
write_int(tarstream_, static_cast<std::uint16_t>(0)); // this disk number
|
write_int(destination_stream_, static_cast<std::uint16_t>(0)); // this disk number
|
||||||
write_int(tarstream_, static_cast<std::uint16_t>(file_headers_.size())); // one entry in center in this disk
|
write_int(destination_stream_, static_cast<std::uint16_t>(file_headers_.size())); // one entry in center in this disk
|
||||||
write_int(tarstream_, static_cast<std::uint16_t>(file_headers_.size())); // one entry in center
|
write_int(destination_stream_, static_cast<std::uint16_t>(file_headers_.size())); // one entry in center
|
||||||
write_int(tarstream_, static_cast<std::uint32_t>(central_end - final_position)); // size of header
|
write_int(destination_stream_, static_cast<std::uint32_t>(central_end - final_position)); // size of header
|
||||||
write_int(tarstream_, static_cast<std::uint32_t>(final_position)); // offset to header
|
write_int(destination_stream_, static_cast<std::uint32_t>(final_position)); // offset to header
|
||||||
write_int(tarstream_, static_cast<std::uint16_t>(0)); // zip comment
|
write_int(destination_stream_, static_cast<std::uint16_t>(0)); // zip comment
|
||||||
}
|
}
|
||||||
|
|
||||||
std::ostream &ZipFileWriter::open(const std::string &filename)
|
std::unique_ptr<std::streambuf> zip_file_writer::open(const path &filename)
|
||||||
{
|
{
|
||||||
zip_file_header header;
|
zip_file_header header;
|
||||||
header.filename = filename;
|
header.filename = filename.string();
|
||||||
file_headers_.push_back(header);
|
file_headers_.push_back(header);
|
||||||
auto streambuf = std::make_unique<ZipStreambufCompress>(&file_headers_.back(), tarstream_);
|
return std::make_unique<zip_streambuf_compress>(&file_headers_.back(), destination_stream_);
|
||||||
auto stream = new zip_file_ostream(std::move(streambuf));
|
|
||||||
write_stream_.reset(stream);
|
|
||||||
return *write_stream_;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ZipFileWriter::close()
|
zip_file_reader::zip_file_reader(std::istream &stream)
|
||||||
{
|
: source_stream_(stream)
|
||||||
write_stream_.reset(nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
ZipFileReader::ZipFileReader(std::istream &stream) : source_stream_(stream)
|
|
||||||
{
|
{
|
||||||
if (!stream)
|
if (!stream)
|
||||||
{
|
{
|
||||||
|
@ -524,11 +506,11 @@ ZipFileReader::ZipFileReader(std::istream &stream) : source_stream_(stream)
|
||||||
read_central_header();
|
read_central_header();
|
||||||
}
|
}
|
||||||
|
|
||||||
ZipFileReader::~ZipFileReader()
|
zip_file_reader::~zip_file_reader()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ZipFileReader::read_central_header()
|
bool zip_file_reader::read_central_header()
|
||||||
{
|
{
|
||||||
// Find the header
|
// Find the header
|
||||||
// NOTE: this assumes the zip file header is the last thing written to file...
|
// NOTE: this assumes the zip file header is the last thing written to file...
|
||||||
|
@ -605,43 +587,37 @@ bool ZipFileReader::read_central_header()
|
||||||
|
|
||||||
for (std::uint16_t i = 0; i < num_files; ++i)
|
for (std::uint16_t i = 0; i < num_files; ++i)
|
||||||
{
|
{
|
||||||
zip_file_header header;
|
auto header = read_header(source_stream_, true);
|
||||||
|
file_headers_[header.filename] = header;
|
||||||
if (header.read(source_stream_, true))
|
|
||||||
{
|
|
||||||
file_headers_[header.filename] = header;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::istream &ZipFileReader::open(const std::string &filename)
|
std::unique_ptr<std::streambuf> zip_file_reader::open(const path &filename)
|
||||||
{
|
{
|
||||||
if (!has_file(filename))
|
if (!has_file(filename))
|
||||||
{
|
{
|
||||||
throw "not found";
|
throw "not found";
|
||||||
}
|
}
|
||||||
|
|
||||||
auto header = file_headers_.at(filename);
|
auto header = file_headers_.at(filename.string());
|
||||||
source_stream_.seekg(header.header_offset);
|
source_stream_.seekg(header.header_offset);
|
||||||
auto streambuf = std::make_unique<ZipStreambufDecompress>(source_stream_, header);
|
return std::make_unique<zip_streambuf_decompress>(source_stream_, header);
|
||||||
read_stream_.reset(new zip_file_istream(std::move(streambuf)));
|
|
||||||
|
|
||||||
return *read_stream_;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string> ZipFileReader::files() const
|
std::vector<path> zip_file_reader::files() const
|
||||||
{
|
{
|
||||||
std::vector<std::string> filenames;
|
std::vector<path> filenames;
|
||||||
std::transform(file_headers_.begin(), file_headers_.end(), std::back_inserter(filenames),
|
std::transform(file_headers_.begin(), file_headers_.end(), std::back_inserter(filenames),
|
||||||
[](const std::pair<std::string, zip_file_header> &h) { return h.first; });
|
[](const std::pair<std::string, zip_file_header> &h) { return path(h.first); });
|
||||||
|
|
||||||
return filenames;
|
return filenames;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ZipFileReader::has_file(const std::string &filename) const
|
bool zip_file_reader::has_file(const path &filename) const
|
||||||
{
|
{
|
||||||
return file_headers_.count(filename) != 0;
|
return file_headers_.count(filename.string()) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
|
|
|
@ -40,9 +40,15 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include <xlnt/utils/path.hpp>
|
||||||
|
|
||||||
namespace xlnt {
|
namespace xlnt {
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A structure representing the header that occurs before each compressed file in a ZIP
|
||||||
|
/// archive and again at the end of the file with more information.
|
||||||
|
/// </summary>
|
||||||
struct zip_file_header
|
struct zip_file_header
|
||||||
{
|
{
|
||||||
std::uint16_t version = 20;
|
std::uint16_t version = 20;
|
||||||
|
@ -56,61 +62,82 @@ struct zip_file_header
|
||||||
std::string comment;
|
std::string comment;
|
||||||
std::vector<std::uint8_t> extra;
|
std::vector<std::uint8_t> extra;
|
||||||
std::uint32_t header_offset = 0;
|
std::uint32_t header_offset = 0;
|
||||||
|
|
||||||
zip_file_header();
|
|
||||||
|
|
||||||
bool read(std::istream &istream, const bool global);
|
|
||||||
void Write(std::ostream &ostream, const bool global) const;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class zip_file_istream : public std::istream
|
/// <summary>
|
||||||
|
/// Writes a series of uncompressed binary file data as ostreams into another ostream
|
||||||
|
/// according to the ZIP format.
|
||||||
|
/// </summary>
|
||||||
|
class zip_file_writer
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
zip_file_istream(std::unique_ptr<std::streambuf> &&buf);
|
/// <summary>
|
||||||
virtual ~zip_file_istream();
|
/// Construct a new zip_file_writer which writes a ZIP archive to the given stream.
|
||||||
|
/// </summary>
|
||||||
private:
|
zip_file_writer(std::ostream &stream);
|
||||||
std::unique_ptr<std::streambuf> buf;
|
|
||||||
};
|
|
||||||
|
|
||||||
class zip_file_ostream : public std::ostream
|
/// <summary>
|
||||||
{
|
/// Destructor.
|
||||||
public:
|
/// </summary>
|
||||||
zip_file_ostream(std::unique_ptr<std::streambuf> &&buf);
|
virtual ~zip_file_writer();
|
||||||
virtual ~zip_file_ostream();
|
|
||||||
|
|
||||||
private:
|
/// <summary>
|
||||||
std::unique_ptr<std::streambuf> buf;
|
/// Returns a pointer to a streambuf which compresses the data it receives.
|
||||||
};
|
/// </summary>
|
||||||
|
std::unique_ptr<std::streambuf> open(const path &file);
|
||||||
|
|
||||||
class ZipFileWriter
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
ZipFileWriter(std::ostream &filename);
|
|
||||||
virtual ~ZipFileWriter();
|
|
||||||
std::ostream &open(const std::string &filename);
|
|
||||||
void close();
|
|
||||||
private:
|
private:
|
||||||
std::vector<zip_file_header> file_headers_;
|
std::vector<zip_file_header> file_headers_;
|
||||||
std::ostream &tarstream_;
|
std::ostream &destination_stream_;
|
||||||
std::unique_ptr<std::ostream> write_stream_;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class ZipFileReader
|
/// <summary>
|
||||||
|
/// Reads an archive containing a number of files from an istream and allows them
|
||||||
|
/// to be decompressed into an istream.
|
||||||
|
/// </summary>
|
||||||
|
class zip_file_reader
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ZipFileReader(std::istream &stream);
|
/// <summary>
|
||||||
virtual ~ZipFileReader();
|
/// Construct a new zip_file_reader which reads a ZIP archive from the given stream.
|
||||||
std::istream &open(const std::string &filename);
|
/// </summary>
|
||||||
std::vector<std::string> files() const;
|
zip_file_reader(std::istream &stream);
|
||||||
bool has_file(const std::string &filename) const;
|
|
||||||
|
/// <summary>
|
||||||
|
/// Destructor.
|
||||||
|
/// </summary>
|
||||||
|
virtual ~zip_file_reader();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
std::unique_ptr<std::streambuf> open(const path &file);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
std::vector<path> files() const;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
bool has_file(const path &filename) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
bool read_central_header();
|
bool read_central_header();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
std::unordered_map<std::string, zip_file_header> file_headers_;
|
std::unordered_map<std::string, zip_file_header> file_headers_;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
std::istream &source_stream_;
|
std::istream &source_stream_;
|
||||||
std::unique_ptr<std::istream> read_stream_;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
|
|
|
@ -64,17 +64,17 @@ path manifest::canonicalize(const std::vector<xlnt::relationship> &rels) const
|
||||||
absolute_parts.pop_back();
|
absolute_parts.pop_back();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
absolute_parts.push_back(component);
|
absolute_parts.push_back(component);
|
||||||
}
|
}
|
||||||
|
|
||||||
xlnt::path result;
|
xlnt::path result;
|
||||||
|
|
||||||
for (const auto &component : absolute_parts)
|
for (const auto &component : absolute_parts)
|
||||||
{
|
{
|
||||||
result = result.append(component);
|
result = result.append(component);
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,7 +86,7 @@ bool manifest::has_relationship(const path &part, relationship_type type) const
|
||||||
{
|
{
|
||||||
if (rel.second.type() == type) return true;
|
if (rel.second.type() == type) return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -98,13 +98,13 @@ relationship manifest::relationship(const path &part, relationship_type type) co
|
||||||
{
|
{
|
||||||
if (rel.second.type() == type) return rel.second;
|
if (rel.second.type() == type) return rel.second;
|
||||||
}
|
}
|
||||||
|
|
||||||
throw key_not_found();
|
throw key_not_found();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<xlnt::relationship> manifest::relationships(const path &part, relationship_type type) const
|
std::vector<xlnt::relationship> manifest::relationships(const path &part, relationship_type type) const
|
||||||
{
|
{
|
||||||
std::vector<xlnt::relationship> matches;
|
std::vector<xlnt::relationship> matches;
|
||||||
|
|
||||||
if (has_relationship(part, type))
|
if (has_relationship(part, type))
|
||||||
{
|
{
|
||||||
|
@ -117,23 +117,23 @@ std::vector<xlnt::relationship> manifest::relationships(const path &part, relati
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return matches;
|
return matches;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string manifest::content_type(const path &part) const
|
std::string manifest::content_type(const path &part) const
|
||||||
{
|
{
|
||||||
auto absolute = part.resolve(path("/"));
|
auto absolute = part.resolve(path("/"));
|
||||||
|
|
||||||
if (has_override_type(absolute))
|
if (has_override_type(absolute))
|
||||||
{
|
{
|
||||||
return override_type(absolute);
|
return override_type(absolute);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (has_default_type(part.extension()))
|
if (has_default_type(part.extension()))
|
||||||
{
|
{
|
||||||
return default_type(part.extension());
|
return default_type(part.extension());
|
||||||
}
|
}
|
||||||
|
|
||||||
throw key_not_found();
|
throw key_not_found();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -144,27 +144,27 @@ void manifest::register_override_type(const path &part, const std::string &conte
|
||||||
|
|
||||||
void manifest::unregister_override_type(const path &part)
|
void manifest::unregister_override_type(const path &part)
|
||||||
{
|
{
|
||||||
override_content_types_.erase(part);
|
override_content_types_.erase(part);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<path> manifest::parts_with_overriden_types() const
|
std::vector<path> manifest::parts_with_overriden_types() const
|
||||||
{
|
{
|
||||||
std::vector<path> overriden;
|
std::vector<path> overriden;
|
||||||
|
|
||||||
for (const auto &part : override_content_types_)
|
for (const auto &part : override_content_types_)
|
||||||
{
|
{
|
||||||
overriden.push_back(part.first);
|
overriden.push_back(part.first);
|
||||||
}
|
}
|
||||||
|
|
||||||
return overriden;
|
return overriden;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<relationship> manifest::relationships(const path &part) const
|
std::vector<relationship> manifest::relationships(const path &part) const
|
||||||
{
|
{
|
||||||
if (relationships_.find(part) == relationships_.end())
|
if (relationships_.find(part) == relationships_.end())
|
||||||
{
|
{
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<xlnt::relationship> relationships;
|
std::vector<xlnt::relationship> relationships;
|
||||||
|
|
||||||
|
@ -172,36 +172,36 @@ std::vector<relationship> manifest::relationships(const path &part) const
|
||||||
{
|
{
|
||||||
relationships.push_back(rel.second);
|
relationships.push_back(rel.second);
|
||||||
}
|
}
|
||||||
|
|
||||||
return relationships;
|
return relationships;
|
||||||
}
|
}
|
||||||
|
|
||||||
relationship manifest::relationship(const path &part, const std::string &rel_id) const
|
relationship manifest::relationship(const path &part, const std::string &rel_id) const
|
||||||
{
|
{
|
||||||
if (relationships_.find(part) == relationships_.end())
|
if (relationships_.find(part) == relationships_.end())
|
||||||
{
|
{
|
||||||
throw key_not_found();
|
throw key_not_found();
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const auto &rel : relationships_.at(part))
|
for (const auto &rel : relationships_.at(part))
|
||||||
{
|
{
|
||||||
if (rel.second.id() == rel_id)
|
if (rel.second.id() == rel_id)
|
||||||
{
|
{
|
||||||
return rel.second;
|
return rel.second;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
throw key_not_found();
|
throw key_not_found();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<path> manifest::parts() const
|
std::vector<path> manifest::parts() const
|
||||||
{
|
{
|
||||||
std::unordered_set<path> parts;
|
std::unordered_set<path> parts;
|
||||||
|
|
||||||
for (const auto &part_rels : relationships_)
|
for (const auto &part_rels : relationships_)
|
||||||
{
|
{
|
||||||
parts.insert(part_rels.first);
|
parts.insert(part_rels.first);
|
||||||
|
|
||||||
for (const auto &rel : part_rels.second)
|
for (const auto &rel : part_rels.second)
|
||||||
{
|
{
|
||||||
if (rel.second.target_mode() == target_mode::internal)
|
if (rel.second.target_mode() == target_mode::internal)
|
||||||
|
@ -209,78 +209,79 @@ std::vector<path> manifest::parts() const
|
||||||
parts.insert(rel.second.target().path());
|
parts.insert(rel.second.target().path());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return std::vector<path>(parts.begin(), parts.end());
|
return std::vector<path>(parts.begin(), parts.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string manifest::register_relationship(const uri &source, relationship_type type, const uri &target, target_mode mode)
|
std::string manifest::register_relationship(
|
||||||
|
const uri &source, relationship_type type, const uri &target, target_mode mode)
|
||||||
{
|
{
|
||||||
xlnt::relationship rel(next_relationship_id(source.path()), type, source, target, mode);
|
xlnt::relationship rel(next_relationship_id(source.path()), type, source, target, mode);
|
||||||
return register_relationship(rel);
|
return register_relationship(rel);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string manifest::register_relationship(const class relationship &rel)
|
std::string manifest::register_relationship(const class relationship &rel)
|
||||||
{
|
{
|
||||||
relationships_[rel.source().path()][rel.id()] = rel;
|
relationships_[rel.source().path()][rel.id()] = rel;
|
||||||
return rel.id();
|
return rel.id();
|
||||||
}
|
}
|
||||||
|
|
||||||
void manifest::unregister_relationship(const uri &source, const std::string &rel_id)
|
void manifest::unregister_relationship(const uri &source, const std::string &rel_id)
|
||||||
{
|
{
|
||||||
relationships_.at(source.path()).erase(rel_id);
|
relationships_.at(source.path()).erase(rel_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool manifest::has_default_type(const std::string &extension) const
|
bool manifest::has_default_type(const std::string &extension) const
|
||||||
{
|
{
|
||||||
return default_content_types_.find(extension) != default_content_types_.end();
|
return default_content_types_.find(extension) != default_content_types_.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string> manifest::extensions_with_default_types() const
|
std::vector<std::string> manifest::extensions_with_default_types() const
|
||||||
{
|
{
|
||||||
std::vector<std::string> extensions;
|
std::vector<std::string> extensions;
|
||||||
|
|
||||||
for (const auto &extension_type_pair : default_content_types_)
|
for (const auto &extension_type_pair : default_content_types_)
|
||||||
{
|
{
|
||||||
extensions.push_back(extension_type_pair.first);
|
extensions.push_back(extension_type_pair.first);
|
||||||
}
|
}
|
||||||
|
|
||||||
return extensions;
|
return extensions;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string manifest::default_type(const std::string &extension) const
|
std::string manifest::default_type(const std::string &extension) const
|
||||||
{
|
{
|
||||||
if (default_content_types_.find(extension) == default_content_types_.end())
|
if (default_content_types_.find(extension) == default_content_types_.end())
|
||||||
{
|
{
|
||||||
throw key_not_found();
|
throw key_not_found();
|
||||||
}
|
}
|
||||||
|
|
||||||
return default_content_types_.at(extension);
|
return default_content_types_.at(extension);
|
||||||
}
|
}
|
||||||
|
|
||||||
void manifest::register_default_type(const std::string &extension, const std::string &content_type)
|
void manifest::register_default_type(const std::string &extension, const std::string &content_type)
|
||||||
{
|
{
|
||||||
default_content_types_[extension] = content_type;
|
default_content_types_[extension] = content_type;
|
||||||
}
|
}
|
||||||
|
|
||||||
void manifest::unregister_default_type(const std::string &extension)
|
void manifest::unregister_default_type(const std::string &extension)
|
||||||
{
|
{
|
||||||
default_content_types_.erase(extension);
|
default_content_types_.erase(extension);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string manifest::next_relationship_id(const path &part) const
|
std::string manifest::next_relationship_id(const path &part) const
|
||||||
{
|
{
|
||||||
if (relationships_.find(part) == relationships_.end()) return "rId1";
|
if (relationships_.find(part) == relationships_.end()) return "rId1";
|
||||||
|
|
||||||
std::size_t index = 1;
|
std::size_t index = 1;
|
||||||
const auto &part_rels = relationships_.at(part);
|
const auto &part_rels = relationships_.at(part);
|
||||||
|
|
||||||
while (part_rels.find("rId" + std::to_string(index)) != part_rels.end())
|
while (part_rels.find("rId" + std::to_string(index)) != part_rels.end())
|
||||||
{
|
{
|
||||||
++index;
|
++index;
|
||||||
}
|
}
|
||||||
|
|
||||||
return "rId" + std::to_string(index);
|
return "rId" + std::to_string(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool manifest::has_override_type(const xlnt::path &part) const
|
bool manifest::has_override_type(const xlnt::path &part) const
|
||||||
|
@ -294,7 +295,7 @@ std::string manifest::override_type(const xlnt::path &part) const
|
||||||
{
|
{
|
||||||
throw key_not_found();
|
throw key_not_found();
|
||||||
}
|
}
|
||||||
|
|
||||||
return override_content_types_.at(part);
|
return override_content_types_.at(part);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -30,12 +30,9 @@ relationship::relationship()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
relationship::relationship(const std::string &id, relationship_type t, const uri &source, const uri &target, xlnt::target_mode mode)
|
relationship::relationship(
|
||||||
: id_(id),
|
const std::string &id, relationship_type t, const uri &source, const uri &target, xlnt::target_mode mode)
|
||||||
type_(t),
|
: id_(id), type_(t), source_(source), target_(target), mode_(mode)
|
||||||
source_(source),
|
|
||||||
target_(target),
|
|
||||||
mode_(mode)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -66,11 +63,8 @@ relationship_type relationship::type() const
|
||||||
|
|
||||||
bool relationship::operator==(const relationship &rhs) const
|
bool relationship::operator==(const relationship &rhs) const
|
||||||
{
|
{
|
||||||
return type_ == rhs.type_
|
return type_ == rhs.type_ && id_ == rhs.id_ && source_ == rhs.source_ && target_ == rhs.target_
|
||||||
&& id_ == rhs.id_
|
&& mode_ == rhs.mode_;
|
||||||
&& source_ == rhs.source_
|
|
||||||
&& target_ == rhs.target_
|
|
||||||
&& mode_ == rhs.mode_;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace xlnt
|
} // namespace xlnt
|
||||||
|
|
|
@ -6,7 +6,8 @@ uri::uri()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
uri::uri(const std::string &uri_string) : path_(uri_string)
|
uri::uri(const std::string &uri_string)
|
||||||
|
: path_(uri_string)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -33,19 +33,19 @@ optional<bool> alignment::wrap() const
|
||||||
|
|
||||||
alignment &alignment::wrap(bool wrap_text)
|
alignment &alignment::wrap(bool wrap_text)
|
||||||
{
|
{
|
||||||
wrap_text_ = wrap_text;
|
wrap_text_ = wrap_text;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
optional<bool> alignment::shrink() const
|
optional<bool> alignment::shrink() const
|
||||||
{
|
{
|
||||||
return shrink_to_fit_;
|
return shrink_to_fit_;
|
||||||
}
|
}
|
||||||
|
|
||||||
alignment &alignment::shrink(bool shrink_to_fit)
|
alignment &alignment::shrink(bool shrink_to_fit)
|
||||||
{
|
{
|
||||||
shrink_to_fit_ = shrink_to_fit;
|
shrink_to_fit_ = shrink_to_fit;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
optional<horizontal_alignment> alignment::horizontal() const
|
optional<horizontal_alignment> alignment::horizontal() const
|
||||||
|
@ -56,7 +56,7 @@ optional<horizontal_alignment> alignment::horizontal() const
|
||||||
alignment &alignment::horizontal(horizontal_alignment horizontal)
|
alignment &alignment::horizontal(horizontal_alignment horizontal)
|
||||||
{
|
{
|
||||||
horizontal_ = horizontal;
|
horizontal_ = horizontal;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
optional<vertical_alignment> alignment::vertical() const
|
optional<vertical_alignment> alignment::vertical() const
|
||||||
|
@ -67,29 +67,29 @@ optional<vertical_alignment> alignment::vertical() const
|
||||||
alignment &alignment::vertical(vertical_alignment vertical)
|
alignment &alignment::vertical(vertical_alignment vertical)
|
||||||
{
|
{
|
||||||
vertical_ = vertical;
|
vertical_ = vertical;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
alignment &alignment::indent(int value)
|
alignment &alignment::indent(int value)
|
||||||
{
|
{
|
||||||
indent_ = value;
|
indent_ = value;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
optional<int> alignment::indent() const
|
optional<int> alignment::indent() const
|
||||||
{
|
{
|
||||||
return indent_;
|
return indent_;
|
||||||
}
|
}
|
||||||
|
|
||||||
alignment &alignment::rotation(int value)
|
alignment &alignment::rotation(int value)
|
||||||
{
|
{
|
||||||
text_rotation_ = value;
|
text_rotation_ = value;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
optional<int> alignment::rotation() const
|
optional<int> alignment::rotation() const
|
||||||
{
|
{
|
||||||
return text_rotation_;
|
return text_rotation_;
|
||||||
}
|
}
|
||||||
|
|
||||||
XLNT_API bool operator==(const alignment &left, const alignment &right)
|
XLNT_API bool operator==(const alignment &left, const alignment &right)
|
||||||
|
@ -98,7 +98,7 @@ XLNT_API bool operator==(const alignment &left, const alignment &right)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (left.horizontal().is_set())
|
if (left.horizontal().is_set())
|
||||||
{
|
{
|
||||||
if (left.horizontal().get() != right.horizontal().get())
|
if (left.horizontal().get() != right.horizontal().get())
|
||||||
|
@ -111,7 +111,7 @@ XLNT_API bool operator==(const alignment &left, const alignment &right)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (left.indent().is_set())
|
if (left.indent().is_set())
|
||||||
{
|
{
|
||||||
if (left.indent().get() != right.indent().get())
|
if (left.indent().get() != right.indent().get())
|
||||||
|
@ -124,7 +124,7 @@ XLNT_API bool operator==(const alignment &left, const alignment &right)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (left.rotation().is_set())
|
if (left.rotation().is_set())
|
||||||
{
|
{
|
||||||
if (left.rotation().get() != right.rotation().get())
|
if (left.rotation().get() != right.rotation().get())
|
||||||
|
@ -132,12 +132,12 @@ XLNT_API bool operator==(const alignment &left, const alignment &right)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (left.shrink().is_set() != right.shrink().is_set())
|
if (left.shrink().is_set() != right.shrink().is_set())
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (left.shrink().is_set())
|
if (left.shrink().is_set())
|
||||||
{
|
{
|
||||||
if (left.shrink().get() != right.shrink().get())
|
if (left.shrink().get() != right.shrink().get())
|
||||||
|
@ -145,12 +145,12 @@ XLNT_API bool operator==(const alignment &left, const alignment &right)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (left.vertical().is_set() != right.vertical().is_set())
|
if (left.vertical().is_set() != right.vertical().is_set())
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (left.vertical().is_set())
|
if (left.vertical().is_set())
|
||||||
{
|
{
|
||||||
if (left.vertical().get() != right.vertical().get())
|
if (left.vertical().get() != right.vertical().get())
|
||||||
|
@ -158,12 +158,12 @@ XLNT_API bool operator==(const alignment &left, const alignment &right)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (left.wrap().is_set() != right.wrap().is_set())
|
if (left.wrap().is_set() != right.wrap().is_set())
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (left.wrap().is_set())
|
if (left.wrap().is_set())
|
||||||
{
|
{
|
||||||
if (left.wrap().get() != right.wrap().get())
|
if (left.wrap().get() != right.wrap().get())
|
||||||
|
@ -171,7 +171,7 @@ XLNT_API bool operator==(const alignment &left, const alignment &right)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,42 +22,41 @@
|
||||||
// @license: http://www.opensource.org/licenses/mit-license.php
|
// @license: http://www.opensource.org/licenses/mit-license.php
|
||||||
// @author: see AUTHORS file
|
// @author: see AUTHORS file
|
||||||
|
|
||||||
#include <detail/default_case.hpp>
|
|
||||||
#include <xlnt/utils/exceptions.hpp>
|
|
||||||
#include <xlnt/styles/border.hpp>
|
#include <xlnt/styles/border.hpp>
|
||||||
|
#include <xlnt/utils/exceptions.hpp>
|
||||||
|
#include <detail/default_case.hpp>
|
||||||
|
|
||||||
namespace xlnt {
|
namespace xlnt {
|
||||||
|
|
||||||
optional<xlnt::color> border::border_property::color() const
|
optional<xlnt::color> border::border_property::color() const
|
||||||
{
|
{
|
||||||
return color_;
|
return color_;
|
||||||
}
|
}
|
||||||
|
|
||||||
border::border_property &border::border_property::color(const xlnt::color &c)
|
border::border_property &border::border_property::color(const xlnt::color &c)
|
||||||
{
|
{
|
||||||
color_ = c;
|
color_ = c;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
optional<border_style> border::border_property::style() const
|
optional<border_style> border::border_property::style() const
|
||||||
{
|
{
|
||||||
return style_;
|
return style_;
|
||||||
}
|
}
|
||||||
|
|
||||||
border::border_property &border::border_property::style(border_style s)
|
border::border_property &border::border_property::style(border_style s)
|
||||||
{
|
{
|
||||||
style_ = s;
|
style_ = s;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator==(const border::border_property &left,
|
bool operator==(const border::border_property &left, const border::border_property &right)
|
||||||
const border::border_property &right)
|
|
||||||
{
|
{
|
||||||
if (left.style().is_set() != right.style().is_set())
|
if (left.style().is_set() != right.style().is_set())
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (left.style().is_set())
|
if (left.style().is_set())
|
||||||
{
|
{
|
||||||
if (left.style().get() != right.style().get())
|
if (left.style().get() != right.style().get())
|
||||||
|
@ -65,12 +64,12 @@ bool operator==(const border::border_property &left,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (left.color().is_set() != right.color().is_set())
|
if (left.color().is_set() != right.color().is_set())
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (left.color().is_set())
|
if (left.color().is_set())
|
||||||
{
|
{
|
||||||
if (left.color().get() != right.color().get())
|
if (left.color().get() != right.color().get())
|
||||||
|
@ -78,7 +77,7 @@ bool operator==(const border::border_property &left,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -88,61 +87,75 @@ border::border()
|
||||||
|
|
||||||
const std::vector<xlnt::border_side> &border::all_sides()
|
const std::vector<xlnt::border_side> &border::all_sides()
|
||||||
{
|
{
|
||||||
static auto *sides = new std::vector<xlnt::border_side>
|
static auto *sides = new std::vector<xlnt::border_side>{xlnt::border_side::start, xlnt::border_side::end,
|
||||||
{
|
xlnt::border_side::top, xlnt::border_side::bottom, xlnt::border_side::diagonal, xlnt::border_side::vertical,
|
||||||
xlnt::border_side::start,
|
xlnt::border_side::horizontal};
|
||||||
xlnt::border_side::end,
|
|
||||||
xlnt::border_side::top,
|
|
||||||
xlnt::border_side::bottom,
|
|
||||||
xlnt::border_side::diagonal,
|
|
||||||
xlnt::border_side::vertical,
|
|
||||||
xlnt::border_side::horizontal
|
|
||||||
};
|
|
||||||
|
|
||||||
return *sides;
|
return *sides;
|
||||||
}
|
}
|
||||||
|
|
||||||
optional<border::border_property> border::side(border_side s) const
|
optional<border::border_property> border::side(border_side s) const
|
||||||
{
|
{
|
||||||
switch (s)
|
switch (s)
|
||||||
{
|
{
|
||||||
case border_side::bottom: return bottom_;
|
case border_side::bottom:
|
||||||
case border_side::top: return top_;
|
return bottom_;
|
||||||
case border_side::start: return start_;
|
case border_side::top:
|
||||||
case border_side::end: return end_;
|
return top_;
|
||||||
case border_side::vertical: return vertical_;
|
case border_side::start:
|
||||||
case border_side::horizontal: return horizontal_;
|
return start_;
|
||||||
case border_side::diagonal: return diagonal_;
|
case border_side::end:
|
||||||
}
|
return end_;
|
||||||
|
case border_side::vertical:
|
||||||
|
return vertical_;
|
||||||
|
case border_side::horizontal:
|
||||||
|
return horizontal_;
|
||||||
|
case border_side::diagonal:
|
||||||
|
return diagonal_;
|
||||||
|
}
|
||||||
|
|
||||||
default_case(start_);
|
default_case(start_);
|
||||||
}
|
}
|
||||||
|
|
||||||
border &border::side(border_side s, const border_property &prop)
|
border &border::side(border_side s, const border_property &prop)
|
||||||
{
|
{
|
||||||
switch (s)
|
switch (s)
|
||||||
{
|
{
|
||||||
case border_side::bottom: bottom_ = prop; break;
|
case border_side::bottom:
|
||||||
case border_side::top: top_ = prop; break;
|
bottom_ = prop;
|
||||||
case border_side::start: start_ = prop; break;
|
break;
|
||||||
case border_side::end: end_ = prop; break;
|
case border_side::top:
|
||||||
case border_side::vertical: vertical_ = prop; break;
|
top_ = prop;
|
||||||
case border_side::horizontal: horizontal_ = prop; break;
|
break;
|
||||||
case border_side::diagonal: diagonal_ = prop; break;
|
case border_side::start:
|
||||||
}
|
start_ = prop;
|
||||||
|
break;
|
||||||
|
case border_side::end:
|
||||||
|
end_ = prop;
|
||||||
|
break;
|
||||||
|
case border_side::vertical:
|
||||||
|
vertical_ = prop;
|
||||||
|
break;
|
||||||
|
case border_side::horizontal:
|
||||||
|
horizontal_ = prop;
|
||||||
|
break;
|
||||||
|
case border_side::diagonal:
|
||||||
|
diagonal_ = prop;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
border &border::diagonal(diagonal_direction direction)
|
border &border::diagonal(diagonal_direction direction)
|
||||||
{
|
{
|
||||||
diagonal_direction_ = direction;
|
diagonal_direction_ = direction;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
optional<diagonal_direction> border::diagonal() const
|
optional<diagonal_direction> border::diagonal() const
|
||||||
{
|
{
|
||||||
return diagonal_direction_;
|
return diagonal_direction_;
|
||||||
}
|
}
|
||||||
|
|
||||||
XLNT_API bool operator==(const border &left, const border &right)
|
XLNT_API bool operator==(const border &left, const border &right)
|
||||||
|
@ -153,7 +166,7 @@ XLNT_API bool operator==(const border &left, const border &right)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (left.side(side).is_set())
|
if (left.side(side).is_set())
|
||||||
{
|
{
|
||||||
if (left.side(side).get() != right.side(side).get())
|
if (left.side(side).get() != right.side(side).get())
|
||||||
|
@ -162,7 +175,7 @@ XLNT_API bool operator==(const border &left, const border &right)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -30,11 +30,13 @@
|
||||||
|
|
||||||
namespace xlnt {
|
namespace xlnt {
|
||||||
|
|
||||||
indexed_color::indexed_color(std::size_t index) : index_(index)
|
indexed_color::indexed_color(std::size_t index)
|
||||||
|
: index_(index)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
theme_color::theme_color(std::size_t index) : index_(index)
|
theme_color::theme_color(std::size_t index)
|
||||||
|
: index_(index)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,42 +91,22 @@ const color color::darkyellow()
|
||||||
}
|
}
|
||||||
|
|
||||||
color::color()
|
color::color()
|
||||||
: type_(color_type::indexed),
|
: type_(color_type::indexed), rgb_(rgb_color(0, 0, 0, 0)), indexed_(0), theme_(0), tint_(0), auto__(false)
|
||||||
rgb_(rgb_color(0, 0, 0, 0)),
|
|
||||||
indexed_(0),
|
|
||||||
theme_(0),
|
|
||||||
tint_(0),
|
|
||||||
auto__(false)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
color::color(const rgb_color &rgb)
|
color::color(const rgb_color &rgb)
|
||||||
: type_(color_type::rgb),
|
: type_(color_type::rgb), rgb_(rgb), indexed_(0), theme_(0), tint_(0), auto__(false)
|
||||||
rgb_(rgb),
|
|
||||||
indexed_(0),
|
|
||||||
theme_(0),
|
|
||||||
tint_(0),
|
|
||||||
auto__(false)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
color::color(const indexed_color &indexed)
|
color::color(const indexed_color &indexed)
|
||||||
: type_(color_type::indexed),
|
: type_(color_type::indexed), rgb_(rgb_color(0, 0, 0, 0)), indexed_(indexed), theme_(0), tint_(0), auto__(false)
|
||||||
rgb_(rgb_color(0, 0, 0, 0)),
|
|
||||||
indexed_(indexed),
|
|
||||||
theme_(0),
|
|
||||||
tint_(0),
|
|
||||||
auto__(false)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
color::color(const theme_color &theme)
|
color::color(const theme_color &theme)
|
||||||
: type_(color_type::theme),
|
: type_(color_type::theme), rgb_(rgb_color(0, 0, 0, 0)), indexed_(0), theme_(theme), tint_(0), auto__(false)
|
||||||
rgb_(rgb_color(0, 0, 0, 0)),
|
|
||||||
indexed_(0),
|
|
||||||
theme_(theme),
|
|
||||||
tint_(0),
|
|
||||||
auto__(false)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -135,7 +117,7 @@ color_type color::type() const
|
||||||
|
|
||||||
bool color::is_auto() const
|
bool color::is_auto() const
|
||||||
{
|
{
|
||||||
return auto__;
|
return auto__;
|
||||||
}
|
}
|
||||||
|
|
||||||
void color::auto_(bool value)
|
void color::auto_(bool value)
|
||||||
|
@ -145,102 +127,100 @@ void color::auto_(bool value)
|
||||||
|
|
||||||
const indexed_color &color::indexed() const
|
const indexed_color &color::indexed() const
|
||||||
{
|
{
|
||||||
assert_type(color_type::indexed);
|
assert_type(color_type::indexed);
|
||||||
return indexed_;
|
return indexed_;
|
||||||
}
|
}
|
||||||
|
|
||||||
const theme_color &color::theme() const
|
const theme_color &color::theme() const
|
||||||
{
|
{
|
||||||
assert_type(color_type::theme);
|
assert_type(color_type::theme);
|
||||||
return theme_;
|
return theme_;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string rgb_color::hex_string() const
|
std::string rgb_color::hex_string() const
|
||||||
{
|
{
|
||||||
static const char* digits = "0123456789abcdef";
|
static const char *digits = "0123456789abcdef";
|
||||||
std::string hex_string(8, '0');
|
std::string hex_string(8, '0');
|
||||||
auto out_iter = hex_string.begin();
|
auto out_iter = hex_string.begin();
|
||||||
|
|
||||||
for (auto byte : { rgba_[3], rgba_[0], rgba_[1], rgba_[2] })
|
for (auto byte : {rgba_[3], rgba_[0], rgba_[1], rgba_[2]})
|
||||||
{
|
{
|
||||||
for (auto i = 0; i < 2; ++i)
|
for (auto i = 0; i < 2; ++i)
|
||||||
{
|
{
|
||||||
auto nibble = byte >> (4 * (1 - i)) & 0xf;
|
auto nibble = byte >> (4 * (1 - i)) & 0xf;
|
||||||
*(out_iter++) = digits[nibble];
|
*(out_iter++) = digits[nibble];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return hex_string;
|
return hex_string;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::array<std::uint8_t, 4> rgb_color::decode_hex_string(const std::string &hex_string)
|
std::array<std::uint8_t, 4> rgb_color::decode_hex_string(const std::string &hex_string)
|
||||||
{
|
{
|
||||||
auto x = std::strtoul(hex_string.c_str(), NULL, 16);
|
auto x = std::strtoul(hex_string.c_str(), NULL, 16);
|
||||||
|
|
||||||
auto a = static_cast<std::uint8_t>(x >> 24);
|
auto a = static_cast<std::uint8_t>(x >> 24);
|
||||||
auto r = static_cast<std::uint8_t>((x >> 16) & 0xff);
|
auto r = static_cast<std::uint8_t>((x >> 16) & 0xff);
|
||||||
auto g = static_cast<std::uint8_t>((x >> 8) & 0xff);
|
auto g = static_cast<std::uint8_t>((x >> 8) & 0xff);
|
||||||
auto b = static_cast<std::uint8_t>(x & 0xff);
|
auto b = static_cast<std::uint8_t>(x & 0xff);
|
||||||
|
|
||||||
return { {r, g, b, a} };
|
return {{r, g, b, a}};
|
||||||
}
|
}
|
||||||
|
|
||||||
rgb_color::rgb_color(const std::string &hex_string)
|
rgb_color::rgb_color(const std::string &hex_string)
|
||||||
: rgba_(decode_hex_string(hex_string))
|
: rgba_(decode_hex_string(hex_string))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
rgb_color::rgb_color(std::uint8_t r, std::uint8_t g, std::uint8_t b, std::uint8_t a)
|
rgb_color::rgb_color(std::uint8_t r, std::uint8_t g, std::uint8_t b, std::uint8_t a)
|
||||||
: rgba_({{r, g, b, a}})
|
: rgba_({{r, g, b, a}})
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
std::size_t indexed_color::index() const
|
std::size_t indexed_color::index() const
|
||||||
{
|
{
|
||||||
return index_;
|
return index_;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::size_t theme_color::index() const
|
std::size_t theme_color::index() const
|
||||||
{
|
{
|
||||||
return index_;
|
return index_;
|
||||||
}
|
}
|
||||||
|
|
||||||
const rgb_color &color::rgb() const
|
const rgb_color &color::rgb() const
|
||||||
{
|
{
|
||||||
assert_type(color_type::rgb);
|
assert_type(color_type::rgb);
|
||||||
return rgb_;
|
return rgb_;
|
||||||
}
|
}
|
||||||
|
|
||||||
void color::tint(double tint)
|
void color::tint(double tint)
|
||||||
{
|
{
|
||||||
tint_ = tint;
|
tint_ = tint;
|
||||||
}
|
}
|
||||||
|
|
||||||
void color::assert_type(color_type t) const
|
void color::assert_type(color_type t) const
|
||||||
{
|
{
|
||||||
if (t != type_)
|
if (t != type_)
|
||||||
{
|
{
|
||||||
throw invalid_attribute();
|
throw invalid_attribute();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
XLNT_API bool color::operator==(const xlnt::color &other) const
|
XLNT_API bool color::operator==(const xlnt::color &other) const
|
||||||
{
|
{
|
||||||
if (type_ != other.type_
|
if (type_ != other.type_ || std::fabs(tint_ - other.tint_) != 0.0 || auto__ != other.auto__)
|
||||||
|| std::fabs(tint_ - other.tint_) != 0.0
|
|
||||||
|| auto__ != other.auto__)
|
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch(type_)
|
switch (type_)
|
||||||
{
|
{
|
||||||
case color_type::indexed:
|
case color_type::indexed:
|
||||||
return indexed_.index() == other.indexed_.index();
|
return indexed_.index() == other.indexed_.index();
|
||||||
case color_type::theme:
|
case color_type::theme:
|
||||||
return theme_.index() == other.theme_.index();
|
return theme_.index() == other.theme_.index();
|
||||||
case color_type::rgb:
|
case color_type::rgb:
|
||||||
return rgb_.hex_string() == other.rgb_.hex_string();
|
return rgb_.hex_string() == other.rgb_.hex_string();
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -32,46 +32,45 @@ namespace xlnt {
|
||||||
|
|
||||||
pattern_fill::pattern_fill()
|
pattern_fill::pattern_fill()
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pattern_fill_type pattern_fill::type() const
|
pattern_fill_type pattern_fill::type() const
|
||||||
{
|
{
|
||||||
return type_;
|
return type_;
|
||||||
}
|
}
|
||||||
|
|
||||||
pattern_fill &pattern_fill::type(pattern_fill_type type)
|
pattern_fill &pattern_fill::type(pattern_fill_type type)
|
||||||
{
|
{
|
||||||
type_ = type;
|
type_ = type;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
optional<color> pattern_fill::foreground() const
|
optional<color> pattern_fill::foreground() const
|
||||||
{
|
{
|
||||||
return foreground_;
|
return foreground_;
|
||||||
}
|
}
|
||||||
|
|
||||||
pattern_fill &pattern_fill::foreground(const color &new_foreground)
|
pattern_fill &pattern_fill::foreground(const color &new_foreground)
|
||||||
{
|
{
|
||||||
foreground_ = new_foreground;
|
foreground_ = new_foreground;
|
||||||
|
|
||||||
if (!background_)
|
if (!background_)
|
||||||
{
|
{
|
||||||
background_.set(indexed_color(64));
|
background_.set(indexed_color(64));
|
||||||
}
|
}
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
optional<color> pattern_fill::background() const
|
optional<color> pattern_fill::background() const
|
||||||
{
|
{
|
||||||
return background_;
|
return background_;
|
||||||
}
|
}
|
||||||
|
|
||||||
pattern_fill &pattern_fill::background(const color &new_background)
|
pattern_fill &pattern_fill::background(const color &new_background)
|
||||||
{
|
{
|
||||||
background_ = new_background;
|
background_ = new_background;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
XLNT_API bool operator==(const pattern_fill &left, const pattern_fill &right)
|
XLNT_API bool operator==(const pattern_fill &left, const pattern_fill &right)
|
||||||
|
@ -80,7 +79,7 @@ XLNT_API bool operator==(const pattern_fill &left, const pattern_fill &right)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (left.background().is_set())
|
if (left.background().is_set())
|
||||||
{
|
{
|
||||||
if (left.background().get() != right.background().get())
|
if (left.background().get() != right.background().get())
|
||||||
|
@ -93,7 +92,7 @@ XLNT_API bool operator==(const pattern_fill &left, const pattern_fill &right)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (left.foreground().is_set())
|
if (left.foreground().is_set())
|
||||||
{
|
{
|
||||||
if (left.foreground().get() != right.foreground().get())
|
if (left.foreground().get() != right.foreground().get())
|
||||||
|
@ -101,103 +100,103 @@ XLNT_API bool operator==(const pattern_fill &left, const pattern_fill &right)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (left.type() != right.type())
|
if (left.type() != right.type())
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// gradient_fill
|
// gradient_fill
|
||||||
|
|
||||||
gradient_fill::gradient_fill() : type_(gradient_fill_type::linear)
|
gradient_fill::gradient_fill()
|
||||||
|
: type_(gradient_fill_type::linear)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
gradient_fill_type gradient_fill::type() const
|
gradient_fill_type gradient_fill::type() const
|
||||||
{
|
{
|
||||||
return type_;
|
return type_;
|
||||||
}
|
}
|
||||||
|
|
||||||
gradient_fill &gradient_fill::type(gradient_fill_type t)
|
gradient_fill &gradient_fill::type(gradient_fill_type t)
|
||||||
{
|
{
|
||||||
type_ = t;
|
type_ = t;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
gradient_fill &gradient_fill::degree(double degree)
|
gradient_fill &gradient_fill::degree(double degree)
|
||||||
{
|
{
|
||||||
degree_ = degree;
|
degree_ = degree;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
double gradient_fill::degree() const
|
double gradient_fill::degree() const
|
||||||
{
|
{
|
||||||
return degree_;
|
return degree_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
double gradient_fill::left() const
|
double gradient_fill::left() const
|
||||||
{
|
{
|
||||||
return left_;
|
return left_;
|
||||||
}
|
}
|
||||||
|
|
||||||
gradient_fill &gradient_fill::left(double value)
|
gradient_fill &gradient_fill::left(double value)
|
||||||
{
|
{
|
||||||
left_ = value;
|
left_ = value;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
double gradient_fill::right() const
|
double gradient_fill::right() const
|
||||||
{
|
{
|
||||||
return right_;
|
return right_;
|
||||||
}
|
}
|
||||||
|
|
||||||
gradient_fill &gradient_fill::right(double value)
|
gradient_fill &gradient_fill::right(double value)
|
||||||
{
|
{
|
||||||
right_ = value;
|
right_ = value;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
double gradient_fill::top() const
|
double gradient_fill::top() const
|
||||||
{
|
{
|
||||||
return top_;
|
return top_;
|
||||||
}
|
}
|
||||||
|
|
||||||
gradient_fill &gradient_fill::top(double value)
|
gradient_fill &gradient_fill::top(double value)
|
||||||
{
|
{
|
||||||
top_ = value;
|
top_ = value;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
double gradient_fill::bottom() const
|
double gradient_fill::bottom() const
|
||||||
{
|
{
|
||||||
return bottom_;
|
return bottom_;
|
||||||
}
|
}
|
||||||
|
|
||||||
gradient_fill &gradient_fill::bottom(double value)
|
gradient_fill &gradient_fill::bottom(double value)
|
||||||
{
|
{
|
||||||
bottom_ = value;
|
bottom_ = value;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
gradient_fill &gradient_fill::add_stop(double position, color stop_color)
|
gradient_fill &gradient_fill::add_stop(double position, color stop_color)
|
||||||
{
|
{
|
||||||
stops_[position] = stop_color;
|
stops_[position] = stop_color;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
gradient_fill &gradient_fill::clear_stops()
|
gradient_fill &gradient_fill::clear_stops()
|
||||||
{
|
{
|
||||||
stops_.clear();
|
stops_.clear();
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unordered_map<double, color> gradient_fill::stops() const
|
std::unordered_map<double, color> gradient_fill::stops() const
|
||||||
{
|
{
|
||||||
return stops_;
|
return stops_;
|
||||||
}
|
}
|
||||||
|
|
||||||
XLNT_API bool operator==(const gradient_fill &left, const gradient_fill &right)
|
XLNT_API bool operator==(const gradient_fill &left, const gradient_fill &right)
|
||||||
|
@ -206,37 +205,37 @@ XLNT_API bool operator==(const gradient_fill &left, const gradient_fill &right)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (std::fabs(left.degree() - right.degree()) != 0.)
|
if (std::fabs(left.degree() - right.degree()) != 0.)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (std::fabs(left.bottom() - right.bottom()) != 0.)
|
if (std::fabs(left.bottom() - right.bottom()) != 0.)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (std::fabs(left.right() - right.right()) != 0.)
|
if (std::fabs(left.right() - right.right()) != 0.)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (std::fabs(left.top() - right.top()) != 0.)
|
if (std::fabs(left.top() - right.top()) != 0.)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (std::fabs(left.left() - right.left()) != 0.)
|
if (std::fabs(left.left() - right.left()) != 0.)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (left.stops() != right.stops())
|
if (left.stops() != right.stops())
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -244,25 +243,22 @@ XLNT_API bool operator==(const gradient_fill &left, const gradient_fill &right)
|
||||||
|
|
||||||
fill fill::solid(const color &fill_color)
|
fill fill::solid(const color &fill_color)
|
||||||
{
|
{
|
||||||
return fill(xlnt::pattern_fill()
|
return fill(
|
||||||
.type(xlnt::pattern_fill_type::solid)
|
xlnt::pattern_fill().type(xlnt::pattern_fill_type::solid).foreground(fill_color).background(indexed_color(64)));
|
||||||
.foreground(fill_color)
|
|
||||||
.background(indexed_color(64)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fill::fill() : type_(fill_type::pattern)
|
fill::fill()
|
||||||
|
: type_(fill_type::pattern)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
fill::fill(const xlnt::pattern_fill &pattern)
|
fill::fill(const xlnt::pattern_fill &pattern)
|
||||||
: type_(fill_type::pattern),
|
: type_(fill_type::pattern), pattern_(pattern)
|
||||||
pattern_(pattern)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
fill::fill(const xlnt::gradient_fill &gradient)
|
fill::fill(const xlnt::gradient_fill &gradient)
|
||||||
: type_(fill_type::gradient),
|
: type_(fill_type::gradient), gradient_(gradient)
|
||||||
gradient_(gradient)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -275,7 +271,7 @@ gradient_fill fill::gradient_fill() const
|
||||||
{
|
{
|
||||||
if (type_ != fill_type::gradient)
|
if (type_ != fill_type::gradient)
|
||||||
{
|
{
|
||||||
throw invalid_attribute();
|
throw invalid_attribute();
|
||||||
}
|
}
|
||||||
|
|
||||||
return gradient_;
|
return gradient_;
|
||||||
|
@ -285,7 +281,7 @@ pattern_fill fill::pattern_fill() const
|
||||||
{
|
{
|
||||||
if (type_ != fill_type::pattern)
|
if (type_ != fill_type::pattern)
|
||||||
{
|
{
|
||||||
throw invalid_attribute();
|
throw invalid_attribute();
|
||||||
}
|
}
|
||||||
|
|
||||||
return pattern_;
|
return pattern_;
|
||||||
|
@ -297,7 +293,7 @@ XLNT_API bool operator==(const fill &left, const fill &right)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (left.type() == fill_type::gradient)
|
if (left.type() == fill_type::gradient)
|
||||||
{
|
{
|
||||||
return left.gradient_fill() == right.gradient_fill();
|
return left.gradient_fill() == right.gradient_fill();
|
||||||
|
|
|
@ -28,7 +28,6 @@
|
||||||
|
|
||||||
namespace xlnt {
|
namespace xlnt {
|
||||||
|
|
||||||
|
|
||||||
font::font()
|
font::font()
|
||||||
: name_("Calibri"),
|
: name_("Calibri"),
|
||||||
size_(12.0),
|
size_(12.0),
|
||||||
|
@ -44,7 +43,7 @@ font::font()
|
||||||
font &font::bold(bool bold)
|
font &font::bold(bool bold)
|
||||||
{
|
{
|
||||||
bold_ = bold;
|
bold_ = bold;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool font::bold() const
|
bool font::bold() const
|
||||||
|
@ -54,19 +53,19 @@ bool font::bold() const
|
||||||
|
|
||||||
font &font::superscript(bool superscript)
|
font &font::superscript(bool superscript)
|
||||||
{
|
{
|
||||||
superscript_ = superscript;
|
superscript_ = superscript;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool font::superscript() const
|
bool font::superscript() const
|
||||||
{
|
{
|
||||||
return superscript_;
|
return superscript_;
|
||||||
}
|
}
|
||||||
|
|
||||||
font &font::italic(bool italic)
|
font &font::italic(bool italic)
|
||||||
{
|
{
|
||||||
italic_ = italic;
|
italic_ = italic;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool font::italic() const
|
bool font::italic() const
|
||||||
|
@ -77,7 +76,7 @@ bool font::italic() const
|
||||||
font &font::strikethrough(bool strikethrough)
|
font &font::strikethrough(bool strikethrough)
|
||||||
{
|
{
|
||||||
strikethrough_ = strikethrough;
|
strikethrough_ = strikethrough;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool font::strikethrough() const
|
bool font::strikethrough() const
|
||||||
|
@ -88,7 +87,7 @@ bool font::strikethrough() const
|
||||||
font &font::underline(underline_style new_underline)
|
font &font::underline(underline_style new_underline)
|
||||||
{
|
{
|
||||||
underline_ = new_underline;
|
underline_ = new_underline;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool font::underlined() const
|
bool font::underlined() const
|
||||||
|
@ -109,7 +108,7 @@ bool font::has_size() const
|
||||||
font &font::size(double size)
|
font &font::size(double size)
|
||||||
{
|
{
|
||||||
size_ = size;
|
size_ = size;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
double font::size() const
|
double font::size() const
|
||||||
|
@ -125,7 +124,7 @@ bool font::has_name() const
|
||||||
font &font::name(const std::string &name)
|
font &font::name(const std::string &name)
|
||||||
{
|
{
|
||||||
name_ = name;
|
name_ = name;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string font::name() const
|
std::string font::name() const
|
||||||
|
@ -141,7 +140,7 @@ bool font::has_color() const
|
||||||
font &font::color(const xlnt::color &c)
|
font &font::color(const xlnt::color &c)
|
||||||
{
|
{
|
||||||
color_ = c;
|
color_ = c;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool font::has_family() const
|
bool font::has_family() const
|
||||||
|
@ -152,7 +151,7 @@ bool font::has_family() const
|
||||||
font &font::family(std::size_t family)
|
font &font::family(std::size_t family)
|
||||||
{
|
{
|
||||||
family_ = family;
|
family_ = family;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool font::has_scheme() const
|
bool font::has_scheme() const
|
||||||
|
@ -163,7 +162,7 @@ bool font::has_scheme() const
|
||||||
font &font::scheme(const std::string &scheme)
|
font &font::scheme(const std::string &scheme)
|
||||||
{
|
{
|
||||||
scheme_ = scheme;
|
scheme_ = scheme;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
color font::color() const
|
color font::color() const
|
||||||
|
@ -192,7 +191,7 @@ XLNT_API bool operator==(const font &left, const font &right)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (left.has_color())
|
if (left.has_color())
|
||||||
{
|
{
|
||||||
if (left.color() != right.color())
|
if (left.color() != right.color())
|
||||||
|
@ -205,7 +204,7 @@ XLNT_API bool operator==(const font &left, const font &right)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (left.has_family())
|
if (left.has_family())
|
||||||
{
|
{
|
||||||
if (left.family() != right.family())
|
if (left.family() != right.family())
|
||||||
|
@ -213,22 +212,22 @@ XLNT_API bool operator==(const font &left, const font &right)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (left.italic() != right.italic())
|
if (left.italic() != right.italic())
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (left.name() != right.name())
|
if (left.name() != right.name())
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (left.has_scheme() != right.has_scheme())
|
if (left.has_scheme() != right.has_scheme())
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (left.has_scheme())
|
if (left.has_scheme())
|
||||||
{
|
{
|
||||||
if (left.scheme() != right.scheme())
|
if (left.scheme() != right.scheme())
|
||||||
|
@ -236,27 +235,27 @@ XLNT_API bool operator==(const font &left, const font &right)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (std::fabs(left.size() - right.size()) != 0.0)
|
if (std::fabs(left.size() - right.size()) != 0.0)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (left.strikethrough() != right.strikethrough())
|
if (left.strikethrough() != right.strikethrough())
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (left.superscript() != right.superscript())
|
if (left.superscript() != right.superscript())
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (left.underline() != right.underline())
|
if (left.underline() != right.underline())
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,20 +22,21 @@
|
||||||
// @license: http://www.opensource.org/licenses/mit-license.php
|
// @license: http://www.opensource.org/licenses/mit-license.php
|
||||||
// @author: see AUTHORS file
|
// @author: see AUTHORS file
|
||||||
|
|
||||||
#include <detail/format_impl.hpp>
|
|
||||||
#include <detail/stylesheet.hpp>
|
|
||||||
#include <xlnt/styles/format.hpp>
|
#include <xlnt/styles/format.hpp>
|
||||||
#include <xlnt/styles/style.hpp>
|
#include <xlnt/styles/style.hpp>
|
||||||
|
#include <detail/format_impl.hpp>
|
||||||
|
#include <detail/stylesheet.hpp>
|
||||||
|
|
||||||
namespace xlnt {
|
namespace xlnt {
|
||||||
|
|
||||||
format::format(detail::format_impl *d) : d_(d)
|
format::format(detail::format_impl *d)
|
||||||
|
: d_(d)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
std::size_t format::id() const
|
std::size_t format::id() const
|
||||||
{
|
{
|
||||||
return d_->id;
|
return d_->id;
|
||||||
}
|
}
|
||||||
|
|
||||||
void format::clear_style()
|
void format::clear_style()
|
||||||
|
@ -45,39 +46,39 @@ void format::clear_style()
|
||||||
|
|
||||||
format format::style(const xlnt::style &new_style)
|
format format::style(const xlnt::style &new_style)
|
||||||
{
|
{
|
||||||
d_ = d_->parent->find_or_create_with(d_, new_style.name());
|
d_ = d_->parent->find_or_create_with(d_, new_style.name());
|
||||||
return format(d_);
|
return format(d_);
|
||||||
}
|
}
|
||||||
|
|
||||||
format format::style(const std::string &new_style)
|
format format::style(const std::string &new_style)
|
||||||
{
|
{
|
||||||
d_->style = new_style;
|
d_->style = new_style;
|
||||||
return format(d_);
|
return format(d_);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool format::has_style() const
|
bool format::has_style() const
|
||||||
{
|
{
|
||||||
return d_->style;
|
return d_->style;
|
||||||
}
|
}
|
||||||
|
|
||||||
const style format::style() const
|
const style format::style() const
|
||||||
{
|
{
|
||||||
if (!has_style())
|
if (!has_style())
|
||||||
{
|
{
|
||||||
throw invalid_attribute();
|
throw invalid_attribute();
|
||||||
}
|
}
|
||||||
|
|
||||||
return d_->parent->style(d_->style.get());
|
return d_->parent->style(d_->style.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
xlnt::alignment &format::alignment()
|
xlnt::alignment &format::alignment()
|
||||||
{
|
{
|
||||||
return d_->parent->alignments.at(d_->alignment_id.get());
|
return d_->parent->alignments.at(d_->alignment_id.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
const xlnt::alignment &format::alignment() const
|
const xlnt::alignment &format::alignment() const
|
||||||
{
|
{
|
||||||
return d_->parent->alignments.at(d_->alignment_id.get());
|
return d_->parent->alignments.at(d_->alignment_id.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
format format::alignment(const xlnt::alignment &new_alignment, bool applied)
|
format format::alignment(const xlnt::alignment &new_alignment, bool applied)
|
||||||
|
@ -88,12 +89,12 @@ format format::alignment(const xlnt::alignment &new_alignment, bool applied)
|
||||||
|
|
||||||
xlnt::border &format::border()
|
xlnt::border &format::border()
|
||||||
{
|
{
|
||||||
return d_->parent->borders.at(d_->border_id.get());
|
return d_->parent->borders.at(d_->border_id.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
const xlnt::border &format::border() const
|
const xlnt::border &format::border() const
|
||||||
{
|
{
|
||||||
return d_->parent->borders.at(d_->border_id.get());
|
return d_->parent->borders.at(d_->border_id.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
format format::border(const xlnt::border &new_border, bool applied)
|
format format::border(const xlnt::border &new_border, bool applied)
|
||||||
|
@ -104,12 +105,12 @@ format format::border(const xlnt::border &new_border, bool applied)
|
||||||
|
|
||||||
xlnt::fill &format::fill()
|
xlnt::fill &format::fill()
|
||||||
{
|
{
|
||||||
return d_->parent->fills.at(d_->fill_id.get());
|
return d_->parent->fills.at(d_->fill_id.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
const xlnt::fill &format::fill() const
|
const xlnt::fill &format::fill() const
|
||||||
{
|
{
|
||||||
return d_->parent->fills.at(d_->fill_id.get());
|
return d_->parent->fills.at(d_->fill_id.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
format format::fill(const xlnt::fill &new_fill, bool applied)
|
format format::fill(const xlnt::fill &new_fill, bool applied)
|
||||||
|
@ -120,12 +121,12 @@ format format::fill(const xlnt::fill &new_fill, bool applied)
|
||||||
|
|
||||||
xlnt::font &format::font()
|
xlnt::font &format::font()
|
||||||
{
|
{
|
||||||
return d_->parent->fonts.at(d_->font_id.get());
|
return d_->parent->fonts.at(d_->font_id.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
const xlnt::font &format::font() const
|
const xlnt::font &format::font() const
|
||||||
{
|
{
|
||||||
return d_->parent->fonts.at(d_->font_id.get());
|
return d_->parent->fonts.at(d_->font_id.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
format format::font(const xlnt::font &new_font, bool applied)
|
format format::font(const xlnt::font &new_font, bool applied)
|
||||||
|
@ -136,23 +137,23 @@ format format::font(const xlnt::font &new_font, bool applied)
|
||||||
|
|
||||||
xlnt::number_format &format::number_format()
|
xlnt::number_format &format::number_format()
|
||||||
{
|
{
|
||||||
return d_->parent->number_formats.at(d_->number_format_id.get());
|
return d_->parent->number_formats.at(d_->number_format_id.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
const xlnt::number_format &format::number_format() const
|
const xlnt::number_format &format::number_format() const
|
||||||
{
|
{
|
||||||
return d_->parent->number_formats.at(d_->number_format_id.get());
|
return d_->parent->number_formats.at(d_->number_format_id.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
format 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;
|
auto copy = new_number_format;
|
||||||
|
|
||||||
if (!copy.has_id())
|
if (!copy.has_id())
|
||||||
{
|
{
|
||||||
copy.id(d_->parent->next_custom_number_format_id());
|
copy.id(d_->parent->next_custom_number_format_id());
|
||||||
d_->parent->number_formats.push_back(copy);
|
d_->parent->number_formats.push_back(copy);
|
||||||
}
|
}
|
||||||
|
|
||||||
d_ = d_->parent->find_or_create_with(d_, copy, applied);
|
d_ = d_->parent->find_or_create_with(d_, copy, applied);
|
||||||
return format(d_);
|
return format(d_);
|
||||||
|
@ -160,12 +161,12 @@ format format::number_format(const xlnt::number_format &new_number_format, bool
|
||||||
|
|
||||||
xlnt::protection &format::protection()
|
xlnt::protection &format::protection()
|
||||||
{
|
{
|
||||||
return d_->parent->protections.at(d_->protection_id.get());
|
return d_->parent->protections.at(d_->protection_id.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
const xlnt::protection &format::protection() const
|
const xlnt::protection &format::protection() const
|
||||||
{
|
{
|
||||||
return d_->parent->protections.at(d_->protection_id.get());
|
return d_->parent->protections.at(d_->protection_id.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
format format::protection(const xlnt::protection &new_protection, bool applied)
|
format format::protection(const xlnt::protection &new_protection, bool applied)
|
||||||
|
|
|
@ -27,54 +27,30 @@
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include <detail/number_formatter.hpp>
|
|
||||||
#include <xlnt/styles/number_format.hpp>
|
#include <xlnt/styles/number_format.hpp>
|
||||||
#include <xlnt/utils/datetime.hpp>
|
#include <xlnt/utils/datetime.hpp>
|
||||||
#include <xlnt/utils/exceptions.hpp>
|
#include <xlnt/utils/exceptions.hpp>
|
||||||
|
#include <detail/number_formatter.hpp>
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
const std::unordered_map<std::size_t, std::string> &builtin_formats()
|
const std::unordered_map<std::size_t, std::string> &builtin_formats()
|
||||||
{
|
{
|
||||||
static const std::unordered_map<std::size_t, std::string> *formats =
|
static const std::unordered_map<std::size_t, std::string> *formats =
|
||||||
new std::unordered_map<std::size_t, std::string>
|
new std::unordered_map<std::size_t, std::string>(
|
||||||
({
|
{{0, "General"}, {1, "0"}, {2, "0.00"}, {3, "#,##0"}, {4, "#,##0.00"}, {9, "0%"}, {10, "0.00%"},
|
||||||
{ 0, "General" },
|
{11, "0.00E+00"}, {12, "# ?/?"}, {13, "# \?\?/??"}, // escape trigraph
|
||||||
{ 1, "0" },
|
{14, "mm-dd-yy"}, {15, "d-mmm-yy"}, {16, "d-mmm"}, {17, "mmm-yy"}, {18, "h:mm AM/PM"},
|
||||||
{ 2, "0.00" },
|
{19, "h:mm:ss AM/PM"}, {20, "h:mm"}, {21, "h:mm:ss"}, {22, "m/d/yy h:mm"}, {37, "#,##0 ;(#,##0)"},
|
||||||
{ 3, "#,##0" },
|
{38, "#,##0 ;[Red](#,##0)"}, {39, "#,##0.00;(#,##0.00)"}, {40, "#,##0.00;[Red](#,##0.00)"},
|
||||||
{ 4, "#,##0.00" },
|
|
||||||
{ 9, "0%" },
|
|
||||||
{ 10, "0.00%" },
|
|
||||||
{ 11, "0.00E+00" },
|
|
||||||
{ 12, "# ?/?" },
|
|
||||||
{ 13, "# \?\?/??" }, // escape trigraph
|
|
||||||
{ 14, "mm-dd-yy" },
|
|
||||||
{ 15, "d-mmm-yy" },
|
|
||||||
{ 16, "d-mmm" },
|
|
||||||
{ 17, "mmm-yy" },
|
|
||||||
{ 18, "h:mm AM/PM" },
|
|
||||||
{ 19, "h:mm:ss AM/PM" },
|
|
||||||
{ 20, "h:mm" },
|
|
||||||
{ 21, "h:mm:ss" },
|
|
||||||
{ 22, "m/d/yy h:mm" },
|
|
||||||
{ 37, "#,##0 ;(#,##0)" },
|
|
||||||
{ 38, "#,##0 ;[Red](#,##0)" },
|
|
||||||
{ 39, "#,##0.00;(#,##0.00)" },
|
|
||||||
{ 40, "#,##0.00;[Red](#,##0.00)" },
|
|
||||||
|
|
||||||
// 41-44 aren't in the ECMA 376 v4 standard, but Libre Office uses them
|
// 41-44 aren't in the ECMA 376 v4 standard, but Libre Office uses them
|
||||||
{ 41, "_(* #,##0_);_(* \\(#,##0\\);_(* \"-\"_);_(@_)" },
|
{41, "_(* #,##0_);_(* \\(#,##0\\);_(* \"-\"_);_(@_)"},
|
||||||
{ 42, "_(\"$\"* #,##0_);_(\"$\"* \\(#,##0\\);_(\"$\"* \"-\"_);_(@_)" },
|
{42, "_(\"$\"* #,##0_);_(\"$\"* \\(#,##0\\);_(\"$\"* \"-\"_);_(@_)"},
|
||||||
{ 43, "_(* #,##0.00_);_(* \\(#,##0.00\\);_(* \"-\"??_);_(@_)" },
|
{43, "_(* #,##0.00_);_(* \\(#,##0.00\\);_(* \"-\"??_);_(@_)"},
|
||||||
{ 44, "_(\"$\"* #,##0.00_)_(\"$\"* \\(#,##0.00\\)_(\"$\"* \"-\"??_)_(@_)" },
|
{44, "_(\"$\"* #,##0.00_)_(\"$\"* \\(#,##0.00\\)_(\"$\"* \"-\"??_)_(@_)"},
|
||||||
|
|
||||||
{ 45, "mm:ss" },
|
{45, "mm:ss"}, {46, "[h]:mm:ss"}, {47, "mmss.0"}, {48, "##0.0E+0"}, {49, "@"}});
|
||||||
{ 46, "[h]:mm:ss" },
|
|
||||||
{ 47, "mmss.0" },
|
|
||||||
{ 48, "##0.0E+0" },
|
|
||||||
{ 49, "@" }
|
|
||||||
});
|
|
||||||
|
|
||||||
return *formats;
|
return *formats;
|
||||||
}
|
}
|
||||||
|
@ -239,20 +215,24 @@ const number_format number_format::date_time6()
|
||||||
return *format;
|
return *format;
|
||||||
}
|
}
|
||||||
|
|
||||||
number_format::number_format() : number_format(general())
|
number_format::number_format()
|
||||||
|
: number_format(general())
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
number_format::number_format(std::size_t id) : number_format(from_builtin_id(id))
|
number_format::number_format(std::size_t id)
|
||||||
|
: number_format(from_builtin_id(id))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
number_format::number_format(const std::string &format_string) : id_set_(false), id_(0)
|
number_format::number_format(const std::string &format_string)
|
||||||
|
: id_set_(false), id_(0)
|
||||||
{
|
{
|
||||||
this->format_string(format_string);
|
this->format_string(format_string);
|
||||||
}
|
}
|
||||||
|
|
||||||
number_format::number_format(const std::string &format_string, std::size_t id) : id_set_(false), id_(0)
|
number_format::number_format(const std::string &format_string, std::size_t id)
|
||||||
|
: id_set_(false), id_(0)
|
||||||
{
|
{
|
||||||
this->format_string(format_string, id);
|
this->format_string(format_string, id);
|
||||||
}
|
}
|
||||||
|
@ -261,7 +241,7 @@ number_format number_format::from_builtin_id(std::size_t builtin_id)
|
||||||
{
|
{
|
||||||
if (builtin_formats().find(builtin_id) == builtin_formats().end())
|
if (builtin_formats().find(builtin_id) == builtin_formats().end())
|
||||||
{
|
{
|
||||||
throw invalid_parameter(); //("unknown id: " + std::to_string(builtin_id));
|
throw invalid_parameter(); //("unknown id: " + std::to_string(builtin_id));
|
||||||
}
|
}
|
||||||
|
|
||||||
auto format_string = builtin_formats().at(builtin_id);
|
auto format_string = builtin_formats().at(builtin_id);
|
||||||
|
@ -310,11 +290,11 @@ void number_format::id(std::size_t id)
|
||||||
|
|
||||||
std::size_t number_format::id() const
|
std::size_t number_format::id() const
|
||||||
{
|
{
|
||||||
if(!id_set_)
|
if (!id_set_)
|
||||||
{
|
{
|
||||||
throw invalid_attribute();
|
throw invalid_attribute();
|
||||||
}
|
}
|
||||||
|
|
||||||
return id_;
|
return id_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,8 @@
|
||||||
|
|
||||||
namespace xlnt {
|
namespace xlnt {
|
||||||
|
|
||||||
protection::protection() : locked_(false), hidden_(false)
|
protection::protection()
|
||||||
|
: locked_(false), hidden_(false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,7 +39,7 @@ bool protection::locked() const
|
||||||
protection &protection::locked(bool locked)
|
protection &protection::locked(bool locked)
|
||||||
{
|
{
|
||||||
locked_ = locked;
|
locked_ = locked;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool protection::hidden() const
|
bool protection::hidden() const
|
||||||
|
@ -49,7 +50,7 @@ bool protection::hidden() const
|
||||||
protection &protection::hidden(bool hidden)
|
protection &protection::hidden(bool hidden)
|
||||||
{
|
{
|
||||||
hidden_ = hidden;
|
hidden_ = hidden;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
XLNT_API bool operator==(const protection &left, const protection &right)
|
XLNT_API bool operator==(const protection &left, const protection &right)
|
||||||
|
|
|
@ -22,7 +22,6 @@
|
||||||
// @license: http://www.opensource.org/licenses/mit-license.php
|
// @license: http://www.opensource.org/licenses/mit-license.php
|
||||||
// @author: see AUTHORS file
|
// @author: see AUTHORS file
|
||||||
|
|
||||||
#include <detail/stylesheet.hpp>
|
|
||||||
#include <xlnt/styles/alignment.hpp>
|
#include <xlnt/styles/alignment.hpp>
|
||||||
#include <xlnt/styles/border.hpp>
|
#include <xlnt/styles/border.hpp>
|
||||||
#include <xlnt/styles/fill.hpp>
|
#include <xlnt/styles/fill.hpp>
|
||||||
|
@ -30,10 +29,12 @@
|
||||||
#include <xlnt/styles/number_format.hpp>
|
#include <xlnt/styles/number_format.hpp>
|
||||||
#include <xlnt/styles/protection.hpp>
|
#include <xlnt/styles/protection.hpp>
|
||||||
#include <xlnt/styles/style.hpp>
|
#include <xlnt/styles/style.hpp>
|
||||||
|
#include <detail/stylesheet.hpp>
|
||||||
|
|
||||||
namespace xlnt {
|
namespace xlnt {
|
||||||
|
|
||||||
style::style(detail::style_impl *d) : d_(d)
|
style::style(detail::style_impl *d)
|
||||||
|
: d_(d)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,7 +46,7 @@ bool style::hidden() const
|
||||||
style style::hidden(bool value)
|
style style::hidden(bool value)
|
||||||
{
|
{
|
||||||
d_->hidden_style = value;
|
d_->hidden_style = value;
|
||||||
return style(d_);
|
return style(d_);
|
||||||
}
|
}
|
||||||
|
|
||||||
optional<std::size_t> style::builtin_id() const
|
optional<std::size_t> style::builtin_id() const
|
||||||
|
@ -56,7 +57,7 @@ optional<std::size_t> style::builtin_id() const
|
||||||
style style::builtin_id(std::size_t builtin_id)
|
style style::builtin_id(std::size_t builtin_id)
|
||||||
{
|
{
|
||||||
d_->builtin_id = builtin_id;
|
d_->builtin_id = builtin_id;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string style::name() const
|
std::string style::name() const
|
||||||
|
@ -67,33 +68,33 @@ std::string style::name() const
|
||||||
style style::name(const std::string &name)
|
style style::name(const std::string &name)
|
||||||
{
|
{
|
||||||
d_->name = name;
|
d_->name = name;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
optional<bool> style::custom() const
|
optional<bool> style::custom() const
|
||||||
{
|
{
|
||||||
return d_->custom_builtin;
|
return d_->custom_builtin;
|
||||||
}
|
}
|
||||||
|
|
||||||
style style::custom(bool value)
|
style style::custom(bool value)
|
||||||
{
|
{
|
||||||
d_->custom_builtin = value;
|
d_->custom_builtin = value;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool style::operator==(const style &other) const
|
bool style::operator==(const style &other) const
|
||||||
{
|
{
|
||||||
return name() == other.name();
|
return name() == other.name();
|
||||||
}
|
}
|
||||||
|
|
||||||
xlnt::alignment &style::alignment()
|
xlnt::alignment &style::alignment()
|
||||||
{
|
{
|
||||||
return d_->parent->alignments.at(d_->alignment_id.get());
|
return d_->parent->alignments.at(d_->alignment_id.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
const xlnt::alignment &style::alignment() const
|
const xlnt::alignment &style::alignment() const
|
||||||
{
|
{
|
||||||
return d_->parent->alignments.at(d_->alignment_id.get());
|
return d_->parent->alignments.at(d_->alignment_id.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
style style::alignment(const xlnt::alignment &new_alignment, bool applied)
|
style style::alignment(const xlnt::alignment &new_alignment, bool applied)
|
||||||
|
@ -105,12 +106,12 @@ style style::alignment(const xlnt::alignment &new_alignment, bool applied)
|
||||||
|
|
||||||
xlnt::border &style::border()
|
xlnt::border &style::border()
|
||||||
{
|
{
|
||||||
return d_->parent->borders.at(d_->border_id.get());
|
return d_->parent->borders.at(d_->border_id.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
const xlnt::border &style::border() const
|
const xlnt::border &style::border() const
|
||||||
{
|
{
|
||||||
return d_->parent->borders.at(d_->border_id.get());
|
return d_->parent->borders.at(d_->border_id.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
style style::border(const xlnt::border &new_border, bool applied)
|
style style::border(const xlnt::border &new_border, bool applied)
|
||||||
|
@ -122,12 +123,12 @@ style style::border(const xlnt::border &new_border, bool applied)
|
||||||
|
|
||||||
xlnt::fill &style::fill()
|
xlnt::fill &style::fill()
|
||||||
{
|
{
|
||||||
return d_->parent->fills.at(d_->fill_id.get());
|
return d_->parent->fills.at(d_->fill_id.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
const xlnt::fill &style::fill() const
|
const xlnt::fill &style::fill() const
|
||||||
{
|
{
|
||||||
return d_->parent->fills.at(d_->fill_id.get());
|
return d_->parent->fills.at(d_->fill_id.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
style style::fill(const xlnt::fill &new_fill, bool applied)
|
style style::fill(const xlnt::fill &new_fill, bool applied)
|
||||||
|
@ -139,12 +140,12 @@ style style::fill(const xlnt::fill &new_fill, bool applied)
|
||||||
|
|
||||||
xlnt::font &style::font()
|
xlnt::font &style::font()
|
||||||
{
|
{
|
||||||
return d_->parent->fonts.at(d_->font_id.get());
|
return d_->parent->fonts.at(d_->font_id.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
const xlnt::font &style::font() const
|
const xlnt::font &style::font() const
|
||||||
{
|
{
|
||||||
return d_->parent->fonts.at(d_->font_id.get());
|
return d_->parent->fonts.at(d_->font_id.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
style style::font(const xlnt::font &new_font, bool applied)
|
style style::font(const xlnt::font &new_font, bool applied)
|
||||||
|
@ -157,34 +158,33 @@ style style::font(const xlnt::font &new_font, bool applied)
|
||||||
xlnt::number_format &style::number_format()
|
xlnt::number_format &style::number_format()
|
||||||
{
|
{
|
||||||
auto tarid = d_->number_format_id.get();
|
auto tarid = d_->number_format_id.get();
|
||||||
return *std::find_if(d_->parent->number_formats.begin(), d_->parent->number_formats.end(),
|
return *std::find_if(d_->parent->number_formats.begin(), d_->parent->number_formats.end(),
|
||||||
[=](const class number_format &nf) { return nf.id() == tarid; });
|
[=](const class number_format &nf) { return nf.id() == tarid; });
|
||||||
}
|
}
|
||||||
|
|
||||||
const xlnt::number_format &style::number_format() const
|
const xlnt::number_format &style::number_format() const
|
||||||
{
|
{
|
||||||
auto tarid = d_->number_format_id.get();
|
auto tarid = d_->number_format_id.get();
|
||||||
return *std::find_if(d_->parent->number_formats.begin(), d_->parent->number_formats.end(),
|
return *std::find_if(d_->parent->number_formats.begin(), d_->parent->number_formats.end(),
|
||||||
[=](const class number_format &nf) { return nf.id() == tarid; });
|
[=](const class number_format &nf) { return nf.id() == tarid; });
|
||||||
}
|
}
|
||||||
|
|
||||||
style style::number_format(const xlnt::number_format &new_number_format, bool applied)
|
style style::number_format(const xlnt::number_format &new_number_format, bool applied)
|
||||||
{
|
{
|
||||||
auto copy = new_number_format;
|
auto copy = new_number_format;
|
||||||
|
|
||||||
if (!copy.has_id())
|
if (!copy.has_id())
|
||||||
{
|
{
|
||||||
copy.id(d_->parent->next_custom_number_format_id());
|
copy.id(d_->parent->next_custom_number_format_id());
|
||||||
d_->parent->number_formats.push_back(copy);
|
d_->parent->number_formats.push_back(copy);
|
||||||
}
|
}
|
||||||
else if (std::find_if(d_->parent->number_formats.begin(),
|
else if (std::find_if(d_->parent->number_formats.begin(), d_->parent->number_formats.end(),
|
||||||
d_->parent->number_formats.end(),
|
[©](const class number_format &nf) { return nf.id() == copy.id(); })
|
||||||
[©](const class number_format &nf) { return nf.id() == copy.id(); })
|
|
||||||
== d_->parent->number_formats.end())
|
== d_->parent->number_formats.end())
|
||||||
{
|
{
|
||||||
d_->parent->number_formats.push_back(copy);
|
d_->parent->number_formats.push_back(copy);
|
||||||
}
|
}
|
||||||
|
|
||||||
d_->number_format_id = copy.id();
|
d_->number_format_id = copy.id();
|
||||||
d_->number_format_applied = applied;
|
d_->number_format_applied = applied;
|
||||||
|
|
||||||
|
@ -193,12 +193,12 @@ style style::number_format(const xlnt::number_format &new_number_format, bool ap
|
||||||
|
|
||||||
xlnt::protection &style::protection()
|
xlnt::protection &style::protection()
|
||||||
{
|
{
|
||||||
return d_->parent->protections.at(d_->protection_id.get());
|
return d_->parent->protections.at(d_->protection_id.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
const xlnt::protection &style::protection() const
|
const xlnt::protection &style::protection() const
|
||||||
{
|
{
|
||||||
return d_->parent->protections.at(d_->protection_id.get());
|
return d_->parent->protections.at(d_->protection_id.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
style style::protection(const xlnt::protection &new_protection, bool applied)
|
style style::protection(const xlnt::protection &new_protection, bool applied)
|
||||||
|
|
|
@ -30,12 +30,12 @@ namespace {
|
||||||
std::tm safe_localtime(std::time_t raw_time)
|
std::tm safe_localtime(std::time_t raw_time)
|
||||||
{
|
{
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
std::tm result;
|
std::tm result;
|
||||||
localtime_s(&result, &raw_time);
|
localtime_s(&result, &raw_time);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
#else
|
#else
|
||||||
return *localtime(&raw_time);
|
return *localtime(&raw_time);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,7 +43,8 @@ std::tm safe_localtime(std::time_t raw_time)
|
||||||
|
|
||||||
namespace xlnt {
|
namespace xlnt {
|
||||||
|
|
||||||
date::date(int year_, int month_, int day_) : year(year_), month(month_), day(day_)
|
date::date(int year_, int month_, int day_)
|
||||||
|
: year(year_), month(month_), day(day_)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -95,9 +96,9 @@ int date::to_number(calendar base_date) const
|
||||||
return 60;
|
return 60;
|
||||||
}
|
}
|
||||||
|
|
||||||
int days_since_1900 = int((1461 * (year + 4800 + int((month - 14) / 12))) / 4) +
|
int days_since_1900 = int((1461 * (year + 4800 + int((month - 14) / 12))) / 4)
|
||||||
int((367 * (month - 2 - 12 * ((month - 14) / 12))) / 12) -
|
+ int((367 * (month - 2 - 12 * ((month - 14) / 12))) / 12)
|
||||||
int((3 * (int((year + 4900 + int((month - 14) / 12)) / 100))) / 4) + day - 2415019 - 32075;
|
- int((3 * (int((year + 4900 + int((month - 14) / 12)) / 100))) / 4) + day - 2415019 - 32075;
|
||||||
|
|
||||||
if (days_since_1900 <= 60)
|
if (days_since_1900 <= 60)
|
||||||
{
|
{
|
||||||
|
@ -124,8 +125,8 @@ int date::weekday() const
|
||||||
auto month_temp = month == 1 ? 13 : month == 2 ? 14 : month;
|
auto month_temp = month == 1 ? 13 : month == 2 ? 14 : month;
|
||||||
auto day_temp = day + 1;
|
auto day_temp = day + 1;
|
||||||
|
|
||||||
auto days = day_temp + static_cast<int>(13 * (month_temp + 1) / 5.0)
|
auto days = day_temp + static_cast<int>(13 * (month_temp + 1) / 5.0) + (year_temp % 100)
|
||||||
+ (year_temp % 100) + static_cast<int>((year_temp % 100) / 4.0);
|
+ static_cast<int>((year_temp % 100) / 4.0);
|
||||||
auto gregorian = days + static_cast<int>(year_temp / 400.0) - 2 * year_temp / 100;
|
auto gregorian = days + static_cast<int>(year_temp / 400.0) - 2 * year_temp / 100;
|
||||||
auto julian = days + 5 - year_temp / 100;
|
auto julian = days + 5 - year_temp / 100;
|
||||||
|
|
||||||
|
|
|
@ -23,20 +23,20 @@
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <ctime>
|
#include <ctime>
|
||||||
|
|
||||||
#include <xlnt/utils/datetime.hpp>
|
|
||||||
#include <xlnt/utils/date.hpp>
|
#include <xlnt/utils/date.hpp>
|
||||||
|
#include <xlnt/utils/datetime.hpp>
|
||||||
#include <xlnt/utils/time.hpp>
|
#include <xlnt/utils/time.hpp>
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
std::string fill(const std::string &string, std::size_t length = 2)
|
std::string fill(const std::string &string, std::size_t length = 2)
|
||||||
{
|
{
|
||||||
if (string.size() >= length)
|
if (string.size() >= length)
|
||||||
{
|
{
|
||||||
return string;
|
return string;
|
||||||
}
|
}
|
||||||
|
|
||||||
return std::string(length - string.size(), '0') + string;
|
return std::string(length - string.size(), '0') + string;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
@ -47,15 +47,15 @@ datetime datetime::from_number(long double raw_time, calendar base_date)
|
||||||
{
|
{
|
||||||
auto date_part = date::from_number(static_cast<int>(raw_time), base_date);
|
auto date_part = date::from_number(static_cast<int>(raw_time), base_date);
|
||||||
auto time_part = time::from_number(raw_time);
|
auto time_part = time::from_number(raw_time);
|
||||||
|
|
||||||
return datetime(date_part.year, date_part.month, date_part.day, time_part.hour, time_part.minute, time_part.second,
|
return datetime(date_part.year, date_part.month, date_part.day, time_part.hour, time_part.minute, time_part.second,
|
||||||
time_part.microsecond);
|
time_part.microsecond);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool datetime::operator==(const datetime &comparand) const
|
bool datetime::operator==(const datetime &comparand) const
|
||||||
{
|
{
|
||||||
return year == comparand.year && month == comparand.month && day == comparand.day && hour == comparand.hour &&
|
return year == comparand.year && month == comparand.month && day == comparand.day && hour == comparand.hour
|
||||||
minute == comparand.minute && second == comparand.second && microsecond == comparand.microsecond;
|
&& minute == comparand.minute && second == comparand.second && microsecond == comparand.microsecond;
|
||||||
}
|
}
|
||||||
|
|
||||||
long double datetime::to_number(calendar base_date) const
|
long double datetime::to_number(calendar base_date) const
|
||||||
|
@ -65,39 +65,33 @@ long double datetime::to_number(calendar base_date) const
|
||||||
|
|
||||||
std::string datetime::to_string() const
|
std::string datetime::to_string() const
|
||||||
{
|
{
|
||||||
return std::to_string(year) + "/" + std::to_string(month) + "/" + std::to_string(day) + " " + std::to_string(hour) +
|
return std::to_string(year) + "/" + std::to_string(month) + "/" + std::to_string(day) + " " + std::to_string(hour)
|
||||||
":" + std::to_string(minute) + ":" + std::to_string(second) + ":" + std::to_string(microsecond);
|
+ ":" + std::to_string(minute) + ":" + std::to_string(second) + ":" + std::to_string(microsecond);
|
||||||
}
|
}
|
||||||
|
|
||||||
datetime datetime::now()
|
datetime datetime::now()
|
||||||
{
|
{
|
||||||
return datetime(date::today(), time::now());
|
return datetime(date::today(), time::now());
|
||||||
}
|
}
|
||||||
|
|
||||||
datetime datetime::today()
|
datetime datetime::today()
|
||||||
{
|
{
|
||||||
return datetime(date::today(), time(0, 0, 0, 0));
|
return datetime(date::today(), time(0, 0, 0, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
datetime::datetime(int year_, int month_, int day_, int hour_, int minute_, int second_, int microsecond_)
|
datetime::datetime(int year_, int month_, int day_, int hour_, int minute_, int second_, int microsecond_)
|
||||||
: year(year_),
|
: year(year_), month(month_), day(day_), hour(hour_), minute(minute_), second(second_), microsecond(microsecond_)
|
||||||
month(month_),
|
|
||||||
day(day_),
|
|
||||||
hour(hour_),
|
|
||||||
minute(minute_),
|
|
||||||
second(second_),
|
|
||||||
microsecond(microsecond_)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
datetime::datetime(const date &d, const time &t)
|
datetime::datetime(const date &d, const time &t)
|
||||||
: year(d.year),
|
: year(d.year),
|
||||||
month(d.month),
|
month(d.month),
|
||||||
day(d.day),
|
day(d.day),
|
||||||
hour(t.hour),
|
hour(t.hour),
|
||||||
minute(t.minute),
|
minute(t.minute),
|
||||||
second(t.second),
|
second(t.second),
|
||||||
microsecond(t.microsecond)
|
microsecond(t.microsecond)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -127,12 +121,8 @@ datetime datetime::from_iso_string(const std::string &string)
|
||||||
|
|
||||||
std::string datetime::to_iso_string() const
|
std::string datetime::to_iso_string() const
|
||||||
{
|
{
|
||||||
return std::to_string(year) + "-"
|
return std::to_string(year) + "-" + fill(std::to_string(month)) + "-" + fill(std::to_string(day)) + "T"
|
||||||
+ fill(std::to_string(month)) + "-"
|
+ fill(std::to_string(hour)) + ":" + fill(std::to_string(minute)) + ":" + fill(std::to_string(second)) + "Z";
|
||||||
+ fill(std::to_string(day)) + "T"
|
|
||||||
+ fill(std::to_string(hour)) + ":"
|
|
||||||
+ fill(std::to_string(minute)) + ":"
|
|
||||||
+ fill(std::to_string(second)) + "Z";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace xlnt
|
} // namespace xlnt
|
||||||
|
|
|
@ -86,8 +86,8 @@ invalid_file::~invalid_file()
|
||||||
}
|
}
|
||||||
|
|
||||||
invalid_cell_reference::invalid_cell_reference(column_t column, row_t row)
|
invalid_cell_reference::invalid_cell_reference(column_t column, row_t row)
|
||||||
: exception(std::string("bad cell coordinates: (") + std::to_string(column.index) + ", " + std::to_string(row) +
|
: exception(
|
||||||
")")
|
std::string("bad cell coordinates: (") + std::to_string(column.index) + ", " + std::to_string(row) + ")")
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -146,7 +146,7 @@ no_visible_worksheets::~no_visible_worksheets()
|
||||||
}
|
}
|
||||||
|
|
||||||
unsupported::unsupported(const std::string &message)
|
unsupported::unsupported(const std::string &message)
|
||||||
: exception(message)
|
: exception(message)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,13 +27,13 @@
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
#include <mach-o/dyld.h>
|
#include <mach-o/dyld.h>
|
||||||
#elif defined(__linux)
|
#elif defined(__linux)
|
||||||
#include <unistd.h>
|
|
||||||
#include <linux/limits.h>
|
#include <linux/limits.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
#include <unistd.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <detail/include_windows.hpp>
|
|
||||||
#include <xlnt/utils/path.hpp>
|
#include <xlnt/utils/path.hpp>
|
||||||
|
#include <detail/include_windows.hpp>
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
@ -41,44 +41,42 @@ namespace {
|
||||||
|
|
||||||
char system_separator()
|
char system_separator()
|
||||||
{
|
{
|
||||||
return '\\';
|
return '\\';
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_drive_letter(char letter)
|
bool is_drive_letter(char letter)
|
||||||
{
|
{
|
||||||
return letter >= 'A' && letter <= 'Z';
|
return letter >= 'A' && letter <= 'Z';
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_root(const std::string &part)
|
bool is_root(const std::string &part)
|
||||||
{
|
{
|
||||||
if (part.size() == 1 && part[0] == '/') return true;
|
if (part.size() == 1 && part[0] == '/') return true;
|
||||||
if (part.size() != 3) return false;
|
if (part.size() != 3) return false;
|
||||||
|
|
||||||
return is_drive_letter(part[0]) && part[1] == ':'
|
return is_drive_letter(part[0]) && part[1] == ':' && (part[2] == '\\' || part[2] == '/');
|
||||||
&& (part[2] == '\\' || part[2] == '/');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_absolute(const std::string &part)
|
bool is_absolute(const std::string &part)
|
||||||
{
|
{
|
||||||
if (!part.empty() && part[0] == '/') return true;
|
if (!part.empty() && part[0] == '/') return true;
|
||||||
if (part.size() < 3) return false;
|
if (part.size() < 3) return false;
|
||||||
|
|
||||||
return is_root(part.substr(0, 3));
|
return is_root(part.substr(0, 3));
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
char system_separator()
|
char system_separator()
|
||||||
{
|
{
|
||||||
return '/';
|
return '/';
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_root(const std::string &part)
|
bool is_root(const std::string &part)
|
||||||
{
|
{
|
||||||
return part == "/";
|
return part == "/";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool is_absolute(const std::string &part)
|
bool is_absolute(const std::string &part)
|
||||||
{
|
{
|
||||||
return !part.empty() && part[0] == '/';
|
return !part.empty() && part[0] == '/';
|
||||||
|
@ -88,38 +86,38 @@ bool is_absolute(const std::string &part)
|
||||||
|
|
||||||
std::vector<std::string> split_path(const std::string &path, char delim)
|
std::vector<std::string> split_path(const std::string &path, char delim)
|
||||||
{
|
{
|
||||||
std::vector<std::string> split;
|
std::vector<std::string> split;
|
||||||
std::string::size_type previous_index = 0;
|
std::string::size_type previous_index = 0;
|
||||||
auto separator_index = path.find(delim);
|
auto separator_index = path.find(delim);
|
||||||
|
|
||||||
while (separator_index != std::string::npos)
|
while (separator_index != std::string::npos)
|
||||||
{
|
{
|
||||||
auto part = path.substr(previous_index, separator_index - previous_index);
|
auto part = path.substr(previous_index, separator_index - previous_index);
|
||||||
split.push_back(part);
|
split.push_back(part);
|
||||||
|
|
||||||
previous_index = separator_index + 1;
|
previous_index = separator_index + 1;
|
||||||
separator_index = path.find(delim, previous_index);
|
separator_index = path.find(delim, previous_index);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Don't add trailing slash
|
// Don't add trailing slash
|
||||||
if (previous_index < path.size())
|
if (previous_index < path.size())
|
||||||
{
|
{
|
||||||
split.push_back(path.substr(previous_index));
|
split.push_back(path.substr(previous_index));
|
||||||
}
|
}
|
||||||
|
|
||||||
return split;
|
return split;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool file_exists(const std::string &path)
|
bool file_exists(const std::string &path)
|
||||||
{
|
{
|
||||||
struct stat info;
|
struct stat info;
|
||||||
return stat(path.c_str(), &info) == 0 && (info.st_mode & S_IFREG);
|
return stat(path.c_str(), &info) == 0 && (info.st_mode & S_IFREG);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool directory_exists(const std::string path)
|
bool directory_exists(const std::string path)
|
||||||
{
|
{
|
||||||
struct stat info;
|
struct stat info;
|
||||||
return stat(path.c_str(), &info) == 0 && (info.st_mode & S_IFDIR);
|
return stat(path.c_str(), &info) == 0 && (info.st_mode & S_IFDIR);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
@ -128,27 +126,28 @@ namespace xlnt {
|
||||||
|
|
||||||
char path::system_separator()
|
char path::system_separator()
|
||||||
{
|
{
|
||||||
return ::system_separator();
|
return ::system_separator();
|
||||||
}
|
}
|
||||||
|
|
||||||
path::path()
|
path::path()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
path::path(const std::string &path_string) : internal_(path_string)
|
path::path(const std::string &path_string)
|
||||||
|
: internal_(path_string)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
// general attributes
|
// general attributes
|
||||||
|
|
||||||
bool path::is_relative() const
|
bool path::is_relative() const
|
||||||
{
|
{
|
||||||
return !is_absolute();
|
return !is_absolute();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool path::is_absolute() const
|
bool path::is_absolute() const
|
||||||
{
|
{
|
||||||
return ::is_absolute(internal_);
|
return ::is_absolute(internal_);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool path::is_root() const
|
bool path::is_root() const
|
||||||
|
@ -161,44 +160,44 @@ path path::parent() const
|
||||||
if (is_root()) return *this;
|
if (is_root()) return *this;
|
||||||
|
|
||||||
auto split_path = split();
|
auto split_path = split();
|
||||||
|
|
||||||
split_path.pop_back();
|
split_path.pop_back();
|
||||||
|
|
||||||
if (split_path.empty())
|
if (split_path.empty())
|
||||||
{
|
{
|
||||||
return path("");
|
return path("");
|
||||||
}
|
}
|
||||||
|
|
||||||
path result;
|
path result;
|
||||||
|
|
||||||
for (const auto &component : split_path)
|
for (const auto &component : split_path)
|
||||||
{
|
{
|
||||||
result = result.append(component);
|
result = result.append(component);
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string path::filename() const
|
std::string path::filename() const
|
||||||
{
|
{
|
||||||
auto split_path = split();
|
auto split_path = split();
|
||||||
return split_path.empty() ? "" : split_path.back();
|
return split_path.empty() ? "" : split_path.back();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string path::extension() const
|
std::string path::extension() const
|
||||||
{
|
{
|
||||||
auto base = filename();
|
auto base = filename();
|
||||||
auto last_dot = base.find_last_of('.');
|
auto last_dot = base.find_last_of('.');
|
||||||
|
|
||||||
return last_dot == std::string::npos ? "" : base.substr(last_dot + 1);
|
return last_dot == std::string::npos ? "" : base.substr(last_dot + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<std::string, std::string> path::split_extension() const
|
std::pair<std::string, std::string> path::split_extension() const
|
||||||
{
|
{
|
||||||
auto base = filename();
|
auto base = filename();
|
||||||
auto last_dot = base.find_last_of('.');
|
auto last_dot = base.find_last_of('.');
|
||||||
|
|
||||||
return{ base.substr(0, last_dot), base.substr(last_dot + 1) };
|
return {base.substr(0, last_dot), base.substr(last_dot + 1)};
|
||||||
}
|
}
|
||||||
|
|
||||||
// conversion
|
// conversion
|
||||||
|
@ -215,18 +214,18 @@ std::vector<std::string> path::split() const
|
||||||
|
|
||||||
path path::resolve(const path &base_path) const
|
path path::resolve(const path &base_path) const
|
||||||
{
|
{
|
||||||
if (is_absolute())
|
if (is_absolute())
|
||||||
{
|
{
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
path copy(base_path.internal_);
|
path copy(base_path.internal_);
|
||||||
|
|
||||||
for (const auto &part : split())
|
for (const auto &part : split())
|
||||||
{
|
{
|
||||||
copy = copy.append(part);
|
copy = copy.append(part);
|
||||||
}
|
}
|
||||||
|
|
||||||
return copy;
|
return copy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -234,28 +233,28 @@ path path::resolve(const path &base_path) const
|
||||||
|
|
||||||
bool path::exists() const
|
bool path::exists() const
|
||||||
{
|
{
|
||||||
return is_file() || is_directory();
|
return is_file() || is_directory();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool path::is_directory() const
|
bool path::is_directory() const
|
||||||
{
|
{
|
||||||
return directory_exists(string());
|
return directory_exists(string());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool path::is_file() const
|
bool path::is_file() const
|
||||||
{
|
{
|
||||||
return file_exists(string());
|
return file_exists(string());
|
||||||
}
|
}
|
||||||
|
|
||||||
// filesystem
|
// filesystem
|
||||||
|
|
||||||
std::string path::read_contents() const
|
std::string path::read_contents() const
|
||||||
{
|
{
|
||||||
std::ifstream f(string());
|
std::ifstream f(string());
|
||||||
std::ostringstream ss;
|
std::ostringstream ss;
|
||||||
ss << f.rdbuf();
|
ss << f.rdbuf();
|
||||||
|
|
||||||
return ss.str();
|
return ss.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
// append
|
// append
|
||||||
|
@ -263,27 +262,27 @@ std::string path::read_contents() const
|
||||||
path path::append(const std::string &to_append) const
|
path path::append(const std::string &to_append) const
|
||||||
{
|
{
|
||||||
path copy(internal_);
|
path copy(internal_);
|
||||||
|
|
||||||
if (!internal_.empty() && internal_.back() != guess_separator())
|
if (!internal_.empty() && internal_.back() != guess_separator())
|
||||||
{
|
{
|
||||||
copy.internal_.push_back(guess_separator());
|
copy.internal_.push_back(guess_separator());
|
||||||
}
|
}
|
||||||
|
|
||||||
copy.internal_.append(to_append);
|
copy.internal_.append(to_append);
|
||||||
|
|
||||||
return copy;
|
return copy;
|
||||||
}
|
}
|
||||||
|
|
||||||
path path::append(const path &to_append) const
|
path path::append(const path &to_append) const
|
||||||
{
|
{
|
||||||
path copy(internal_);
|
path copy(internal_);
|
||||||
|
|
||||||
for (const auto &component : to_append.split())
|
for (const auto &component : to_append.split())
|
||||||
{
|
{
|
||||||
copy = copy.append(component);
|
copy = copy.append(component);
|
||||||
}
|
}
|
||||||
|
|
||||||
return copy;
|
return copy;
|
||||||
}
|
}
|
||||||
|
|
||||||
char path::guess_separator() const
|
char path::guess_separator() const
|
||||||
|
|
|
@ -30,12 +30,12 @@ namespace {
|
||||||
std::tm safe_localtime(std::time_t raw_time)
|
std::tm safe_localtime(std::time_t raw_time)
|
||||||
{
|
{
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
std::tm result;
|
std::tm result;
|
||||||
localtime_s(&result, &raw_time);
|
localtime_s(&result, &raw_time);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
#else
|
#else
|
||||||
return *localtime(&raw_time);
|
return *localtime(&raw_time);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,18 +58,18 @@ time time::from_number(long double raw_time)
|
||||||
result.second = static_cast<int>(fractional_part);
|
result.second = static_cast<int>(fractional_part);
|
||||||
fractional_part = 1000000 * (fractional_part - result.second);
|
fractional_part = 1000000 * (fractional_part - result.second);
|
||||||
result.microsecond = static_cast<int>(fractional_part);
|
result.microsecond = static_cast<int>(fractional_part);
|
||||||
|
|
||||||
if (result.microsecond == 999999 && fractional_part - result.microsecond > 0.5)
|
if (result.microsecond == 999999 && fractional_part - result.microsecond > 0.5)
|
||||||
{
|
{
|
||||||
result.microsecond = 0;
|
result.microsecond = 0;
|
||||||
result.second += 1;
|
result.second += 1;
|
||||||
|
|
||||||
if (result.second == 60)
|
if (result.second == 60)
|
||||||
{
|
{
|
||||||
result.second = 0;
|
result.second = 0;
|
||||||
result.minute += 1;
|
result.minute += 1;
|
||||||
|
|
||||||
//TODO: too much nesting
|
// TODO: too much nesting
|
||||||
if (result.minute == 60)
|
if (result.minute == 60)
|
||||||
{
|
{
|
||||||
result.minute = 0;
|
result.minute = 0;
|
||||||
|
@ -77,7 +77,7 @@ time time::from_number(long double raw_time)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -88,11 +88,12 @@ time::time(int hour_, int minute_, int second_, int microsecond_)
|
||||||
|
|
||||||
bool time::operator==(const time &comparand) const
|
bool time::operator==(const time &comparand) const
|
||||||
{
|
{
|
||||||
return hour == comparand.hour && minute == comparand.minute && second == comparand.second &&
|
return hour == comparand.hour && minute == comparand.minute && second == comparand.second
|
||||||
microsecond == comparand.microsecond;
|
&& microsecond == comparand.microsecond;
|
||||||
}
|
}
|
||||||
|
|
||||||
time::time(const std::string &time_string) : hour(0), minute(0), second(0), microsecond(0)
|
time::time(const std::string &time_string)
|
||||||
|
: hour(0), minute(0), second(0), microsecond(0)
|
||||||
{
|
{
|
||||||
std::string remaining = time_string;
|
std::string remaining = time_string;
|
||||||
auto colon_index = remaining.find(':');
|
auto colon_index = remaining.find(':');
|
||||||
|
@ -101,7 +102,7 @@ time::time(const std::string &time_string) : hour(0), minute(0), second(0), micr
|
||||||
colon_index = remaining.find(':');
|
colon_index = remaining.find(':');
|
||||||
minute = std::stoi(remaining.substr(0, colon_index));
|
minute = std::stoi(remaining.substr(0, colon_index));
|
||||||
colon_index = remaining.find(':');
|
colon_index = remaining.find(':');
|
||||||
|
|
||||||
if (colon_index != std::string::npos)
|
if (colon_index != std::string::npos)
|
||||||
{
|
{
|
||||||
remaining = remaining.substr(colon_index + 1);
|
remaining = remaining.substr(colon_index + 1);
|
||||||
|
@ -114,19 +115,19 @@ long double time::to_number() const
|
||||||
std::uint64_t microseconds = static_cast<std::uint64_t>(microsecond);
|
std::uint64_t microseconds = static_cast<std::uint64_t>(microsecond);
|
||||||
microseconds += static_cast<std::uint64_t>(second * 1e6);
|
microseconds += static_cast<std::uint64_t>(second * 1e6);
|
||||||
microseconds += static_cast<std::uint64_t>(minute * 1e6 * 60);
|
microseconds += static_cast<std::uint64_t>(minute * 1e6 * 60);
|
||||||
auto microseconds_per_hour = static_cast<std::uint64_t>(1e6) * 60 * 60;
|
auto microseconds_per_hour = static_cast<std::uint64_t>(1e6) * 60 * 60;
|
||||||
microseconds += static_cast<std::uint64_t>(hour) * microseconds_per_hour;
|
microseconds += static_cast<std::uint64_t>(hour) * microseconds_per_hour;
|
||||||
auto number = microseconds / (24.0L * microseconds_per_hour);
|
auto number = microseconds / (24.0L * microseconds_per_hour);
|
||||||
auto hundred_billion = static_cast<std::uint64_t>(1e9) * 100;
|
auto hundred_billion = static_cast<std::uint64_t>(1e9) * 100;
|
||||||
number = std::floor(number * hundred_billion + 0.5L) / hundred_billion;
|
number = std::floor(number * hundred_billion + 0.5L) / hundred_billion;
|
||||||
|
|
||||||
return number;
|
return number;
|
||||||
}
|
}
|
||||||
|
|
||||||
time time::now()
|
time time::now()
|
||||||
{
|
{
|
||||||
std::tm now = safe_localtime(std::time(0));
|
std::tm now = safe_localtime(std::time(0));
|
||||||
return time(now.tm_hour, now.tm_min, now.tm_sec);
|
return time(now.tm_hour, now.tm_min, now.tm_sec);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace xlnt
|
} // namespace xlnt
|
||||||
|
|
|
@ -27,18 +27,15 @@
|
||||||
|
|
||||||
namespace xlnt {
|
namespace xlnt {
|
||||||
|
|
||||||
timedelta::timedelta() : timedelta(0, 0, 0, 0, 0)
|
timedelta::timedelta()
|
||||||
|
: timedelta(0, 0, 0, 0, 0)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
timedelta::timedelta(int days_, int hours_, int minutes_, int seconds_, int microseconds_)
|
timedelta::timedelta(int days_, int hours_, int minutes_, int seconds_, int microseconds_)
|
||||||
: days(days_),
|
: days(days_), hours(hours_), minutes(minutes_), seconds(seconds_), microseconds(microseconds_)
|
||||||
hours(hours_),
|
{
|
||||||
minutes(minutes_),
|
}
|
||||||
seconds(seconds_),
|
|
||||||
microseconds(microseconds_)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
long double timedelta::to_number() const
|
long double timedelta::to_number() const
|
||||||
{
|
{
|
||||||
|
@ -51,7 +48,7 @@ long double timedelta::to_number() const
|
||||||
auto hundred_billion = static_cast<std::uint64_t>(1e9) * 100;
|
auto hundred_billion = static_cast<std::uint64_t>(1e9) * 100;
|
||||||
number = std::floor(number * hundred_billion + 0.5L) / hundred_billion;
|
number = std::floor(number * hundred_billion + 0.5L) / hundred_billion;
|
||||||
number += days;
|
number += days;
|
||||||
|
|
||||||
return number;
|
return number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,23 +67,23 @@ timedelta timedelta::from_number(long double raw_time)
|
||||||
result.seconds = static_cast<int>(fractional_part);
|
result.seconds = static_cast<int>(fractional_part);
|
||||||
fractional_part = 1000000 * (fractional_part - result.seconds);
|
fractional_part = 1000000 * (fractional_part - result.seconds);
|
||||||
result.microseconds = static_cast<int>(fractional_part);
|
result.microseconds = static_cast<int>(fractional_part);
|
||||||
|
|
||||||
if (result.microseconds == 999999 && fractional_part - result.microseconds > 0.5L)
|
if (result.microseconds == 999999 && fractional_part - result.microseconds > 0.5L)
|
||||||
{
|
{
|
||||||
result.microseconds = 0;
|
result.microseconds = 0;
|
||||||
result.seconds += 1;
|
result.seconds += 1;
|
||||||
|
|
||||||
if (result.seconds == 60)
|
if (result.seconds == 60)
|
||||||
{
|
{
|
||||||
result.seconds = 0;
|
result.seconds = 0;
|
||||||
result.minutes += 1;
|
result.minutes += 1;
|
||||||
|
|
||||||
//TODO: too much nesting
|
// TODO: too much nesting
|
||||||
if (result.minutes == 60)
|
if (result.minutes == 60)
|
||||||
{
|
{
|
||||||
result.minutes = 0;
|
result.minutes = 0;
|
||||||
result.hours += 1;
|
result.hours += 1;
|
||||||
|
|
||||||
if (result.hours == 24)
|
if (result.hours == 24)
|
||||||
{
|
{
|
||||||
result.hours = 0;
|
result.hours = 0;
|
||||||
|
@ -95,7 +92,7 @@ timedelta timedelta::from_number(long double raw_time)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,11 +27,13 @@
|
||||||
|
|
||||||
namespace xlnt {
|
namespace xlnt {
|
||||||
|
|
||||||
const_worksheet_iterator::const_worksheet_iterator(const workbook &wb, std::size_t index) : wb_(wb), index_(index)
|
const_worksheet_iterator::const_worksheet_iterator(const workbook &wb, std::size_t index)
|
||||||
|
: wb_(wb), index_(index)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
const_worksheet_iterator::const_worksheet_iterator(const const_worksheet_iterator &rhs) : wb_(rhs.wb_), index_(rhs.index_)
|
const_worksheet_iterator::const_worksheet_iterator(const const_worksheet_iterator &rhs)
|
||||||
|
: wb_(rhs.wb_), index_(rhs.index_)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -27,11 +27,13 @@
|
||||||
|
|
||||||
namespace xlnt {
|
namespace xlnt {
|
||||||
|
|
||||||
worksheet_iterator::worksheet_iterator(workbook &wb, std::size_t index) : wb_(wb), index_(index)
|
worksheet_iterator::worksheet_iterator(workbook &wb, std::size_t index)
|
||||||
|
: wb_(wb), index_(index)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
worksheet_iterator::worksheet_iterator(const worksheet_iterator &rhs) : wb_(rhs.wb_), index_(rhs.index_)
|
worksheet_iterator::worksheet_iterator(const worksheet_iterator &rhs)
|
||||||
|
: wb_(rhs.wb_), index_(rhs.index_)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,12 +27,16 @@
|
||||||
|
|
||||||
namespace xlnt {
|
namespace xlnt {
|
||||||
|
|
||||||
cell_iterator::cell_iterator(worksheet ws, const cell_reference &start_cell, const range_reference &limits, major_order order)
|
cell_iterator::cell_iterator(worksheet ws, const cell_reference &start_cell,
|
||||||
: ws_(ws), current_cell_(start_cell), range_(limits), order_(order)
|
const range_reference &limits, major_order order)
|
||||||
|
: ws_(ws),
|
||||||
|
current_cell_(start_cell),
|
||||||
|
range_(limits),
|
||||||
|
order_(order)
|
||||||
{
|
{
|
||||||
if (!ws.has_cell(current_cell_))
|
if (!ws.has_cell(current_cell_))
|
||||||
{
|
{
|
||||||
(*this)++;
|
(*this)++; // move to the next non-empty cell or one past the end if none exists
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,7 +47,9 @@ cell_iterator::cell_iterator(const cell_iterator &other)
|
||||||
|
|
||||||
bool cell_iterator::operator==(const cell_iterator &other) const
|
bool cell_iterator::operator==(const cell_iterator &other) const
|
||||||
{
|
{
|
||||||
return ws_ == other.ws_ && current_cell_ == other.current_cell_ && order_ == other.order_;
|
return ws_ == other.ws_
|
||||||
|
&& current_cell_ == other.current_cell_
|
||||||
|
&& order_ == other.order_;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool cell_iterator::operator!=(const cell_iterator &other) const
|
bool cell_iterator::operator!=(const cell_iterator &other) const
|
||||||
|
@ -56,7 +62,7 @@ cell_iterator &cell_iterator::operator--()
|
||||||
if (order_ == major_order::row)
|
if (order_ == major_order::row)
|
||||||
{
|
{
|
||||||
current_cell_.column_index(current_cell_.column_index() - 1);
|
current_cell_.column_index(current_cell_.column_index() - 1);
|
||||||
|
|
||||||
while (!ws_.has_cell(current_cell_) && current_cell_.column() > range_.top_left().column())
|
while (!ws_.has_cell(current_cell_) && current_cell_.column() > range_.top_left().column())
|
||||||
{
|
{
|
||||||
current_cell_.column_index(current_cell_.column_index() - 1);
|
current_cell_.column_index(current_cell_.column_index() - 1);
|
||||||
|
@ -90,7 +96,7 @@ cell_iterator &cell_iterator::operator++()
|
||||||
{
|
{
|
||||||
current_cell_.column_index(current_cell_.column_index() + 1);
|
current_cell_.column_index(current_cell_.column_index() + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
while (!ws_.has_cell(current_cell_) && current_cell_.column() <= range_.bottom_right().column())
|
while (!ws_.has_cell(current_cell_) && current_cell_.column() <= range_.bottom_right().column())
|
||||||
{
|
{
|
||||||
current_cell_.column_index(current_cell_.column_index() + 1);
|
current_cell_.column_index(current_cell_.column_index() + 1);
|
||||||
|
@ -116,6 +122,7 @@ cell_iterator cell_iterator::operator++(int)
|
||||||
{
|
{
|
||||||
cell_iterator old = *this;
|
cell_iterator old = *this;
|
||||||
++*this;
|
++*this;
|
||||||
|
|
||||||
return old;
|
return old;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -38,11 +38,13 @@ cell_vector::iterator cell_vector::end()
|
||||||
{
|
{
|
||||||
auto past_end = ref_.bottom_right();
|
auto past_end = ref_.bottom_right();
|
||||||
past_end.column_index(past_end.column_index() + 1);
|
past_end.column_index(past_end.column_index() + 1);
|
||||||
|
|
||||||
return iterator(ws_, past_end, ref_, order_);
|
return iterator(ws_, past_end, ref_, order_);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto past_end = ref_.bottom_right();
|
auto past_end = ref_.bottom_right();
|
||||||
past_end.row(past_end.row() + 1);
|
past_end.row(past_end.row() + 1);
|
||||||
|
|
||||||
return iterator(ws_, past_end, ref_, order_);
|
return iterator(ws_, past_end, ref_, order_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,11 +59,13 @@ cell_vector::const_iterator cell_vector::cend() const
|
||||||
{
|
{
|
||||||
auto past_end = ref_.bottom_right();
|
auto past_end = ref_.bottom_right();
|
||||||
past_end.column_index(past_end.column_index() + 1);
|
past_end.column_index(past_end.column_index() + 1);
|
||||||
|
|
||||||
return const_iterator(ws_, past_end, order_);
|
return const_iterator(ws_, past_end, order_);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto past_end = ref_.bottom_right();
|
auto past_end = ref_.bottom_right();
|
||||||
past_end.row(past_end.row() + 1);
|
past_end.row(past_end.row() + 1);
|
||||||
|
|
||||||
return const_iterator(ws_, past_end, order_);
|
return const_iterator(ws_, past_end, order_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -102,9 +106,7 @@ cell cell_vector::back()
|
||||||
|
|
||||||
std::size_t cell_vector::length() const
|
std::size_t cell_vector::length() const
|
||||||
{
|
{
|
||||||
return order_ == major_order::row
|
return order_ == major_order::row ? ref_.width() + 1 : ref_.height() + 1;
|
||||||
? ref_.width() + 1
|
|
||||||
: ref_.height() + 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cell_vector::const_iterator cell_vector::begin() const
|
cell_vector::const_iterator cell_vector::begin() const
|
||||||
|
|
|
@ -28,7 +28,10 @@
|
||||||
namespace xlnt {
|
namespace xlnt {
|
||||||
|
|
||||||
const_cell_iterator::const_cell_iterator(worksheet ws, const cell_reference &start_cell, major_order order)
|
const_cell_iterator::const_cell_iterator(worksheet ws, const cell_reference &start_cell, major_order order)
|
||||||
: ws_(ws), current_cell_(start_cell), range_(start_cell.to_range()), order_(order)
|
: ws_(ws),
|
||||||
|
current_cell_(start_cell),
|
||||||
|
range_(start_cell.to_range()),
|
||||||
|
order_(order)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,6 +68,7 @@ const_cell_iterator const_cell_iterator::operator--(int)
|
||||||
{
|
{
|
||||||
const_cell_iterator old = *this;
|
const_cell_iterator old = *this;
|
||||||
--*this;
|
--*this;
|
||||||
|
|
||||||
return old;
|
return old;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,6 +90,7 @@ const_cell_iterator const_cell_iterator::operator++(int)
|
||||||
{
|
{
|
||||||
const_cell_iterator old = *this;
|
const_cell_iterator old = *this;
|
||||||
++*this;
|
++*this;
|
||||||
|
|
||||||
return old;
|
return old;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,16 +20,20 @@
|
||||||
//
|
//
|
||||||
// @license: http://www.opensource.org/licenses/mit-license.php
|
// @license: http://www.opensource.org/licenses/mit-license.php
|
||||||
// @author: see AUTHORS file
|
// @author: see AUTHORS file
|
||||||
#include <xlnt/worksheet/range.hpp>
|
|
||||||
#include <xlnt/cell/cell.hpp>
|
#include <xlnt/cell/cell.hpp>
|
||||||
#include <xlnt/worksheet/const_range_iterator.hpp>
|
#include <xlnt/worksheet/const_range_iterator.hpp>
|
||||||
|
#include <xlnt/worksheet/range.hpp>
|
||||||
#include <xlnt/worksheet/range_reference.hpp>
|
#include <xlnt/worksheet/range_reference.hpp>
|
||||||
#include <xlnt/worksheet/worksheet.hpp>
|
#include <xlnt/worksheet/worksheet.hpp>
|
||||||
|
|
||||||
namespace xlnt {
|
namespace xlnt {
|
||||||
|
|
||||||
const_range_iterator::const_range_iterator(const worksheet &ws, const range_reference &start_cell, major_order order)
|
const_range_iterator::const_range_iterator(const worksheet &ws,
|
||||||
: ws_(ws.d_), current_cell_(start_cell.top_left()), range_(start_cell), order_(order)
|
const range_reference &start_cell, major_order order)
|
||||||
|
: ws_(ws.d_),
|
||||||
|
current_cell_(start_cell.top_left()),
|
||||||
|
range_(start_cell),
|
||||||
|
order_(order)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,7 +44,9 @@ const_range_iterator::const_range_iterator(const const_range_iterator &other)
|
||||||
|
|
||||||
bool const_range_iterator::operator==(const const_range_iterator &other) const
|
bool const_range_iterator::operator==(const const_range_iterator &other) const
|
||||||
{
|
{
|
||||||
return ws_ == other.ws_ && current_cell_ == other.current_cell_ && order_ == other.order_;
|
return ws_ == other.ws_
|
||||||
|
&& current_cell_ == other.current_cell_
|
||||||
|
&& order_ == other.order_;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool const_range_iterator::operator!=(const const_range_iterator &other) const
|
bool const_range_iterator::operator!=(const const_range_iterator &other) const
|
||||||
|
@ -66,7 +72,7 @@ const_range_iterator const_range_iterator::operator--(int)
|
||||||
{
|
{
|
||||||
const_range_iterator old = *this;
|
const_range_iterator old = *this;
|
||||||
--*this;
|
--*this;
|
||||||
|
|
||||||
return old;
|
return old;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -88,7 +94,7 @@ const_range_iterator const_range_iterator::operator++(int)
|
||||||
{
|
{
|
||||||
const_range_iterator old = *this;
|
const_range_iterator old = *this;
|
||||||
++*this;
|
++*this;
|
||||||
|
|
||||||
return old;
|
return old;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -97,12 +103,12 @@ const cell_vector const_range_iterator::operator*() const
|
||||||
if (order_ == major_order::row)
|
if (order_ == major_order::row)
|
||||||
{
|
{
|
||||||
range_reference reference(range_.top_left().column_index(), current_cell_.row(),
|
range_reference reference(range_.top_left().column_index(), current_cell_.row(),
|
||||||
range_.bottom_right().column_index(), current_cell_.row());
|
range_.bottom_right().column_index(), current_cell_.row());
|
||||||
return cell_vector(ws_, reference, order_);
|
return cell_vector(ws_, reference, order_);
|
||||||
}
|
}
|
||||||
|
|
||||||
range_reference reference(current_cell_.column_index(), range_.top_left().row(),
|
range_reference reference(current_cell_.column_index(), range_.top_left().row(),
|
||||||
current_cell_.column_index(), range_.bottom_right().row());
|
current_cell_.column_index(), range_.bottom_right().row());
|
||||||
return cell_vector(ws_, reference, order_);
|
return cell_vector(ws_, reference, order_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -88,5 +88,5 @@ void page_margins::footer(double footer)
|
||||||
{
|
{
|
||||||
footer_ = footer;
|
footer_ = footer;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace xlnt
|
} // namespace xlnt
|
||||||
|
|
|
@ -20,9 +20,9 @@
|
||||||
//
|
//
|
||||||
// @license: http://www.opensource.org/licenses/mit-license.php
|
// @license: http://www.opensource.org/licenses/mit-license.php
|
||||||
// @author: see AUTHORS file
|
// @author: see AUTHORS file
|
||||||
#include <xlnt/worksheet/range.hpp>
|
|
||||||
#include <xlnt/cell/cell.hpp>
|
#include <xlnt/cell/cell.hpp>
|
||||||
#include <xlnt/worksheet/const_range_iterator.hpp>
|
#include <xlnt/worksheet/const_range_iterator.hpp>
|
||||||
|
#include <xlnt/worksheet/range.hpp>
|
||||||
#include <xlnt/worksheet/range_iterator.hpp>
|
#include <xlnt/worksheet/range_iterator.hpp>
|
||||||
#include <xlnt/worksheet/range_reference.hpp>
|
#include <xlnt/worksheet/range_reference.hpp>
|
||||||
#include <xlnt/worksheet/worksheet.hpp>
|
#include <xlnt/worksheet/worksheet.hpp>
|
||||||
|
@ -30,7 +30,10 @@
|
||||||
namespace xlnt {
|
namespace xlnt {
|
||||||
|
|
||||||
range::range(worksheet ws, const range_reference &reference, major_order order, bool skip_null)
|
range::range(worksheet ws, const range_reference &reference, major_order order, bool skip_null)
|
||||||
: ws_(ws), ref_(reference), order_(order), skip_null_(skip_null)
|
: ws_(ws),
|
||||||
|
ref_(reference),
|
||||||
|
order_(order),
|
||||||
|
skip_null_(skip_null)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,36 +63,37 @@ std::size_t range::length() const
|
||||||
|
|
||||||
bool range::operator==(const range &comparand) const
|
bool range::operator==(const range &comparand) const
|
||||||
{
|
{
|
||||||
return ref_ == comparand.ref_ && ws_ == comparand.ws_ && order_ == comparand.order_;
|
return ref_ == comparand.ref_
|
||||||
|
&& ws_ == comparand.ws_
|
||||||
|
&& order_ == comparand.order_;
|
||||||
}
|
}
|
||||||
|
|
||||||
cell_vector range::vector(std::size_t vector_index)
|
cell_vector range::vector(std::size_t vector_index)
|
||||||
{
|
{
|
||||||
|
range_reference vector_ref = ref_;
|
||||||
|
|
||||||
if (order_ == major_order::row)
|
if (order_ == major_order::row)
|
||||||
{
|
{
|
||||||
range_reference reference(
|
auto row = ref_.top_left().row() + static_cast<row_t>(vector_index);
|
||||||
ref_.top_left().column_index(),
|
vector_ref.top_left().row(row);
|
||||||
static_cast<row_t>(static_cast<std::size_t>(ref_.top_left().row()) + vector_index),
|
vector_ref.bottom_right().row(row);
|
||||||
ref_.bottom_right().column_index(),
|
}
|
||||||
static_cast<row_t>(static_cast<std::size_t>(ref_.top_left().row()) + vector_index));
|
else
|
||||||
|
{
|
||||||
return cell_vector(ws_, reference, order_);
|
auto column = ref_.top_left().column() + static_cast<column_t::index_t>(vector_index);
|
||||||
|
vector_ref.top_left().column_index(column);
|
||||||
|
vector_ref.bottom_right().column_index(column);
|
||||||
}
|
}
|
||||||
|
|
||||||
range_reference reference(
|
return cell_vector(ws_, vector_ref, order_);
|
||||||
static_cast<column_t::index_t>(static_cast<std::size_t>(ref_.top_left().column().index) + vector_index),
|
|
||||||
ref_.top_left().row(),
|
|
||||||
static_cast<column_t::index_t>(static_cast<std::size_t>(ref_.top_left().column().index) + vector_index),
|
|
||||||
ref_.bottom_right().row());
|
|
||||||
|
|
||||||
return cell_vector(ws_, reference, order_);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool range::contains(const cell_reference &ref)
|
bool range::contains(const cell_reference &ref)
|
||||||
{
|
{
|
||||||
return ref_.top_left().column_index() <= ref.column_index() &&
|
return ref_.top_left().column_index() <= ref.column_index()
|
||||||
ref_.bottom_right().column_index() >= ref.column_index() &&
|
&& ref_.bottom_right().column_index() >= ref.column_index()
|
||||||
ref_.top_left().row() <= ref.row() && ref_.bottom_right().row() >= ref.row();
|
&& ref_.top_left().row() <= ref.row()
|
||||||
|
&& ref_.bottom_right().row() >= ref.row();
|
||||||
}
|
}
|
||||||
|
|
||||||
cell range::cell(const cell_reference &ref)
|
cell range::cell(const cell_reference &ref)
|
||||||
|
|
|
@ -20,8 +20,8 @@
|
||||||
//
|
//
|
||||||
// @license: http://www.opensource.org/licenses/mit-license.php
|
// @license: http://www.opensource.org/licenses/mit-license.php
|
||||||
// @author: see AUTHORS file
|
// @author: see AUTHORS file
|
||||||
#include <xlnt/worksheet/range.hpp>
|
|
||||||
#include <xlnt/cell/cell.hpp>
|
#include <xlnt/cell/cell.hpp>
|
||||||
|
#include <xlnt/worksheet/range.hpp>
|
||||||
#include <xlnt/worksheet/range_iterator.hpp>
|
#include <xlnt/worksheet/range_iterator.hpp>
|
||||||
#include <xlnt/worksheet/range_reference.hpp>
|
#include <xlnt/worksheet/range_reference.hpp>
|
||||||
#include <xlnt/worksheet/worksheet.hpp>
|
#include <xlnt/worksheet/worksheet.hpp>
|
||||||
|
@ -33,17 +33,21 @@ cell_vector range_iterator::operator*() const
|
||||||
if (order_ == major_order::row)
|
if (order_ == major_order::row)
|
||||||
{
|
{
|
||||||
range_reference reference(range_.top_left().column_index(), current_cell_.row(),
|
range_reference reference(range_.top_left().column_index(), current_cell_.row(),
|
||||||
range_.bottom_right().column_index(), current_cell_.row());
|
range_.bottom_right().column_index(), current_cell_.row());
|
||||||
return cell_vector(ws_, reference, order_);
|
return cell_vector(ws_, reference, order_);
|
||||||
}
|
}
|
||||||
|
|
||||||
range_reference reference(current_cell_.column_index(), range_.top_left().row(),
|
range_reference reference(current_cell_.column_index(), range_.top_left().row(),
|
||||||
current_cell_.column_index(), range_.bottom_right().row());
|
current_cell_.column_index(), range_.bottom_right().row());
|
||||||
return cell_vector(ws_, reference, order_);
|
return cell_vector(ws_, reference, order_);
|
||||||
}
|
}
|
||||||
|
|
||||||
range_iterator::range_iterator(worksheet &ws, const range_reference &start_cell, const range_reference &limits, major_order order)
|
range_iterator::range_iterator(worksheet &ws, const range_reference &start_cell,
|
||||||
: ws_(ws), current_cell_(start_cell.top_left()), range_(limits), order_(order)
|
const range_reference &limits, major_order order)
|
||||||
|
: ws_(ws),
|
||||||
|
current_cell_(start_cell.top_left()),
|
||||||
|
range_(limits),
|
||||||
|
order_(order)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,7 +58,9 @@ range_iterator::range_iterator(const range_iterator &other)
|
||||||
|
|
||||||
bool range_iterator::operator==(const range_iterator &other) const
|
bool range_iterator::operator==(const range_iterator &other) const
|
||||||
{
|
{
|
||||||
return ws_ == other.ws_ && current_cell_ == other.current_cell_ && order_ == other.order_;
|
return ws_ == other.ws_
|
||||||
|
&& current_cell_ == other.current_cell_
|
||||||
|
&& order_ == other.order_;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool range_iterator::operator!=(const range_iterator &other) const
|
bool range_iterator::operator!=(const range_iterator &other) const
|
||||||
|
@ -80,7 +86,7 @@ range_iterator range_iterator::operator--(int)
|
||||||
{
|
{
|
||||||
range_iterator old = *this;
|
range_iterator old = *this;
|
||||||
--*this;
|
--*this;
|
||||||
|
|
||||||
return old;
|
return old;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,10 +95,12 @@ range_iterator &range_iterator::operator++()
|
||||||
if (order_ == major_order::row)
|
if (order_ == major_order::row)
|
||||||
{
|
{
|
||||||
bool any_non_null = false;
|
bool any_non_null = false;
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
current_cell_.row(current_cell_.row() + 1);
|
current_cell_.row(current_cell_.row() + 1);
|
||||||
any_non_null = false;
|
any_non_null = false;
|
||||||
|
|
||||||
for (auto column = current_cell_.column(); column <= range_.bottom_right().column(); column++)
|
for (auto column = current_cell_.column(); column <= range_.bottom_right().column(); column++)
|
||||||
{
|
{
|
||||||
if (ws_.has_cell(cell_reference(column, current_cell_.row())))
|
if (ws_.has_cell(cell_reference(column, current_cell_.row())))
|
||||||
|
@ -101,8 +109,7 @@ range_iterator &range_iterator::operator++()
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
} while (!any_non_null && current_cell_.row() <= range_.bottom_right().row());
|
||||||
while (!any_non_null && current_cell_.row() <= range_.bottom_right().row());
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -116,7 +123,7 @@ range_iterator range_iterator::operator++(int)
|
||||||
{
|
{
|
||||||
range_iterator old = *this;
|
range_iterator old = *this;
|
||||||
++*this;
|
++*this;
|
||||||
|
|
||||||
return old;
|
return old;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,23 +26,28 @@
|
||||||
|
|
||||||
namespace xlnt {
|
namespace xlnt {
|
||||||
|
|
||||||
range_reference range_reference::make_absolute(const xlnt::range_reference &relative_reference)
|
range_reference range_reference::make_absolute(const xlnt::range_reference &relative)
|
||||||
{
|
{
|
||||||
range_reference copy = relative_reference;
|
range_reference copy = relative;
|
||||||
|
|
||||||
copy.top_left_.make_absolute(true, true);
|
copy.top_left_.make_absolute(true, true);
|
||||||
copy.bottom_right_.make_absolute(true, true);
|
copy.bottom_right_.make_absolute(true, true);
|
||||||
|
|
||||||
return copy;
|
return copy;
|
||||||
}
|
}
|
||||||
|
|
||||||
range_reference::range_reference() : range_reference("A1")
|
range_reference::range_reference()
|
||||||
|
: range_reference("A1")
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
range_reference::range_reference(const char *range_string) : range_reference(std::string(range_string))
|
range_reference::range_reference(const char *range_string)
|
||||||
|
: range_reference(std::string(range_string))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
range_reference::range_reference(const std::string &range_string) : top_left_("A1"), bottom_right_("A1")
|
range_reference::range_reference(const std::string &range_string)
|
||||||
|
: top_left_("A1"), bottom_right_("A1")
|
||||||
{
|
{
|
||||||
auto colon_index = range_string.find(':');
|
auto colon_index = range_string.find(':');
|
||||||
|
|
||||||
|
@ -63,16 +68,19 @@ range_reference::range_reference(const cell_reference &top_left, const cell_refe
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
range_reference::range_reference(column_t column_index_start, row_t row_index_start, column_t column_index_end,
|
range_reference::range_reference(
|
||||||
row_t row_index_end)
|
column_t column_index_start, row_t row_index_start, column_t column_index_end, row_t row_index_end)
|
||||||
: top_left_(column_index_start, row_index_start), bottom_right_(column_index_end, row_index_end)
|
: top_left_(column_index_start, row_index_start), bottom_right_(column_index_end, row_index_end)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
range_reference range_reference::make_offset(int column_offset, int row_offset) const
|
range_reference range_reference::make_offset(int column_offset, int row_offset) const
|
||||||
{
|
{
|
||||||
return range_reference(top_left_.make_offset(column_offset, row_offset),
|
auto top_left = top_left_.make_offset(column_offset, row_offset);
|
||||||
bottom_right_.make_offset(column_offset, row_offset));
|
auto bottom_right = bottom_right_.make_offset(column_offset, row_offset);
|
||||||
|
|
||||||
|
return top_left, bottom_right; // lol
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::size_t range_reference::height() const
|
std::size_t range_reference::height() const
|
||||||
|
|
|
@ -34,6 +34,7 @@ std::string int_to_hex(T i)
|
||||||
{
|
{
|
||||||
std::stringstream stream;
|
std::stringstream stream;
|
||||||
stream << std::hex << i;
|
stream << std::hex << i;
|
||||||
|
|
||||||
return stream.str();
|
return stream.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,7 +71,8 @@ std::string sheet_protection::hash_password(const std::string &plaintext_passwor
|
||||||
|
|
||||||
std::string hashed = int_to_hex(password);
|
std::string hashed = int_to_hex(password);
|
||||||
std::transform(hashed.begin(), hashed.end(), hashed.begin(),
|
std::transform(hashed.begin(), hashed.end(), hashed.begin(),
|
||||||
[](char c) { return std::toupper(c, std::locale::classic()); });
|
[](char c) { return std::toupper(c, std::locale::classic()); });
|
||||||
|
|
||||||
return hashed;
|
return hashed;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,10 +38,10 @@
|
||||||
#include <xlnt/worksheet/cell_iterator.hpp>
|
#include <xlnt/worksheet/cell_iterator.hpp>
|
||||||
#include <xlnt/worksheet/const_cell_iterator.hpp>
|
#include <xlnt/worksheet/const_cell_iterator.hpp>
|
||||||
#include <xlnt/worksheet/const_range_iterator.hpp>
|
#include <xlnt/worksheet/const_range_iterator.hpp>
|
||||||
|
#include <xlnt/worksheet/header_footer.hpp>
|
||||||
#include <xlnt/worksheet/range.hpp>
|
#include <xlnt/worksheet/range.hpp>
|
||||||
#include <xlnt/worksheet/range_iterator.hpp>
|
#include <xlnt/worksheet/range_iterator.hpp>
|
||||||
#include <xlnt/worksheet/range_reference.hpp>
|
#include <xlnt/worksheet/range_reference.hpp>
|
||||||
#include <xlnt/worksheet/header_footer.hpp>
|
|
||||||
#include <xlnt/worksheet/worksheet.hpp>
|
#include <xlnt/worksheet/worksheet.hpp>
|
||||||
|
|
||||||
#include <detail/cell_impl.hpp>
|
#include <detail/cell_impl.hpp>
|
||||||
|
@ -49,26 +49,37 @@
|
||||||
#include <detail/workbook_impl.hpp>
|
#include <detail/workbook_impl.hpp>
|
||||||
#include <detail/worksheet_impl.hpp>
|
#include <detail/worksheet_impl.hpp>
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
int points_to_pixels(double points, double dpi)
|
||||||
|
{
|
||||||
|
return static_cast<int>(std::ceil(points * dpi / 72));
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
namespace xlnt {
|
namespace xlnt {
|
||||||
|
|
||||||
worksheet::worksheet() : d_(nullptr)
|
worksheet::worksheet()
|
||||||
|
: d_(nullptr)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
worksheet::worksheet(detail::worksheet_impl *d) : d_(d)
|
worksheet::worksheet(detail::worksheet_impl *d)
|
||||||
|
: d_(d)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
worksheet::worksheet(const worksheet &rhs) : d_(rhs.d_)
|
worksheet::worksheet(const worksheet &rhs)
|
||||||
|
: d_(rhs.d_)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
bool worksheet::has_frozen_panes() const
|
bool worksheet::has_frozen_panes() const
|
||||||
{
|
{
|
||||||
return !d_->views_.empty()
|
return !d_->views_.empty() && d_->views_.front().has_pane()
|
||||||
&& d_->views_.front().has_pane()
|
|
||||||
&& (d_->views_.front().pane().state == pane_state::frozen
|
&& (d_->views_.front().pane().state == pane_state::frozen
|
||||||
|| d_->views_.front().pane().state == pane_state::frozen_split);
|
|| d_->views_.front().pane().state == pane_state::frozen_split);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string worksheet::unique_sheet_name(const std::string &value) const
|
std::string worksheet::unique_sheet_name(const std::string &value) const
|
||||||
|
@ -94,24 +105,24 @@ void worksheet::create_named_range(const std::string &name, const std::string &r
|
||||||
|
|
||||||
void worksheet::create_named_range(const std::string &name, const range_reference &reference)
|
void worksheet::create_named_range(const std::string &name, const range_reference &reference)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
auto temp = cell_reference::split_reference(name);
|
auto temp = cell_reference::split_reference(name);
|
||||||
|
|
||||||
// name is a valid reference, make sure it's outside the allowed range
|
// name is a valid reference, make sure it's outside the allowed range
|
||||||
|
|
||||||
if (column_t(temp.first).index <= column_t("XFD").index && temp.second <= 1048576)
|
if (column_t(temp.first).index <= column_t("XFD").index && temp.second <= 1048576)
|
||||||
{
|
{
|
||||||
throw invalid_parameter(); //("named range name must be outside the range A1-XFD1048576");
|
throw invalid_parameter(); //("named range name must be outside the range A1-XFD1048576");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (xlnt::invalid_cell_reference)
|
catch (xlnt::invalid_cell_reference)
|
||||||
{
|
{
|
||||||
// name is not a valid reference, that's good
|
// name is not a valid reference, that's good
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<named_range::target> targets;
|
std::vector<named_range::target> targets;
|
||||||
targets.push_back({ *this, reference });
|
targets.push_back({*this, reference});
|
||||||
|
|
||||||
d_->named_ranges_[name] = xlnt::named_range(name, targets);
|
d_->named_ranges_[name] = xlnt::named_range(name, targets);
|
||||||
}
|
}
|
||||||
|
@ -133,12 +144,12 @@ std::vector<range_reference> worksheet::merged_ranges() const
|
||||||
|
|
||||||
bool worksheet::has_page_margins() const
|
bool worksheet::has_page_margins() const
|
||||||
{
|
{
|
||||||
return d_->page_margins_.is_set();
|
return d_->page_margins_.is_set();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool worksheet::has_page_setup() const
|
bool worksheet::has_page_setup() const
|
||||||
{
|
{
|
||||||
return d_->page_setup_.is_set();
|
return d_->page_setup_.is_set();
|
||||||
}
|
}
|
||||||
|
|
||||||
page_margins worksheet::page_margins() const
|
page_margins worksheet::page_margins() const
|
||||||
|
@ -148,7 +159,7 @@ page_margins worksheet::page_margins() const
|
||||||
|
|
||||||
void worksheet::page_margins(const class page_margins &margins)
|
void worksheet::page_margins(const class page_margins &margins)
|
||||||
{
|
{
|
||||||
d_->page_margins_ = margins;
|
d_->page_margins_ = margins;
|
||||||
}
|
}
|
||||||
|
|
||||||
void worksheet::auto_filter(const std::string &reference_string)
|
void worksheet::auto_filter(const std::string &reference_string)
|
||||||
|
@ -183,15 +194,15 @@ void worksheet::clear_auto_filter()
|
||||||
|
|
||||||
void worksheet::page_setup(const struct page_setup &setup)
|
void worksheet::page_setup(const struct page_setup &setup)
|
||||||
{
|
{
|
||||||
d_->page_setup_ = setup;
|
d_->page_setup_ = setup;
|
||||||
}
|
}
|
||||||
|
|
||||||
page_setup worksheet::page_setup() const
|
page_setup worksheet::page_setup() const
|
||||||
{
|
{
|
||||||
if (!has_page_setup())
|
if (!has_page_setup())
|
||||||
{
|
{
|
||||||
throw invalid_attribute();
|
throw invalid_attribute();
|
||||||
}
|
}
|
||||||
|
|
||||||
return d_->page_setup_.get();
|
return d_->page_setup_.get();
|
||||||
}
|
}
|
||||||
|
@ -203,7 +214,7 @@ workbook &worksheet::workbook()
|
||||||
|
|
||||||
const workbook &worksheet::workbook() const
|
const workbook &worksheet::workbook() const
|
||||||
{
|
{
|
||||||
return *d_->parent_;
|
return *d_->parent_;
|
||||||
}
|
}
|
||||||
|
|
||||||
void worksheet::garbage_collect()
|
void worksheet::garbage_collect()
|
||||||
|
@ -254,28 +265,27 @@ std::string worksheet::title() const
|
||||||
|
|
||||||
void worksheet::title(const std::string &title)
|
void worksheet::title(const std::string &title)
|
||||||
{
|
{
|
||||||
if (title.length() > 31)
|
if (title.length() > 31)
|
||||||
{
|
{
|
||||||
throw invalid_sheet_title(title);
|
throw invalid_sheet_title(title);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (title.find_first_of("*:/\\?[]") != std::string::npos)
|
if (title.find_first_of("*:/\\?[]") != std::string::npos)
|
||||||
{
|
{
|
||||||
throw invalid_sheet_title(title);
|
throw invalid_sheet_title(title);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto same_title = std::find_if(workbook().begin(), workbook().end(),
|
auto same_title =
|
||||||
[&](worksheet ws) { return ws.title() == title; });
|
std::find_if(workbook().begin(), workbook().end(), [&](worksheet ws) { return ws.title() == title; });
|
||||||
|
|
||||||
if (same_title != workbook().end() && *same_title != *this)
|
if (same_title != workbook().end() && *same_title != *this)
|
||||||
{
|
{
|
||||||
throw invalid_sheet_title(title);
|
throw invalid_sheet_title(title);
|
||||||
}
|
}
|
||||||
|
|
||||||
workbook().d_->sheet_title_rel_id_map_[title] =
|
workbook().d_->sheet_title_rel_id_map_[title] = workbook().d_->sheet_title_rel_id_map_[d_->title_];
|
||||||
workbook().d_->sheet_title_rel_id_map_[d_->title_];
|
workbook().d_->sheet_title_rel_id_map_.erase(d_->title_);
|
||||||
workbook().d_->sheet_title_rel_id_map_.erase(d_->title_);
|
d_->title_ = title;
|
||||||
d_->title_ = title;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cell_reference worksheet::frozen_panes() const
|
cell_reference worksheet::frozen_panes() const
|
||||||
|
@ -312,7 +322,7 @@ void worksheet::freeze_panes(const cell_reference &ref)
|
||||||
|
|
||||||
primary_view.clear_selections();
|
primary_view.clear_selections();
|
||||||
primary_view.add_selection(selection());
|
primary_view.add_selection(selection());
|
||||||
|
|
||||||
if (ref == "A1")
|
if (ref == "A1")
|
||||||
{
|
{
|
||||||
unfreeze_panes();
|
unfreeze_panes();
|
||||||
|
@ -383,9 +393,9 @@ cell worksheet::cell(const cell_reference &reference)
|
||||||
if (row.find(reference.column_index()) == row.end())
|
if (row.find(reference.column_index()) == row.end())
|
||||||
{
|
{
|
||||||
auto &impl = row[reference.column_index()] = detail::cell_impl();
|
auto &impl = row[reference.column_index()] = detail::cell_impl();
|
||||||
impl.parent_ = d_;
|
impl.parent_ = d_;
|
||||||
impl.column_ = reference.column_index();
|
impl.column_ = reference.column_index();
|
||||||
impl.row_ = reference.row();
|
impl.row_ = reference.row();
|
||||||
}
|
}
|
||||||
|
|
||||||
return xlnt::cell(&row[reference.column_index()]);
|
return xlnt::cell(&row[reference.column_index()]);
|
||||||
|
@ -399,13 +409,11 @@ const cell worksheet::cell(const cell_reference &reference) const
|
||||||
bool worksheet::has_cell(const cell_reference &reference) const
|
bool worksheet::has_cell(const cell_reference &reference) const
|
||||||
{
|
{
|
||||||
const auto row = d_->cell_map_.find(reference.row());
|
const auto row = d_->cell_map_.find(reference.row());
|
||||||
if(row == d_->cell_map_.cend())
|
if (row == d_->cell_map_.cend()) return false;
|
||||||
return false;
|
|
||||||
|
|
||||||
const auto col = row->second.find(reference.column_index());
|
const auto col = row->second.find(reference.column_index());
|
||||||
if(col == row->second.cend())
|
if (col == row->second.cend()) return false;
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -420,7 +428,7 @@ range worksheet::named_range(const std::string &name)
|
||||||
{
|
{
|
||||||
throw key_not_found();
|
throw key_not_found();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!has_named_range(name))
|
if (!has_named_range(name))
|
||||||
{
|
{
|
||||||
throw key_not_found();
|
throw key_not_found();
|
||||||
|
@ -567,7 +575,7 @@ void worksheet::unmerge_cells(const range_reference &reference)
|
||||||
|
|
||||||
if (match == d_->merged_cells_.end())
|
if (match == d_->merged_cells_.end())
|
||||||
{
|
{
|
||||||
throw invalid_parameter();
|
throw invalid_parameter();
|
||||||
}
|
}
|
||||||
|
|
||||||
d_->merged_cells_.erase(match);
|
d_->merged_cells_.erase(match);
|
||||||
|
@ -690,29 +698,29 @@ bool worksheet::operator==(const worksheet &other) const
|
||||||
|
|
||||||
bool worksheet::compare(const worksheet &other, bool reference) const
|
bool worksheet::compare(const worksheet &other, bool reference) const
|
||||||
{
|
{
|
||||||
if(reference)
|
if (reference)
|
||||||
{
|
{
|
||||||
return d_ == other.d_;
|
return d_ == other.d_;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(d_->parent_ != other.d_->parent_) return false;
|
if (d_->parent_ != other.d_->parent_) return false;
|
||||||
|
|
||||||
for(auto &row : d_->cell_map_)
|
for (auto &row : d_->cell_map_)
|
||||||
{
|
{
|
||||||
if(other.d_->cell_map_.find(row.first) == other.d_->cell_map_.end())
|
if (other.d_->cell_map_.find(row.first) == other.d_->cell_map_.end())
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
for(auto &cell : row.second)
|
for (auto &cell : row.second)
|
||||||
{
|
{
|
||||||
if(other.d_->cell_map_[row.first].find(cell.first) == other.d_->cell_map_[row.first].end())
|
if (other.d_->cell_map_[row.first].find(cell.first) == other.d_->cell_map_[row.first].end())
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
xlnt::cell this_cell(&cell.second);
|
xlnt::cell this_cell(&cell.second);
|
||||||
xlnt::cell other_cell(&other.d_->cell_map_[row.first][cell.first]);
|
xlnt::cell other_cell(&other.d_->cell_map_[row.first][cell.first]);
|
||||||
|
|
||||||
if (this_cell.data_type() != other_cell.data_type())
|
if (this_cell.data_type() != other_cell.data_type())
|
||||||
{
|
{
|
||||||
|
@ -726,16 +734,15 @@ bool worksheet::compare(const worksheet &other, bool reference) const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo: missing some comparisons
|
// todo: missing some comparisons
|
||||||
|
|
||||||
if(d_->auto_filter_ == other.d_->auto_filter_
|
if (d_->auto_filter_ == other.d_->auto_filter_ && d_->views_ == other.d_->views_
|
||||||
&& d_->views_ == other.d_->views_
|
|
||||||
&& d_->merged_cells_ == other.d_->merged_cells_)
|
&& d_->merged_cells_ == other.d_->merged_cells_)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -787,7 +794,7 @@ void worksheet::remove_named_range(const std::string &name)
|
||||||
{
|
{
|
||||||
if (!has_named_range(name))
|
if (!has_named_range(name))
|
||||||
{
|
{
|
||||||
throw key_not_found();
|
throw key_not_found();
|
||||||
}
|
}
|
||||||
|
|
||||||
d_->named_ranges_.erase(name);
|
d_->named_ranges_.erase(name);
|
||||||
|
@ -815,17 +822,6 @@ std::vector<std::string> worksheet::formula_attributes() const
|
||||||
|
|
||||||
cell_reference worksheet::point_pos(int left, int top) const
|
cell_reference worksheet::point_pos(int left, int top) const
|
||||||
{
|
{
|
||||||
static const auto DefaultColumnWidth = 51.85;
|
|
||||||
static const auto DefaultRowHeight = 15.0;
|
|
||||||
|
|
||||||
auto points_to_pixels = [](double value, double dpi)
|
|
||||||
{
|
|
||||||
return static_cast<int>(std::ceil(value * dpi / 72));
|
|
||||||
};
|
|
||||||
|
|
||||||
auto default_height = points_to_pixels(DefaultRowHeight, 96.0);
|
|
||||||
auto default_width = points_to_pixels(DefaultColumnWidth, 96.0);
|
|
||||||
|
|
||||||
column_t current_column = 1;
|
column_t current_column = 1;
|
||||||
row_t current_row = 1;
|
row_t current_row = 1;
|
||||||
|
|
||||||
|
@ -834,41 +830,15 @@ cell_reference worksheet::point_pos(int left, int top) const
|
||||||
|
|
||||||
while (left_pos <= left)
|
while (left_pos <= left)
|
||||||
{
|
{
|
||||||
current_column++;
|
left_pos += column_width(current_column++);
|
||||||
|
|
||||||
if (has_column_properties(current_column) && column_properties(current_column).width.is_set())
|
|
||||||
{
|
|
||||||
auto cdw = column_properties(current_column).width.get();
|
|
||||||
|
|
||||||
if (cdw >= 0)
|
|
||||||
{
|
|
||||||
left_pos += points_to_pixels(cdw, 96.0);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
left_pos += default_width;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
while (top_pos <= top)
|
while (top_pos <= top)
|
||||||
{
|
{
|
||||||
current_row++;
|
top_pos += row_height(current_row++);
|
||||||
|
|
||||||
if (has_row_properties(current_row) && row_properties(current_row).height.is_set())
|
|
||||||
{
|
|
||||||
auto cdh = row_properties(current_row).height.get();
|
|
||||||
|
|
||||||
if (cdh >= 0)
|
|
||||||
{
|
|
||||||
top_pos += points_to_pixels(cdh, 96.0);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
top_pos += default_height;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return { current_column - 1, current_row - 1 };
|
return {current_column - 1, current_row - 1};
|
||||||
}
|
}
|
||||||
|
|
||||||
cell_reference worksheet::point_pos(const std::pair<int, int> &point) const
|
cell_reference worksheet::point_pos(const std::pair<int, int> &point) const
|
||||||
|
@ -921,7 +891,7 @@ worksheet::iterator worksheet::begin()
|
||||||
auto dimensions = calculate_dimension();
|
auto dimensions = calculate_dimension();
|
||||||
cell_reference top_right(dimensions.bottom_right().column_index(), dimensions.top_left().row());
|
cell_reference top_right(dimensions.bottom_right().column_index(), dimensions.top_left().row());
|
||||||
range_reference row_range(dimensions.top_left(), top_right);
|
range_reference row_range(dimensions.top_left(), top_right);
|
||||||
|
|
||||||
return iterator(*this, row_range, dimensions, major_order::row);
|
return iterator(*this, row_range, dimensions, major_order::row);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -931,7 +901,7 @@ worksheet::iterator worksheet::end()
|
||||||
auto past_end_row_index = dimensions.bottom_right().row() + 1;
|
auto past_end_row_index = dimensions.bottom_right().row() + 1;
|
||||||
cell_reference bottom_left(dimensions.top_left().column_index(), past_end_row_index);
|
cell_reference bottom_left(dimensions.top_left().column_index(), past_end_row_index);
|
||||||
cell_reference bottom_right(dimensions.bottom_right().column_index(), past_end_row_index);
|
cell_reference bottom_right(dimensions.bottom_right().column_index(), past_end_row_index);
|
||||||
|
|
||||||
return iterator(*this, range_reference(bottom_left, bottom_right), dimensions, major_order::row);
|
return iterator(*this, range_reference(bottom_left, bottom_right), dimensions, major_order::row);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -940,7 +910,7 @@ worksheet::const_iterator worksheet::cbegin() const
|
||||||
auto dimensions = calculate_dimension();
|
auto dimensions = calculate_dimension();
|
||||||
cell_reference top_right(dimensions.bottom_right().column_index(), dimensions.top_left().row());
|
cell_reference top_right(dimensions.bottom_right().column_index(), dimensions.top_left().row());
|
||||||
range_reference row_range(dimensions.top_left(), top_right);
|
range_reference row_range(dimensions.top_left(), top_right);
|
||||||
|
|
||||||
return const_iterator(*this, row_range, major_order::row);
|
return const_iterator(*this, row_range, major_order::row);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -950,7 +920,7 @@ worksheet::const_iterator worksheet::cend() const
|
||||||
auto past_end_row_index = dimensions.bottom_right().row() + 1;
|
auto past_end_row_index = dimensions.bottom_right().row() + 1;
|
||||||
cell_reference bottom_left(dimensions.top_left().column_index(), past_end_row_index);
|
cell_reference bottom_left(dimensions.top_left().column_index(), past_end_row_index);
|
||||||
cell_reference bottom_right(dimensions.bottom_right().column_index(), past_end_row_index);
|
cell_reference bottom_right(dimensions.bottom_right().column_index(), past_end_row_index);
|
||||||
|
|
||||||
return const_iterator(*this, range_reference(bottom_left, bottom_right), major_order::row);
|
return const_iterator(*this, range_reference(bottom_left, bottom_right), major_order::row);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1017,7 +987,7 @@ range_reference worksheet::print_area() const
|
||||||
|
|
||||||
bool worksheet::has_view() const
|
bool worksheet::has_view() const
|
||||||
{
|
{
|
||||||
return !d_->views_.empty();
|
return !d_->views_.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
sheet_view worksheet::view(std::size_t index) const
|
sheet_view worksheet::view(std::size_t index) const
|
||||||
|
@ -1032,7 +1002,7 @@ void worksheet::add_view(const sheet_view &new_view)
|
||||||
|
|
||||||
void worksheet::register_comments_in_manifest()
|
void worksheet::register_comments_in_manifest()
|
||||||
{
|
{
|
||||||
workbook().register_comments_in_manifest(*this);
|
workbook().register_comments_in_manifest(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool worksheet::has_header_footer() const
|
bool worksheet::has_header_footer() const
|
||||||
|
@ -1045,24 +1015,52 @@ void worksheet::header_footer(const class header_footer &hf)
|
||||||
d_->header_footer_ = hf;
|
d_->header_footer_ = hf;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<row_t> &worksheet::row_breaks()
|
void worksheet::page_break_at_row(row_t row)
|
||||||
|
{
|
||||||
|
d_->row_breaks_.push_back(row);
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<row_t> &worksheet::page_break_rows() const
|
||||||
{
|
{
|
||||||
return d_->row_breaks_;
|
return d_->row_breaks_;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::vector<row_t> &worksheet::row_breaks() const
|
void worksheet::page_break_at_column(xlnt::column_t column)
|
||||||
{
|
{
|
||||||
return d_->row_breaks_;
|
d_->column_breaks_.push_back(column);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<column_t> &worksheet::column_breaks()
|
const std::vector<column_t> &worksheet::page_break_columns() const
|
||||||
{
|
{
|
||||||
return d_->column_breaks_;
|
return d_->column_breaks_;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::vector<column_t> &worksheet::column_breaks() const
|
double worksheet::column_width(column_t column) const
|
||||||
{
|
{
|
||||||
return d_->column_breaks_;
|
static const auto DefaultColumnWidth = 51.85;
|
||||||
|
|
||||||
|
if (has_column_properties(column))
|
||||||
|
{
|
||||||
|
return column_properties(column).width.get();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return points_to_pixels(DefaultColumnWidth, 96.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
double worksheet::row_height(row_t row) const
|
||||||
|
{
|
||||||
|
static const auto DefaultRowHeight = 15.0;
|
||||||
|
|
||||||
|
if (has_row_properties(row))
|
||||||
|
{
|
||||||
|
return row_properties(row).height.get();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return points_to_pixels(DefaultRowHeight, 96.0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace xlnt
|
} // namespace xlnt
|
||||||
|
|
Binary file not shown.
Binary file not shown.
|
@ -62,7 +62,7 @@ public:
|
||||||
|
|
||||||
auto is_whitespace = [](const std::string &v)
|
auto is_whitespace = [](const std::string &v)
|
||||||
{
|
{
|
||||||
return v.find_first_not_of("\n ") == std::string::npos;
|
return v.find_first_not_of("\n\t ") == std::string::npos;
|
||||||
};
|
};
|
||||||
|
|
||||||
for (auto left_event : left_parser)
|
for (auto left_event : left_parser)
|
||||||
|
@ -155,11 +155,17 @@ public:
|
||||||
std::cout << "documents don't match" << std::endl;
|
std::cout << "documents don't match" << std::endl;
|
||||||
|
|
||||||
std::cout << "left:" << std::endl;
|
std::cout << "left:" << std::endl;
|
||||||
std::cout << left;
|
for (auto c : left)
|
||||||
|
{
|
||||||
|
std::cout << c << std::flush;
|
||||||
|
}
|
||||||
std::cout << std::endl;
|
std::cout << std::endl;
|
||||||
|
|
||||||
std::cout << "right:" << std::endl;
|
std::cout << "right:" << std::endl;
|
||||||
std::cout << right;
|
for (auto c : right)
|
||||||
|
{
|
||||||
|
std::cout << c << std::flush;
|
||||||
|
}
|
||||||
std::cout << std::endl;
|
std::cout << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -172,7 +178,7 @@ public:
|
||||||
std::vector<std::uint8_t> bytes;
|
std::vector<std::uint8_t> bytes;
|
||||||
wb.save(bytes);
|
wb.save(bytes);
|
||||||
std::istringstream file_stream(std::string(bytes.begin(), bytes.end()));
|
std::istringstream file_stream(std::string(bytes.begin(), bytes.end()));
|
||||||
xlnt::detail::ZipFileReader archive(file_stream);
|
xlnt::detail::zip_file_reader archive(file_stream);
|
||||||
|
|
||||||
return string_matches_archive_member(expected, archive, part, content_type);
|
return string_matches_archive_member(expected, archive, part, content_type);
|
||||||
}
|
}
|
||||||
|
@ -183,31 +189,33 @@ public:
|
||||||
std::vector<std::uint8_t> bytes;
|
std::vector<std::uint8_t> bytes;
|
||||||
wb.save(bytes);
|
wb.save(bytes);
|
||||||
std::istringstream file_stream(std::string(bytes.begin(), bytes.end()));
|
std::istringstream file_stream(std::string(bytes.begin(), bytes.end()));
|
||||||
xlnt::detail::ZipFileReader archive(file_stream);
|
xlnt::detail::zip_file_reader archive(file_stream);
|
||||||
|
|
||||||
return file_matches_archive_member(expected, archive, part, content_type);
|
return file_matches_archive_member(expected, archive, part, content_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool string_matches_archive_member(const std::string &expected,
|
static bool string_matches_archive_member(const std::string &expected,
|
||||||
xlnt::detail::ZipFileReader &archive,
|
xlnt::detail::zip_file_reader &archive,
|
||||||
const xlnt::path &member,
|
const xlnt::path &member,
|
||||||
const std::string &content_type)
|
const std::string &content_type)
|
||||||
{
|
{
|
||||||
auto &stream = archive.open(member.string());
|
auto streambuf = archive.open(member);
|
||||||
|
std::istream stream(streambuf.get());
|
||||||
std::string contents((std::istreambuf_iterator<char>(stream)), (std::istreambuf_iterator<char>()));
|
std::string contents((std::istreambuf_iterator<char>(stream)), (std::istreambuf_iterator<char>()));
|
||||||
return compare_files(expected, contents, content_type);
|
return compare_files(expected, contents, content_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool file_matches_archive_member(const xlnt::path &file,
|
static bool file_matches_archive_member(const xlnt::path &file,
|
||||||
xlnt::detail::ZipFileReader &archive,
|
xlnt::detail::zip_file_reader &archive,
|
||||||
const xlnt::path &member,
|
const xlnt::path &member,
|
||||||
const std::string &content_type)
|
const std::string &content_type)
|
||||||
{
|
{
|
||||||
if (!archive.has_file(member.string())) return false;
|
if (!archive.has_file(member)) return false;
|
||||||
std::vector<std::uint8_t> member_data;
|
std::vector<std::uint8_t> member_data;
|
||||||
xlnt::detail::vector_ostreambuf member_data_buffer(member_data);
|
xlnt::detail::vector_ostreambuf member_data_buffer(member_data);
|
||||||
std::ostream member_data_stream(&member_data_buffer);
|
std::ostream member_data_stream(&member_data_buffer);
|
||||||
auto &member_stream = archive.open(member.string());
|
auto member_streambuf = archive.open(member);
|
||||||
|
std::ostream member_stream(member_streambuf.get());
|
||||||
member_data_stream << member_stream.rdbuf();
|
member_data_stream << member_stream.rdbuf();
|
||||||
std::string contents(member_data.begin(), member_data.end());
|
std::string contents(member_data.begin(), member_data.end());
|
||||||
return compare_files(file.read_contents(), contents, content_type);
|
return compare_files(file.read_contents(), contents, content_type);
|
||||||
|
@ -217,13 +225,13 @@ public:
|
||||||
{
|
{
|
||||||
xlnt::detail::vector_istreambuf left_buffer(left);
|
xlnt::detail::vector_istreambuf left_buffer(left);
|
||||||
std::istream left_stream(&left_buffer);
|
std::istream left_stream(&left_buffer);
|
||||||
xlnt::detail::ZipFileReader left_archive(left_stream);
|
xlnt::detail::zip_file_reader left_archive(left_stream);
|
||||||
|
|
||||||
const auto left_info = left_archive.files();
|
const auto left_info = left_archive.files();
|
||||||
|
|
||||||
xlnt::detail::vector_istreambuf right_buffer(right);
|
xlnt::detail::vector_istreambuf right_buffer(right);
|
||||||
std::istream right_stream(&right_buffer);
|
std::istream right_stream(&right_buffer);
|
||||||
xlnt::detail::ZipFileReader right_archive(right_stream);
|
xlnt::detail::zip_file_reader right_archive(right_stream);
|
||||||
|
|
||||||
const auto right_info = right_archive.files();
|
const auto right_info = right_archive.files();
|
||||||
|
|
||||||
|
@ -234,14 +242,14 @@ public:
|
||||||
std::cout << "left has: ";
|
std::cout << "left has: ";
|
||||||
for (auto &info : left_info)
|
for (auto &info : left_info)
|
||||||
{
|
{
|
||||||
std::cout << info << ", ";
|
std::cout << info.string() << ", ";
|
||||||
}
|
}
|
||||||
std::cout << std::endl;
|
std::cout << std::endl;
|
||||||
|
|
||||||
std::cout << "right has: ";
|
std::cout << "right has: ";
|
||||||
for (auto &info : right_info)
|
for (auto &info : right_info)
|
||||||
{
|
{
|
||||||
std::cout << info << ", ";
|
std::cout << info.string() << ", ";
|
||||||
}
|
}
|
||||||
std::cout << std::endl;
|
std::cout << std::endl;
|
||||||
}
|
}
|
||||||
|
@ -262,18 +270,20 @@ public:
|
||||||
if (!right_archive.has_file(left_member))
|
if (!right_archive.has_file(left_member))
|
||||||
{
|
{
|
||||||
match = false;
|
match = false;
|
||||||
std::cout << "right is missing file: " << left_member << std::endl;
|
std::cout << "right is missing file: " << left_member.string() << std::endl;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto &left_member_stream = left_archive.open(left_member);
|
auto left_member_streambuf = left_archive.open(left_member);
|
||||||
|
std::istream left_member_stream(left_member_streambuf.get());
|
||||||
std::vector<std::uint8_t> left_contents_raw;
|
std::vector<std::uint8_t> left_contents_raw;
|
||||||
xlnt::detail::vector_ostreambuf left_contents_buffer(left_contents_raw);
|
xlnt::detail::vector_ostreambuf left_contents_buffer(left_contents_raw);
|
||||||
std::ostream left_contents_stream(&left_contents_buffer);
|
std::ostream left_contents_stream(&left_contents_buffer);
|
||||||
left_contents_stream << left_member_stream.rdbuf();
|
left_contents_stream << left_member_stream.rdbuf();
|
||||||
std::string left_member_contents(left_contents_raw.begin(), left_contents_raw.end());
|
std::string left_member_contents(left_contents_raw.begin(), left_contents_raw.end());
|
||||||
|
|
||||||
auto &right_member_stream = left_archive.open(left_member);
|
auto right_member_streambuf = right_archive.open(left_member);
|
||||||
|
std::istream right_member_stream(right_member_streambuf.get());
|
||||||
std::vector<std::uint8_t> right_contents_raw;
|
std::vector<std::uint8_t> right_contents_raw;
|
||||||
xlnt::detail::vector_ostreambuf right_contents_buffer(right_contents_raw);
|
xlnt::detail::vector_ostreambuf right_contents_buffer(right_contents_raw);
|
||||||
std::ostream right_contents_stream(&right_contents_buffer);
|
std::ostream right_contents_stream(&right_contents_buffer);
|
||||||
|
@ -282,10 +292,10 @@ public:
|
||||||
|
|
||||||
std::string left_content_type, right_content_type;
|
std::string left_content_type, right_content_type;
|
||||||
|
|
||||||
if (left_member != "[Content_Types].xml")
|
if (left_member.string() != "[Content_Types].xml")
|
||||||
{
|
{
|
||||||
left_content_type = left_manifest.content_type(xlnt::path(left_member));
|
left_content_type = left_manifest.content_type(left_member);
|
||||||
right_content_type = right_manifest.content_type(xlnt::path(left_member));
|
right_content_type = right_manifest.content_type(left_member);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -295,7 +305,7 @@ public:
|
||||||
if (left_content_type != right_content_type)
|
if (left_content_type != right_content_type)
|
||||||
{
|
{
|
||||||
std::cout << "content types differ: "
|
std::cout << "content types differ: "
|
||||||
<< left_member
|
<< left_member.string()
|
||||||
<< " "
|
<< " "
|
||||||
<< left_content_type
|
<< left_content_type
|
||||||
<< " "
|
<< " "
|
||||||
|
@ -305,7 +315,7 @@ public:
|
||||||
}
|
}
|
||||||
else if (!compare_files(left_member_contents, right_member_contents, left_content_type))
|
else if (!compare_files(left_member_contents, right_member_contents, left_content_type))
|
||||||
{
|
{
|
||||||
std::cout << left_member << std::endl;
|
std::cout << left_member.string() << std::endl;
|
||||||
match = false;
|
match = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user