mirror of
https://github.com/tfussell/xlnt.git
synced 2024-03-22 13:11:17 +08:00
clean up zip.cpp, enable and fix compiler warnings, use equality instead of hashing for style components, compile all cpp files in sample directory, track remote branches for submodules
This commit is contained in:
parent
dce2367524
commit
0d97105122
|
@ -12,8 +12,8 @@ environment:
|
||||||
init: []
|
init: []
|
||||||
install: []
|
install: []
|
||||||
before_build:
|
before_build:
|
||||||
- git submodule update --init --recursive
|
- git submodule update --init --recursive --remote
|
||||||
- cmake -H. -Bbuild -G"Visual Studio 14 2015 Win64" -DSTATIC=%STATIC%
|
- cmake -H. -Bbuild -G"Visual Studio 14 2015 Win64" -DSTATIC=%STATIC% -DSAMPLES=ON
|
||||||
|
|
||||||
build:
|
build:
|
||||||
project: build/xlnt_all.sln
|
project: build/xlnt_all.sln
|
||||||
|
|
2
.gitmodules
vendored
2
.gitmodules
vendored
|
@ -22,6 +22,8 @@
|
||||||
path = third-party/botan
|
path = third-party/botan
|
||||||
url = https://github.com/randombit/botan
|
url = https://github.com/randombit/botan
|
||||||
branch = master
|
branch = master
|
||||||
|
|
||||||
[submodule "third-party/zlib"]
|
[submodule "third-party/zlib"]
|
||||||
path = third-party/zlib
|
path = third-party/zlib
|
||||||
url = https://github.com/madler/zlib.git
|
url = https://github.com/madler/zlib.git
|
||||||
|
branch = develop
|
||||||
|
|
22
.travis.yml
22
.travis.yml
|
@ -23,6 +23,7 @@ matrix:
|
||||||
- pip install --user git+git://github.com/eddyxu/cpp-coveralls.git
|
- pip install --user git+git://github.com/eddyxu/cpp-coveralls.git
|
||||||
env:
|
env:
|
||||||
- COMPILER=g++-4.9
|
- COMPILER=g++-4.9
|
||||||
|
- COVERAGE=ON
|
||||||
|
|
||||||
- os: linux
|
- os: linux
|
||||||
compiler: gcc
|
compiler: gcc
|
||||||
|
@ -35,25 +36,12 @@ matrix:
|
||||||
- valgrind
|
- valgrind
|
||||||
env:
|
env:
|
||||||
- COMPILER=g++-5
|
- COMPILER=g++-5
|
||||||
|
- COVERAGE=OFF
|
||||||
|
|
||||||
script:
|
script:
|
||||||
- cmake --version
|
|
||||||
- mkdir build
|
- mkdir build
|
||||||
- cd build
|
- cd build
|
||||||
- cmake -D SHARED=1 -D STATIC=0 -D WITH_TESTS=1 -D WITH_SAMPLES=1 -D CMAKE_CXX_COMPILER=$COMPILER ..
|
- cmake -D STATIC=ON -D SAMPLES=ON -D COVERAGE=$COVERAGE -D CMAKE_CXX_COMPILER=$COMPILER -D CMAKE_BUILD_TYPE=Debug ..
|
||||||
- cmake --build . --target xlnt.test
|
- cmake --build .
|
||||||
- cd bin && ./xlnt.test
|
- cd bin && ./xlnt.test
|
||||||
|
- find .
|
||||||
after_success:
|
|
||||||
- if [ "$COMPILER" = "g++-4.9" ]; then sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.9 90 ; fi
|
|
||||||
- if [ "$COMPILER" = "g++-4.9" ]; then sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-4.9 90 ; fi
|
|
||||||
- if [ "$COMPILER" = "g++-4.9" ]; then sudo update-alternatives --install /usr/bin/gcov gcov /usr/bin/gcov-4.9 90 ; fi
|
|
||||||
- if [ "$COMPILER" = "g++-4.9" ]; then cd .. ; fi
|
|
||||||
- if [ "$COMPILER" = "g++-4.9" ]; then rm -rf ./* ; fi
|
|
||||||
- if [ "$COMPILER" = "g++-4.9" ]; then cmake -G "Unix Makefiles" -D DEBUG=1 -D COVERAGE=1 -D SHARED=0 -DCMAKE_BUILD_TYPE=Debug -D STATIC=1 .. ; fi
|
|
||||||
- if [ "$COMPILER" = "g++-4.9" ]; then make ; fi
|
|
||||||
- if [ "$COMPILER" = "g++-4.9" ]; then cd bin && ./xlnt.test ; fi
|
|
||||||
- if [ "$COMPILER" = "g++-4.9" ]; then cd ../ ; fi
|
|
||||||
- if [ "$COMPILER" = "g++-4.9" ]; then export OLDWD=$(pwd) ; fi
|
|
||||||
- if [ "$COMPILER" = "g++-4.9" ]; then cd "build/CMakeFiles/xlnt.static.dir$(pwd)" ; pwd ; fi
|
|
||||||
- if [ "$COMPILER" = "g++-4.9" ]; then coveralls --root $OLDWD --verbose -x ".cpp" --gcov-options '\-p' --exclude include --exclude third-party --exclude tests --exclude samples --exclude benchmarks -E ".*/source/.*/tests/.*" -E ".*/build/tests/runner-autogen.cpp.*" -E ".*CompilerIdCXX/.*" ; fi
|
|
||||||
|
|
|
@ -19,57 +19,107 @@ xlnt is a C++14 library for reading, writing, and modifying XLSX files as descri
|
||||||
Summary of Features
|
Summary of Features
|
||||||
+++++++++++++++++++
|
+++++++++++++++++++
|
||||||
|
|
||||||
|
+---------------------------------------------------------------------+------+------+-------+
|
||||||
| Feature | Read | Edit | Write |
|
| Feature | Read | Edit | Write |
|
||||||
|---------------------------------------------------------------------|------|------|-------|
|
+=====================================================================+======+======+=======+
|
||||||
| Excel-style Workbook | ✓ | ✓ | ✓ |
|
| Excel-style Workbook | ✓ | ✓ | ✓ |
|
||||||
|
+---------------------------------------------------------------------+------+------+-------+
|
||||||
| LibreOffice-style Workbook | ✓ | ✓ | ✓ |
|
| LibreOffice-style Workbook | ✓ | ✓ | ✓ |
|
||||||
|
+---------------------------------------------------------------------+------+------+-------+
|
||||||
| Numbers-style Workbook | ✓ | ✓ | ✓ |
|
| Numbers-style Workbook | ✓ | ✓ | ✓ |
|
||||||
|
+---------------------------------------------------------------------+------+------+-------+
|
||||||
| Encrypted Workbook (Excel 2007-2010) | ✓ | ✓ | |
|
| Encrypted Workbook (Excel 2007-2010) | ✓ | ✓ | |
|
||||||
|
+---------------------------------------------------------------------+------+------+-------+
|
||||||
| Encrypted Workbook (Excel 2013-2016) | ✓ | ✓ | |
|
| Encrypted Workbook (Excel 2013-2016) | ✓ | ✓ | |
|
||||||
|
+---------------------------------------------------------------------+------+------+-------+
|
||||||
| Excel Binary Workbook (.xlsb) | | | |
|
| Excel Binary Workbook (.xlsb) | | | |
|
||||||
|
+---------------------------------------------------------------------+------+------+-------+
|
||||||
| Excel Macro-Enabled Workbook (.xlsm) | | | |
|
| Excel Macro-Enabled Workbook (.xlsm) | | | |
|
||||||
|
+---------------------------------------------------------------------+------+------+-------+
|
||||||
| Excel Macro-Enabled Template (.xltm) | | | |
|
| Excel Macro-Enabled Template (.xltm) | | | |
|
||||||
|
+---------------------------------------------------------------------+------+------+-------+
|
||||||
| Document Properties | ✓ | ✓ | ✓ |
|
| Document Properties | ✓ | ✓ | ✓ |
|
||||||
|
+---------------------------------------------------------------------+------+------+-------+
|
||||||
| Numeric Cell Values | ✓ | ✓ | ✓ |
|
| Numeric Cell Values | ✓ | ✓ | ✓ |
|
||||||
|
+---------------------------------------------------------------------+------+------+-------+
|
||||||
| Inline String Cell Values | ✓ | ✓ | ✓ |
|
| Inline String Cell Values | ✓ | ✓ | ✓ |
|
||||||
|
+---------------------------------------------------------------------+------+------+-------+
|
||||||
| Shared String Cell Values | ✓ | ✓ | ✓ |
|
| Shared String Cell Values | ✓ | ✓ | ✓ |
|
||||||
|
+---------------------------------------------------------------------+------+------+-------+
|
||||||
| Shared String Text Run Formatting (e.g. varied fonts within a cell) | ✓ | ✓ | ✓ |
|
| Shared String Text Run Formatting (e.g. varied fonts within a cell) | ✓ | ✓ | ✓ |
|
||||||
|
+---------------------------------------------------------------------+------+------+-------+
|
||||||
| Hyperlink Cell Values | | | |
|
| Hyperlink Cell Values | | | |
|
||||||
|
+---------------------------------------------------------------------+------+------+-------+
|
||||||
| Formula Cell Values | | | |
|
| Formula Cell Values | | | |
|
||||||
|
+---------------------------------------------------------------------+------+------+-------+
|
||||||
| Formula Evaluation | | | |
|
| Formula Evaluation | | | |
|
||||||
|
+---------------------------------------------------------------------+------+------+-------+
|
||||||
| Page Margins | ✓ | ✓ | ✓ |
|
| Page Margins | ✓ | ✓ | ✓ |
|
||||||
|
+---------------------------------------------------------------------+------+------+-------+
|
||||||
| Page Setup | | | |
|
| Page Setup | | | |
|
||||||
|
+---------------------------------------------------------------------+------+------+-------+
|
||||||
| Print Area | | | |
|
| Print Area | | | |
|
||||||
| Comments | | | |
|
+---------------------------------------------------------------------+------+------+-------+
|
||||||
|
| Comments | ✓ | ✓ | |
|
||||||
|
+---------------------------------------------------------------------+------+------+-------+
|
||||||
| Header and Footer | | | |
|
| Header and Footer | | | |
|
||||||
|
+---------------------------------------------------------------------+------+------+-------+
|
||||||
| Custom Views | | | |
|
| Custom Views | | | |
|
||||||
|
+---------------------------------------------------------------------+------+------+-------+
|
||||||
| Charts | | | |
|
| Charts | | | |
|
||||||
|
+---------------------------------------------------------------------+------+------+-------+
|
||||||
| Chartsheets | | | |
|
| Chartsheets | | | |
|
||||||
|
+---------------------------------------------------------------------+------+------+-------+
|
||||||
| Dialogsheets | | | |
|
| Dialogsheets | | | |
|
||||||
|
+---------------------------------------------------------------------+------+------+-------+
|
||||||
| Themes | ✓ | | ✓ |
|
| Themes | ✓ | | ✓ |
|
||||||
|
+---------------------------------------------------------------------+------+------+-------+
|
||||||
| Cell Styles | ✓ | ✓ | ✓ |
|
| Cell Styles | ✓ | ✓ | ✓ |
|
||||||
|
+---------------------------------------------------------------------+------+------+-------+
|
||||||
| Cell Formats | ✓ | ✓ | ✓ |
|
| Cell Formats | ✓ | ✓ | ✓ |
|
||||||
|
+---------------------------------------------------------------------+------+------+-------+
|
||||||
| Formatting->Alignment (e.g. right align) | ✓ | ✓ | ✓ |
|
| Formatting->Alignment (e.g. right align) | ✓ | ✓ | ✓ |
|
||||||
|
+---------------------------------------------------------------------+------+------+-------+
|
||||||
| Formatting->Border (e.g. red cell outline) | ✓ | ✓ | ✓ |
|
| Formatting->Border (e.g. red cell outline) | ✓ | ✓ | ✓ |
|
||||||
|
+---------------------------------------------------------------------+------+------+-------+
|
||||||
| Formatting->Fill (e.g. green cell background) | ✓ | ✓ | ✓ |
|
| Formatting->Fill (e.g. green cell background) | ✓ | ✓ | ✓ |
|
||||||
|
+---------------------------------------------------------------------+------+------+-------+
|
||||||
| Formatting->Font (e.g. blue cell text) | ✓ | ✓ | ✓ |
|
| Formatting->Font (e.g. blue cell text) | ✓ | ✓ | ✓ |
|
||||||
|
+---------------------------------------------------------------------+------+------+-------+
|
||||||
| Formatting->Number Format (e.g. show 2 decimals) | ✓ | ✓ | ✓ |
|
| Formatting->Number Format (e.g. show 2 decimals) | ✓ | ✓ | ✓ |
|
||||||
|
+---------------------------------------------------------------------+------+------+-------+
|
||||||
| Formatting->Protection (e.g. hide formulas) | ✓ | ✓ | ✓ |
|
| Formatting->Protection (e.g. hide formulas) | ✓ | ✓ | ✓ |
|
||||||
|
+---------------------------------------------------------------------+------+------+-------+
|
||||||
| Column Styles | | | |
|
| Column Styles | | | |
|
||||||
|
+---------------------------------------------------------------------+------+------+-------+
|
||||||
| Row Styles | | | |
|
| Row Styles | | | |
|
||||||
|
+---------------------------------------------------------------------+------+------+-------+
|
||||||
| Sheet Styles | | | |
|
| Sheet Styles | | | |
|
||||||
|
+---------------------------------------------------------------------+------+------+-------+
|
||||||
| Conditional Formatting | | | |
|
| Conditional Formatting | | | |
|
||||||
|
+---------------------------------------------------------------------+------+------+-------+
|
||||||
| Tables | | | |
|
| Tables | | | |
|
||||||
|
+---------------------------------------------------------------------+------+------+-------+
|
||||||
| Table Formatting | | | |
|
| Table Formatting | | | |
|
||||||
|
+---------------------------------------------------------------------+------+------+-------+
|
||||||
| Pivot Tables | | | |
|
| Pivot Tables | | | |
|
||||||
|
+---------------------------------------------------------------------+------+------+-------+
|
||||||
| XLSX Thumbnail | ✓ | | ✓ |
|
| XLSX Thumbnail | ✓ | | ✓ |
|
||||||
|
+---------------------------------------------------------------------+------+------+-------+
|
||||||
| Custom OOXML Properties | | | |
|
| Custom OOXML Properties | | | |
|
||||||
|
+---------------------------------------------------------------------+------+------+-------+
|
||||||
| Custom OOXML Parts | | | |
|
| Custom OOXML Parts | | | |
|
||||||
|
+---------------------------------------------------------------------+------+------+-------+
|
||||||
| Drawing | | | |
|
| Drawing | | | |
|
||||||
|
+---------------------------------------------------------------------+------+------+-------+
|
||||||
| Text Box | | | |
|
| Text Box | | | |
|
||||||
|
+---------------------------------------------------------------------+------+------+-------+
|
||||||
| WordArt | | | |
|
| WordArt | | | |
|
||||||
|
+---------------------------------------------------------------------+------+------+-------+
|
||||||
| Embedded Content (e.g. images) | | | |
|
| Embedded Content (e.g. images) | | | |
|
||||||
|
+---------------------------------------------------------------------+------+------+-------+
|
||||||
| Excel VBA | | | |
|
| Excel VBA | | | |
|
||||||
|
+---------------------------------------------------------------------+------+------+-------+
|
||||||
|
|
||||||
Sample code:
|
Sample code:
|
||||||
++++++++++++
|
++++++++++++
|
||||||
|
|
|
@ -86,12 +86,6 @@ public:
|
||||||
/// </summary>
|
/// </summary>
|
||||||
cell_reference(const std::string &reference_string);
|
cell_reference(const std::string &reference_string);
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Constructs a cell_reference from a string reprenting a column (e.g. A) and
|
|
||||||
/// a 1-indexed row.
|
|
||||||
/// </summary>
|
|
||||||
cell_reference(const std::string &column, row_t row);
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Constructs a cell_reference from a 1-indexed column index and row index.
|
/// Constructs a cell_reference from a 1-indexed column index and row index.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -81,12 +81,12 @@ public:
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Construct a column from a string.
|
/// Construct a column from a string.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
explicit column_t(const std::string &column_string);
|
column_t(const std::string &column_string);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Construct a column from a string.
|
/// Construct a column from a string.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
explicit column_t(const char *column_string);
|
column_t(const char *column_string);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Copy constructor
|
/// Copy constructor
|
||||||
|
|
|
@ -27,7 +27,6 @@
|
||||||
#include <xlnt/utils/hash_combine.hpp>
|
#include <xlnt/utils/hash_combine.hpp>
|
||||||
#include <xlnt/styles/horizontal_alignment.hpp>
|
#include <xlnt/styles/horizontal_alignment.hpp>
|
||||||
#include <xlnt/styles/vertical_alignment.hpp>
|
#include <xlnt/styles/vertical_alignment.hpp>
|
||||||
#include <xlnt/utils/hashable.hpp>
|
|
||||||
#include <xlnt/utils/optional.hpp>
|
#include <xlnt/utils/optional.hpp>
|
||||||
|
|
||||||
namespace xlnt {
|
namespace xlnt {
|
||||||
|
@ -35,7 +34,7 @@ namespace xlnt {
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Alignment options for use in cell formats.
|
/// Alignment options for use in cell formats.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
class XLNT_API alignment : public hashable
|
class XLNT_API alignment
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
optional<bool> shrink() const;
|
optional<bool> shrink() const;
|
||||||
|
@ -62,8 +61,15 @@ public:
|
||||||
|
|
||||||
alignment &vertical(vertical_alignment vertical);
|
alignment &vertical(vertical_alignment vertical);
|
||||||
|
|
||||||
protected:
|
/// <summary>
|
||||||
std::string to_hash_string() const override;
|
/// Returns true if left is exactly equal to right.
|
||||||
|
/// </summary>
|
||||||
|
friend bool operator==(const alignment &left, const alignment &right);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns true if left is not exactly equal to right.
|
||||||
|
/// </summary>
|
||||||
|
friend bool operator!=(const alignment &left, const alignment &right) { return !(left == right); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
optional<bool> shrink_to_fit_;
|
optional<bool> shrink_to_fit_;
|
||||||
|
|
|
@ -33,7 +33,6 @@
|
||||||
#include <xlnt/styles/color.hpp>
|
#include <xlnt/styles/color.hpp>
|
||||||
#include <xlnt/styles/diagonal_direction.hpp>
|
#include <xlnt/styles/diagonal_direction.hpp>
|
||||||
#include <xlnt/styles/side.hpp>
|
#include <xlnt/styles/side.hpp>
|
||||||
#include <xlnt/utils/hashable.hpp>
|
|
||||||
#include <xlnt/utils/optional.hpp>
|
#include <xlnt/utils/optional.hpp>
|
||||||
|
|
||||||
namespace xlnt {
|
namespace xlnt {
|
||||||
|
@ -56,7 +55,7 @@ namespace xlnt {
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Describes the border style of a particular cell.
|
/// Describes the border style of a particular cell.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
class XLNT_API border : public hashable
|
class XLNT_API border
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
class XLNT_API border_property
|
class XLNT_API border_property
|
||||||
|
@ -68,6 +67,16 @@ public:
|
||||||
optional<border_style> style() const;
|
optional<border_style> style() const;
|
||||||
border_property &style(border_style style);
|
border_property &style(border_style style);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns true if left is exactly equal to right.
|
||||||
|
/// </summary>
|
||||||
|
friend bool operator==(const border_property &left, const border_property &right);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns true if left is not exactly equal to right.
|
||||||
|
/// </summary>
|
||||||
|
friend bool operator!=(const border_property &left, const border_property &right) { return !(left == right); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
optional<class color> color_;
|
optional<class color> color_;
|
||||||
optional<border_style> style_;
|
optional<border_style> style_;
|
||||||
|
@ -83,8 +92,15 @@ public:
|
||||||
optional<diagonal_direction> diagonal() const;
|
optional<diagonal_direction> diagonal() const;
|
||||||
border &diagonal(diagonal_direction dir);
|
border &diagonal(diagonal_direction dir);
|
||||||
|
|
||||||
protected:
|
/// <summary>
|
||||||
std::string to_hash_string() const override;
|
/// Returns true if left is exactly equal to right.
|
||||||
|
/// </summary>
|
||||||
|
friend bool operator==(const border &left, const border &right);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns true if left is not exactly equal to right.
|
||||||
|
/// </summary>
|
||||||
|
friend bool operator!=(const border &left, const border &right) { return !(left == right); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
optional<border_property> start_;
|
optional<border_property> start_;
|
||||||
|
|
|
@ -87,7 +87,7 @@ private:
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Colors can be applied to many parts of a cell's style.
|
/// Colors can be applied to many parts of a cell's style.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
class XLNT_API color : public hashable
|
class XLNT_API color
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -136,9 +136,6 @@ public:
|
||||||
bool operator==(const color &other) const;
|
bool operator==(const color &other) const;
|
||||||
bool operator!=(const color &other) const { return !(*this == other); }
|
bool operator!=(const color &other) const { return !(*this == other); }
|
||||||
|
|
||||||
protected:
|
|
||||||
std::string to_hash_string() const override;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void assert_type(type t) const;
|
void assert_type(type t) const;
|
||||||
|
|
||||||
|
|
|
@ -54,7 +54,7 @@ enum class XLNT_API pattern_fill_type
|
||||||
gray0625
|
gray0625
|
||||||
};
|
};
|
||||||
|
|
||||||
class XLNT_API pattern_fill : public hashable
|
class XLNT_API pattern_fill
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
pattern_fill();
|
pattern_fill();
|
||||||
|
@ -71,8 +71,15 @@ public:
|
||||||
|
|
||||||
pattern_fill &background(const color &background);
|
pattern_fill &background(const color &background);
|
||||||
|
|
||||||
protected:
|
/// <summary>
|
||||||
std::string to_hash_string() const override;
|
/// Returns true if left is exactly equal to right.
|
||||||
|
/// </summary>
|
||||||
|
friend bool operator==(const pattern_fill &left, const pattern_fill &right);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns true if left is not exactly equal to right.
|
||||||
|
/// </summary>
|
||||||
|
friend bool operator!=(const pattern_fill &left, const pattern_fill &right) { return !(left == right); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
pattern_fill_type type_ = pattern_fill_type::none;
|
pattern_fill_type type_ = pattern_fill_type::none;
|
||||||
|
@ -87,7 +94,7 @@ enum class XLNT_API gradient_fill_type
|
||||||
path
|
path
|
||||||
};
|
};
|
||||||
|
|
||||||
class XLNT_API gradient_fill : public hashable
|
class XLNT_API gradient_fill
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
gradient_fill();
|
gradient_fill();
|
||||||
|
@ -135,8 +142,15 @@ public:
|
||||||
|
|
||||||
std::unordered_map<double, color> stops() const;
|
std::unordered_map<double, color> stops() const;
|
||||||
|
|
||||||
protected:
|
/// <summary>
|
||||||
std::string to_hash_string() const override;
|
/// Returns true if left is exactly equal to right.
|
||||||
|
/// </summary>
|
||||||
|
friend bool operator==(const gradient_fill &left, const gradient_fill &right);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns true if left is not exactly equal to right.
|
||||||
|
/// </summary>
|
||||||
|
friend bool operator!=(const gradient_fill &left, const gradient_fill &right) { return !(left == right); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
gradient_fill_type type_ = gradient_fill_type::linear;
|
gradient_fill_type type_ = gradient_fill_type::linear;
|
||||||
|
@ -160,7 +174,7 @@ enum class XLNT_API fill_type
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Describes the fill style of a particular cell.
|
/// Describes the fill style of a particular cell.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
class XLNT_API fill : public hashable
|
class XLNT_API fill
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -204,8 +218,15 @@ public:
|
||||||
/// </summary>
|
/// </summary>
|
||||||
class pattern_fill pattern_fill() const;
|
class pattern_fill pattern_fill() const;
|
||||||
|
|
||||||
protected:
|
/// <summary>
|
||||||
std::string to_hash_string() const override;
|
/// Returns true if left is exactly equal to right.
|
||||||
|
/// </summary>
|
||||||
|
friend bool operator==(const fill &left, const fill &right);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns true if left is not exactly equal to right.
|
||||||
|
/// </summary>
|
||||||
|
friend bool operator!=(const fill &left, const fill &right) { return !(left == right); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
fill_type type_ = fill_type::pattern;
|
fill_type type_ = fill_type::pattern;
|
||||||
|
|
|
@ -36,7 +36,7 @@ class style;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Describes the font style of a particular cell.
|
/// Describes the font style of a particular cell.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
class XLNT_API font : public hashable
|
class XLNT_API font
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
enum class underline_style
|
enum class underline_style
|
||||||
|
@ -92,8 +92,15 @@ public:
|
||||||
|
|
||||||
optional<std::string> scheme() const;
|
optional<std::string> scheme() const;
|
||||||
|
|
||||||
protected:
|
/// <summary>
|
||||||
std::string to_hash_string() const override;
|
/// Returns true if left is exactly equal to right.
|
||||||
|
/// </summary>
|
||||||
|
friend bool operator==(const font &left, const font &right);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns true if left is not exactly equal to right.
|
||||||
|
/// </summary>
|
||||||
|
friend bool operator!=(const font &left, const font &right) { return !(left == right); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class style;
|
friend class style;
|
||||||
|
|
|
@ -27,7 +27,6 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include <xlnt/xlnt_config.hpp>
|
#include <xlnt/xlnt_config.hpp>
|
||||||
#include <xlnt/utils/hashable.hpp>
|
|
||||||
|
|
||||||
namespace xlnt {
|
namespace xlnt {
|
||||||
|
|
||||||
|
@ -36,7 +35,7 @@ enum class calendar;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Describes the number formatting applied to text and numbers within a certain cell.
|
/// Describes the number formatting applied to text and numbers within a certain cell.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
class XLNT_API number_format : public hashable
|
class XLNT_API number_format
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static const number_format general();
|
static const number_format general();
|
||||||
|
@ -88,8 +87,16 @@ public:
|
||||||
|
|
||||||
bool is_date_format() const;
|
bool is_date_format() const;
|
||||||
|
|
||||||
protected:
|
|
||||||
std::string to_hash_string() const override;
|
/// <summary>
|
||||||
|
/// Returns true if left is exactly equal to right.
|
||||||
|
/// </summary>
|
||||||
|
friend bool operator==(const number_format &left, const number_format &right);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns true if left is not exactly equal to right.
|
||||||
|
/// </summary>
|
||||||
|
friend bool operator!=(const number_format &left, const number_format &right) { return !(left == right); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool id_set_;
|
bool id_set_;
|
||||||
|
|
|
@ -26,7 +26,6 @@
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
|
|
||||||
#include <xlnt/xlnt_config.hpp>
|
#include <xlnt/xlnt_config.hpp>
|
||||||
#include <xlnt/utils/hashable.hpp>
|
|
||||||
#include <xlnt/utils/optional.hpp>
|
#include <xlnt/utils/optional.hpp>
|
||||||
|
|
||||||
namespace xlnt {
|
namespace xlnt {
|
||||||
|
@ -34,7 +33,7 @@ namespace xlnt {
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Describes the protection style of a particular cell.
|
/// Describes the protection style of a particular cell.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
class XLNT_API protection : public hashable
|
class XLNT_API protection
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static protection unlocked_and_visible();
|
static protection unlocked_and_visible();
|
||||||
|
@ -50,8 +49,15 @@ public:
|
||||||
bool hidden() const;
|
bool hidden() const;
|
||||||
protection &hidden(bool hidden);
|
protection &hidden(bool hidden);
|
||||||
|
|
||||||
protected:
|
/// <summary>
|
||||||
std::string to_hash_string() const override;
|
/// Returns true if left is exactly equal to right.
|
||||||
|
/// </summary>
|
||||||
|
friend bool operator==(const protection &left, const protection &right);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns true if left is not exactly equal to right.
|
||||||
|
/// </summary>
|
||||||
|
friend bool operator!=(const protection &left, const protection &right) { return !(left == right); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool locked_;
|
bool locked_;
|
||||||
|
|
|
@ -38,6 +38,8 @@ class XLNT_API exception : public std::runtime_error
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
exception(const std::string &message);
|
exception(const std::string &message);
|
||||||
|
exception(const exception &) = default;
|
||||||
|
virtual ~exception();
|
||||||
|
|
||||||
void set_message(const std::string &message);
|
void set_message(const std::string &message);
|
||||||
|
|
||||||
|
@ -107,6 +109,8 @@ class XLNT_API invalid_column_string_index : public exception
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
invalid_column_string_index();
|
invalid_column_string_index();
|
||||||
|
invalid_column_string_index(const invalid_column_string_index &) = default;
|
||||||
|
~invalid_column_string_index();
|
||||||
};
|
};
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -117,6 +121,8 @@ class XLNT_API invalid_cell_reference : public exception
|
||||||
public:
|
public:
|
||||||
invalid_cell_reference(column_t column, row_t row);
|
invalid_cell_reference(column_t column, row_t row);
|
||||||
invalid_cell_reference(const std::string &reference_string);
|
invalid_cell_reference(const std::string &reference_string);
|
||||||
|
invalid_cell_reference(const invalid_cell_reference &) = default;
|
||||||
|
~invalid_cell_reference();
|
||||||
};
|
};
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -126,6 +132,8 @@ class XLNT_API invalid_attribute : public exception
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
invalid_attribute();
|
invalid_attribute();
|
||||||
|
invalid_attribute(const invalid_attribute &) = default;
|
||||||
|
virtual ~invalid_attribute();
|
||||||
};
|
};
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
@ -1,55 +0,0 @@
|
||||||
// Copyright (c) 2014-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 <cstdint>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
#include <xlnt/xlnt_config.hpp>
|
|
||||||
|
|
||||||
namespace xlnt {
|
|
||||||
|
|
||||||
class XLNT_API hashable
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
std::size_t hash() const;
|
|
||||||
bool operator==(const hashable &other) const;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
virtual std::string to_hash_string() const = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace xlnt
|
|
||||||
|
|
||||||
namespace std {
|
|
||||||
|
|
||||||
template<>
|
|
||||||
struct hash<xlnt::hashable>
|
|
||||||
{
|
|
||||||
size_t operator()(const xlnt::hashable &k) const
|
|
||||||
{
|
|
||||||
return k.hash();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namepsace std
|
|
|
@ -24,7 +24,6 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include <utf8.h>
|
|
||||||
#include <xlnt/xlnt_config.hpp> // for XLNT_API
|
#include <xlnt/xlnt_config.hpp> // for XLNT_API
|
||||||
|
|
||||||
#include <xlnt/xlnt_config.hpp>
|
#include <xlnt/xlnt_config.hpp>
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <xlnt/xlnt_config.hpp>
|
#include <xlnt/xlnt_config.hpp>
|
||||||
|
#include <xlnt/cell/index_types.hpp>
|
||||||
#include <xlnt/cell/cell_reference.hpp>
|
#include <xlnt/cell/cell_reference.hpp>
|
||||||
|
|
||||||
namespace xlnt {
|
namespace xlnt {
|
||||||
|
@ -57,8 +58,8 @@ public:
|
||||||
cell_reference top_left_cell;
|
cell_reference top_left_cell;
|
||||||
pane_state state;
|
pane_state state;
|
||||||
pane_corner active_pane;
|
pane_corner active_pane;
|
||||||
int y_split;
|
row_t y_split;
|
||||||
int x_split;
|
column_t x_split;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace xlnt
|
} // namespace xlnt
|
||||||
|
|
|
@ -223,10 +223,10 @@ public:
|
||||||
|
|
||||||
range iter_cells(bool skip_null);
|
range iter_cells(bool skip_null);
|
||||||
|
|
||||||
void add_print_title(int i);
|
void set_print_title_rows(row_t first_row, row_t last_row);
|
||||||
void add_print_title(int i, const std::string &rows_or_cols);
|
void set_print_title_rows(row_t last_row);
|
||||||
void set_print_title_rows(const std::string &rows);
|
void set_print_title_cols(column_t first_column, column_t last_column);
|
||||||
void set_print_title_cols(const std::string &rows);
|
void set_print_title_cols(column_t last_column);
|
||||||
std::string get_print_titles() const;
|
std::string get_print_titles() const;
|
||||||
|
|
||||||
void set_print_area(const std::string &print_area);
|
void set_print_area(const std::string &print_area);
|
||||||
|
|
|
@ -26,28 +26,6 @@
|
||||||
|
|
||||||
namespace xlnt {
|
namespace xlnt {
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Enumeration of possible limit styles.
|
|
||||||
/// Excel places limitations on the number of rows and columns,
|
|
||||||
/// but we may wish to change those limits in some cases. Values
|
|
||||||
/// other than excel might prevent the file from being opened in Excel.
|
|
||||||
/// </summary>
|
|
||||||
enum class limit_style
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// limits used in openpyxl
|
|
||||||
/// </summary>
|
|
||||||
openpyxl,
|
|
||||||
/// <summary>
|
|
||||||
/// limits as determined by Excel
|
|
||||||
/// </summary>
|
|
||||||
excel,
|
|
||||||
/// <summary>
|
|
||||||
/// limits as high as possible based on system (i.e. 32-bit or 64-bit)
|
|
||||||
/// </summary>
|
|
||||||
maximum
|
|
||||||
};
|
|
||||||
|
|
||||||
#ifndef XLNT_API
|
#ifndef XLNT_API
|
||||||
#if !defined(XLNT_STATIC) && defined(_MSC_VER)
|
#if !defined(XLNT_STATIC) && defined(_MSC_VER)
|
||||||
#ifdef XLNT_EXPORT
|
#ifdef XLNT_EXPORT
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
cmake_minimum_required(VERSION 3.1)
|
||||||
include(${CMAKE_CURRENT_SOURCE_DIR}/../cmake/common.cmake)
|
include(${CMAKE_CURRENT_SOURCE_DIR}/../cmake/common.cmake)
|
||||||
project(${LIBRARY_NAME}.samples VERSION ${LIBRARY_VERSION} LANGUAGES CXX C)
|
project(${LIBRARY_NAME}.samples VERSION ${LIBRARY_VERSION} LANGUAGES CXX C)
|
||||||
|
|
||||||
|
@ -7,18 +8,22 @@ endif()
|
||||||
|
|
||||||
include_directories(${LIBRARY_INCLUDE_DIR})
|
include_directories(${LIBRARY_INCLUDE_DIR})
|
||||||
|
|
||||||
add_executable(sample-basic ${CMAKE_CURRENT_SOURCE_DIR}/sample.cpp)
|
file(GLOB SAMPLE_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp)
|
||||||
target_link_libraries(sample-basic ${LIBRARY_NAME})
|
|
||||||
|
|
||||||
add_executable(sample-decrypt ${CMAKE_CURRENT_SOURCE_DIR}/decrypt.cpp)
|
|
||||||
target_link_libraries(sample-decrypt ${LIBRARY_NAME})
|
|
||||||
|
|
||||||
if(NOT MSVC)
|
if(NOT MSVC)
|
||||||
set(THREADS_PREFER_PTHREAD_FLAG ON)
|
set(THREADS_PREFER_PTHREAD_FLAG ON)
|
||||||
find_package(Threads REQUIRED)
|
find_package(Threads REQUIRED)
|
||||||
target_link_libraries(sample-basic Threads::Threads)
|
|
||||||
target_link_libraries(sample-decrypt Threads::Threads)
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
foreach(SAMPLE_SOURCE IN ITEMS ${SAMPLE_SOURCES})
|
||||||
|
get_filename_component(SAMPLE_NAME ${SAMPLE_SOURCE} NAME_WE)
|
||||||
|
set(SAMPLE_EXECUTABLE sample-${SAMPLE_NAME})
|
||||||
|
add_executable(${SAMPLE_EXECUTABLE} ${SAMPLE_SOURCE})
|
||||||
|
target_link_libraries(${SAMPLE_EXECUTABLE} ${LIBRARY_NAME})
|
||||||
|
if(NOT MSVC)
|
||||||
|
target_link_libraries(${SAMPLE_EXECUTABLE} Threads::Threads)
|
||||||
|
endif()
|
||||||
|
endforeach()
|
||||||
|
|
||||||
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/data
|
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/data
|
||||||
DESTINATION ${CMAKE_BINARY_DIR}/bin)
|
DESTINATION ${CMAKE_BINARY_DIR}/bin)
|
||||||
|
|
|
@ -51,6 +51,14 @@ if(COVERAGE)
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage")
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(MSVC)
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4")
|
||||||
|
elseif(CMAKE_CXX_COMPILER_ID MATCHES "GNU")
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra")
|
||||||
|
elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Weverything -Wno-c++98-compat -Wno-padded")
|
||||||
|
endif()
|
||||||
|
|
||||||
if(APPLE)
|
if(APPLE)
|
||||||
# Prevent a warning about deployment target not being set
|
# Prevent a warning about deployment target not being set
|
||||||
execute_process(COMMAND "sw_vers -productVersion | awk -F'.' '{print $1\".\"$2}'"
|
execute_process(COMMAND "sw_vers -productVersion | awk -F'.' '{print $1\".\"$2}'"
|
||||||
|
@ -68,7 +76,6 @@ include_directories(${XLNT_INCLUDE_DIR}
|
||||||
${THIRD_PARTY_DIR}/utfcpp/source
|
${THIRD_PARTY_DIR}/utfcpp/source
|
||||||
${THIRD_PARTY_DIR}/pole
|
${THIRD_PARTY_DIR}/pole
|
||||||
${THIRD_PARTY_DIR}/botan
|
${THIRD_PARTY_DIR}/botan
|
||||||
${THIRD_PARTY_DIR}/partio
|
|
||||||
${THIRD_PARTY_DIR}/zlib)
|
${THIRD_PARTY_DIR}/zlib)
|
||||||
|
|
||||||
file(GLOB ROOT_HEADERS ${XLNT_INCLUDE_DIR}/xlnt/*.hpp)
|
file(GLOB ROOT_HEADERS ${XLNT_INCLUDE_DIR}/xlnt/*.hpp)
|
||||||
|
@ -92,7 +99,7 @@ file(GLOB WORKBOOK_HEADERS ${XLNT_INCLUDE_DIR}/xlnt/workbook/*.hpp)
|
||||||
file(GLOB WORKBOOK_SOURCES ${XLNT_SOURCE_DIR}/workbook/*.cpp)
|
file(GLOB WORKBOOK_SOURCES ${XLNT_SOURCE_DIR}/workbook/*.cpp)
|
||||||
file(GLOB WORKSHEET_HEADERS ${XLNT_INCLUDE_DIR}/xlnt/worksheet/*.hpp)
|
file(GLOB WORKSHEET_HEADERS ${XLNT_INCLUDE_DIR}/xlnt/worksheet/*.hpp)
|
||||||
file(GLOB WORKSHEET_SOURCES ${XLNT_SOURCE_DIR}/worksheet/*.cpp)
|
file(GLOB WORKSHEET_SOURCES ${XLNT_SOURCE_DIR}/worksheet/*.cpp)
|
||||||
file(GLOB DETAIL_HEADERS ${XLNT_INCLUDE_DIR}/detail/*.hpp)
|
file(GLOB DETAIL_HEADERS ${XLNT_SOURCE_DIR}/detail/*.hpp)
|
||||||
file(GLOB DETAIL_SOURCES ${XLNT_SOURCE_DIR}/detail/*.cpp)
|
file(GLOB DETAIL_SOURCES ${XLNT_SOURCE_DIR}/detail/*.cpp)
|
||||||
|
|
||||||
set(XLNT_HEADERS ${ROOT_HEADERS} ${CELL_HEADERS} ${CHARTS_HEADERS}
|
set(XLNT_HEADERS ${ROOT_HEADERS} ${CELL_HEADERS} ${CHARTS_HEADERS}
|
||||||
|
|
|
@ -522,7 +522,7 @@ void cell::set_error(const std::string &error)
|
||||||
|
|
||||||
cell cell::offset(int column, int row)
|
cell cell::offset(int column, int row)
|
||||||
{
|
{
|
||||||
return get_worksheet().get_cell(cell_reference(d_->column_ + column, d_->row_ + row));
|
return get_worksheet().get_cell(get_reference().make_offset(column, row));
|
||||||
}
|
}
|
||||||
|
|
||||||
worksheet cell::get_worksheet()
|
worksheet cell::get_worksheet()
|
||||||
|
|
|
@ -61,11 +61,6 @@ cell_reference::cell_reference(const char *reference_string)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
cell_reference::cell_reference(const std::string &column, row_t row)
|
|
||||||
: cell_reference(column_t(column), row)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
||||||
{
|
{
|
||||||
|
@ -268,8 +263,10 @@ 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
|
||||||
return cell_reference(static_cast<column_t>(static_cast<int>(column_.index) + column_offset),
|
auto relative_column = static_cast<column_t::index_t>(static_cast<int>(column_.index) + column_offset);
|
||||||
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);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool cell_reference::operator==(const cell_reference &comparand) const
|
bool cell_reference::operator==(const cell_reference &comparand) const
|
||||||
|
|
|
@ -114,7 +114,7 @@ bool column_t::operator==(const column_t &other) const { return index == other.i
|
||||||
|
|
||||||
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(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); }
|
||||||
|
|
||||||
|
|
|
@ -51,7 +51,7 @@ bool text_run::has_formatting() const
|
||||||
|
|
||||||
bool text_run::has_size() const
|
bool text_run::has_size() const
|
||||||
{
|
{
|
||||||
return (bool)size_;
|
return size_.is_set();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::size_t text_run::get_size() const
|
std::size_t text_run::get_size() const
|
||||||
|
@ -66,7 +66,7 @@ void text_run::set_size(std::size_t size)
|
||||||
|
|
||||||
bool text_run::has_color() const
|
bool text_run::has_color() const
|
||||||
{
|
{
|
||||||
return (bool)color_;
|
return color_.is_set();
|
||||||
}
|
}
|
||||||
|
|
||||||
color text_run::get_color() const
|
color text_run::get_color() const
|
||||||
|
@ -81,7 +81,7 @@ void text_run::set_color(const color &new_color)
|
||||||
|
|
||||||
bool text_run::has_font() const
|
bool text_run::has_font() const
|
||||||
{
|
{
|
||||||
return (bool)font_;
|
return font_.is_set();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string text_run::get_font() const
|
std::string text_run::get_font() const
|
||||||
|
@ -96,7 +96,7 @@ void text_run::set_font(const std::string &font)
|
||||||
|
|
||||||
bool text_run::has_family() const
|
bool text_run::has_family() const
|
||||||
{
|
{
|
||||||
return (bool)family_;
|
return family_.is_set();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::size_t text_run::get_family() const
|
std::size_t text_run::get_family() const
|
||||||
|
@ -111,7 +111,7 @@ void text_run::set_family(std::size_t family)
|
||||||
|
|
||||||
bool text_run::has_scheme() const
|
bool text_run::has_scheme() const
|
||||||
{
|
{
|
||||||
return (bool)scheme_;
|
return scheme_.is_set();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string text_run::get_scheme() const
|
std::string text_run::get_scheme() const
|
||||||
|
@ -126,7 +126,7 @@ void text_run::set_scheme(const std::string &scheme)
|
||||||
|
|
||||||
bool text_run::bold_set() const
|
bool text_run::bold_set() const
|
||||||
{
|
{
|
||||||
return (bool)bold_;
|
return bold_.is_set();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool text_run::is_bold() const
|
bool text_run::is_bold() const
|
||||||
|
|
|
@ -27,12 +27,12 @@
|
||||||
|
|
||||||
namespace xlnt {
|
namespace xlnt {
|
||||||
|
|
||||||
const row_t constants::min_row()
|
row_t constants::min_row()
|
||||||
{
|
{
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
const row_t constants::max_row()
|
row_t constants::max_row()
|
||||||
{
|
{
|
||||||
return std::numeric_limits<row_t>::max();
|
return std::numeric_limits<row_t>::max();
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,12 +35,12 @@ struct XLNT_API constants
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns the lowest allowable row index in a worksheet.
|
/// Returns the lowest allowable row index in a worksheet.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
static const row_t min_row();
|
static row_t min_row();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns the largest allowable row index in a worksheet.
|
/// Returns the largest allowable row index in a worksheet.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
static const row_t max_row();
|
static row_t max_row();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns the lowest allowable column index in a worksheet.
|
/// Returns the lowest allowable column index in a worksheet.
|
||||||
|
|
|
@ -5,6 +5,8 @@
|
||||||
|
|
||||||
namespace xlnt {
|
namespace xlnt {
|
||||||
|
|
||||||
|
const std::vector<std::uint8_t> &excel_thumbnail();
|
||||||
|
|
||||||
const std::vector<std::uint8_t> &excel_thumbnail()
|
const std::vector<std::uint8_t> &excel_thumbnail()
|
||||||
{
|
{
|
||||||
const auto *data = new std::vector<std::uint8_t>{
|
const auto *data = new std::vector<std::uint8_t>{
|
||||||
|
|
|
@ -25,9 +25,9 @@
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
|
||||||
#include <detail/number_formatter.hpp>
|
#include <detail/number_formatter.hpp>
|
||||||
|
#include <xlnt/utils/exceptions.hpp>
|
||||||
|
|
||||||
namespace xlnt {
|
namespace {
|
||||||
namespace detail {
|
|
||||||
|
|
||||||
const std::unordered_map<int, std::string> known_locales()
|
const std::unordered_map<int, std::string> known_locales()
|
||||||
{
|
{
|
||||||
|
@ -139,11 +139,30 @@ const std::unordered_map<int, std::string> known_locales()
|
||||||
{ 0x3409, "English - Phillippines" },
|
{ 0x3409, "English - Phillippines" },
|
||||||
{ 0x3801, "Arabic - United Arab Emirates" },
|
{ 0x3801, "Arabic - United Arab Emirates" },
|
||||||
{ 0x4001, "Arabic - Qatar" }
|
{ 0x4001, "Arabic - Qatar" }
|
||||||
});
|
}
|
||||||
|
);
|
||||||
|
|
||||||
return *all;
|
return *all;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[[ noreturn ]] void unhandled_case_error()
|
||||||
|
{
|
||||||
|
throw xlnt::exception("unhandled");
|
||||||
|
}
|
||||||
|
|
||||||
|
void unhandled_case(bool error)
|
||||||
|
{
|
||||||
|
if (error)
|
||||||
|
{
|
||||||
|
unhandled_case_error();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
namespace xlnt {
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
bool format_condition::satisfied_by(long double number) const
|
bool format_condition::satisfied_by(long double number) const
|
||||||
{
|
{
|
||||||
switch (type)
|
switch (type)
|
||||||
|
@ -157,10 +176,9 @@ bool format_condition::satisfied_by(long double number) const
|
||||||
case condition_type::less_than:
|
case condition_type::less_than:
|
||||||
return number < value;
|
return number < value;
|
||||||
case condition_type::not_equal:
|
case condition_type::not_equal:
|
||||||
return number != value;
|
return std::fabs(number - value) >= std::numeric_limits<long double>::min();
|
||||||
case condition_type::equal:
|
case condition_type::equal:
|
||||||
default:
|
return std::fabs(number - value) < std::numeric_limits<long double>::min();
|
||||||
return number == value;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -336,6 +354,10 @@ void number_format_parser::parse()
|
||||||
part.type = template_part::template_type::elapsed_seconds;
|
part.type = template_part::template_type::elapsed_seconds;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unhandled_case(true);
|
||||||
|
break;
|
||||||
|
|
||||||
case 'm':
|
case 'm':
|
||||||
if (token.string == "m")
|
if (token.string == "m")
|
||||||
{
|
{
|
||||||
|
@ -362,6 +384,10 @@ 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);
|
||||||
|
break;
|
||||||
|
|
||||||
case 'd':
|
case 'd':
|
||||||
if (token.string == "d")
|
if (token.string == "d")
|
||||||
{
|
{
|
||||||
|
@ -383,6 +409,10 @@ 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);
|
||||||
|
break;
|
||||||
|
|
||||||
case 'y':
|
case 'y':
|
||||||
if (token.string == "yy")
|
if (token.string == "yy")
|
||||||
{
|
{
|
||||||
|
@ -394,6 +424,10 @@ 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);
|
||||||
|
break;
|
||||||
|
|
||||||
case 'h':
|
case 'h':
|
||||||
if (token.string == "h")
|
if (token.string == "h")
|
||||||
{
|
{
|
||||||
|
@ -405,6 +439,10 @@ 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);
|
||||||
|
break;
|
||||||
|
|
||||||
case 's':
|
case 's':
|
||||||
if (token.string == "s")
|
if (token.string == "s")
|
||||||
{
|
{
|
||||||
|
@ -416,6 +454,10 @@ 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);
|
||||||
|
break;
|
||||||
|
|
||||||
case 'A':
|
case 'A':
|
||||||
section.twelve_hour = true;
|
section.twelve_hour = true;
|
||||||
|
|
||||||
|
@ -429,6 +471,13 @@ 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);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
unhandled_case(true);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
section.parts.push_back(part);
|
section.parts.push_back(part);
|
||||||
|
@ -445,8 +494,6 @@ void number_format_parser::parse()
|
||||||
|
|
||||||
token = parse_next_token();
|
token = parse_next_token();
|
||||||
}
|
}
|
||||||
|
|
||||||
throw std::runtime_error("bad format");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void number_format_parser::finalize()
|
void number_format_parser::finalize()
|
||||||
|
@ -805,11 +852,41 @@ number_format_token number_format_parser::parse_next_token()
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case '(':
|
case '(':
|
||||||
|
token.type = number_format_token::token_type::text;
|
||||||
|
token.string.push_back(current_char);
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
case ')':
|
case ')':
|
||||||
|
token.type = number_format_token::token_type::text;
|
||||||
|
token.string.push_back(current_char);
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
case '-':
|
case '-':
|
||||||
|
token.type = number_format_token::token_type::text;
|
||||||
|
token.string.push_back(current_char);
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
case '+':
|
case '+':
|
||||||
|
token.type = number_format_token::token_type::text;
|
||||||
|
token.string.push_back(current_char);
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
case ':':
|
case ':':
|
||||||
|
token.type = number_format_token::token_type::text;
|
||||||
|
token.string.push_back(current_char);
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
case ' ':
|
case ' ':
|
||||||
|
token.type = number_format_token::token_type::text;
|
||||||
|
token.string.push_back(current_char);
|
||||||
|
|
||||||
|
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);
|
||||||
|
@ -832,6 +909,8 @@ number_format_token number_format_parser::parse_next_token()
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw std::runtime_error("unexpected character");
|
throw std::runtime_error("unexpected character");
|
||||||
}
|
}
|
||||||
|
@ -951,6 +1030,10 @@ format_color number_format_parser::color_from_string(const std::string &color)
|
||||||
return static_cast<format_color>(color_number);
|
return static_cast<format_color>(color_number);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unhandled_case(true);
|
||||||
|
break;
|
||||||
|
|
||||||
case 'B':
|
case 'B':
|
||||||
if (color == "Black")
|
if (color == "Black")
|
||||||
{
|
{
|
||||||
|
@ -960,34 +1043,60 @@ format_color number_format_parser::color_from_string(const std::string &color)
|
||||||
{
|
{
|
||||||
return format_color::blue;
|
return format_color::blue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unhandled_case(true);
|
||||||
|
break;
|
||||||
|
|
||||||
case 'G':
|
case 'G':
|
||||||
if (color == "Green")
|
if (color == "Green")
|
||||||
{
|
{
|
||||||
return format_color::green;
|
return format_color::green;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unhandled_case(true);
|
||||||
|
break;
|
||||||
|
|
||||||
case 'W':
|
case 'W':
|
||||||
if (color == "White")
|
if (color == "White")
|
||||||
{
|
{
|
||||||
return format_color::white;
|
return format_color::white;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unhandled_case(true);
|
||||||
|
break;
|
||||||
|
|
||||||
case 'M':
|
case 'M':
|
||||||
if (color == "Magenta")
|
if (color == "Magenta")
|
||||||
{
|
{
|
||||||
return format_color::magenta;
|
return format_color::magenta;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unhandled_case(true);
|
||||||
|
break;
|
||||||
|
|
||||||
case 'Y':
|
case 'Y':
|
||||||
if (color == "Yellow")
|
if (color == "Yellow")
|
||||||
{
|
{
|
||||||
return format_color::yellow;
|
return format_color::yellow;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unhandled_case(true);
|
||||||
|
break;
|
||||||
|
|
||||||
case 'R':
|
case 'R':
|
||||||
if (color == "Red")
|
if (color == "Red")
|
||||||
{
|
{
|
||||||
return format_color::red;
|
return format_color::red;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unhandled_case(true);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw std::runtime_error("bad color: " + color);
|
unhandled_case(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unhandled_case_error();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<format_locale, std::string> number_format_parser::locale_from_string(const std::string &locale_string)
|
std::pair<format_locale, std::string> number_format_parser::locale_from_string(const std::string &locale_string)
|
||||||
|
@ -1199,7 +1308,8 @@ std::string number_formatter::fill_placeholders(const format_placeholders &p, lo
|
||||||
else if (p.type == format_placeholders::placeholders_type::fractional_part)
|
else if (p.type == format_placeholders::placeholders_type::fractional_part)
|
||||||
{
|
{
|
||||||
auto fractional_part = number - integer_part;
|
auto fractional_part = number - integer_part;
|
||||||
result = fractional_part == 0 ? std::string(".") : std::to_string(fractional_part).substr(1);
|
result = std::fabs(fractional_part) < std::numeric_limits<long double>::min()
|
||||||
|
? 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))
|
||||||
{
|
{
|
||||||
|
|
|
@ -48,39 +48,32 @@ public:
|
||||||
private:
|
private:
|
||||||
int_type underflow()
|
int_type underflow()
|
||||||
{
|
{
|
||||||
return (position_ == static_cast<std::streampos>(data_.size()))
|
if (position_ == data_.size())
|
||||||
? traits_type::eof() : traits_type::to_int_type(data_[position_]);
|
{
|
||||||
|
return traits_type::eof();
|
||||||
|
}
|
||||||
|
|
||||||
|
return traits_type::to_int_type(static_cast<char>(data_[position_]));
|
||||||
}
|
}
|
||||||
|
|
||||||
int_type uflow()
|
int_type uflow()
|
||||||
{
|
{
|
||||||
if (position_ == static_cast<std::streampos>(data_.size()))
|
if (position_ == data_.size())
|
||||||
{
|
{
|
||||||
return traits_type::eof();
|
return traits_type::eof();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto previous = position_;
|
return traits_type::to_int_type(static_cast<char>(data_[position_++]));
|
||||||
position_ += 1;
|
|
||||||
|
|
||||||
return traits_type::to_int_type(data_[previous]);
|
|
||||||
}
|
|
||||||
|
|
||||||
int_type pbackfail(int_type ch)
|
|
||||||
{
|
|
||||||
if (position_ == std::streampos(0) || (ch != traits_type::eof() && ch != data_[position_ - std::streampos(1)]))
|
|
||||||
{
|
|
||||||
return traits_type::eof();
|
|
||||||
}
|
|
||||||
|
|
||||||
auto old_pos = position_;
|
|
||||||
position_ -= 1;
|
|
||||||
|
|
||||||
return traits_type::to_int_type(data_[position_]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::streamsize showmanyc()
|
std::streamsize showmanyc()
|
||||||
{
|
{
|
||||||
return position_ < data_.size() ? data_.size() - position_ : -1;
|
if (position_ == data_.size())
|
||||||
|
{
|
||||||
|
return static_cast<std::streamsize>(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return static_cast<std::streamsize>(data_.size() - position_);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::streampos seekoff(std::streamoff off,
|
std::streampos seekoff(std::streamoff off,
|
||||||
|
@ -96,23 +89,56 @@ private:
|
||||||
position_ = data_.size();
|
position_ = data_.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
position_ += off;
|
if (off < 0)
|
||||||
|
{
|
||||||
|
if (static_cast<std::size_t>(-off) > position_)
|
||||||
|
{
|
||||||
|
position_ = 0;
|
||||||
|
return static_cast<std::ptrdiff_t>(-1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
position_ -= static_cast<std::size_t>(-off);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (off > 0)
|
||||||
|
{
|
||||||
|
if (static_cast<std::size_t>(off) + position_ > data_.size())
|
||||||
|
{
|
||||||
|
position_ = data_.size();
|
||||||
|
return static_cast<std::ptrdiff_t>(-1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
position_ += static_cast<std::size_t>(off);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (position_ < 0) return -1;
|
return static_cast<std::ptrdiff_t>(position_);
|
||||||
if (position_ > data_.size()) return -1;
|
|
||||||
|
|
||||||
return position_;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::streampos seekpos(std::streampos sp,
|
std::streampos seekpos(std::streampos sp,
|
||||||
std::ios_base::openmode which = std::ios_base::in | std::ios_base::out)
|
std::ios_base::openmode which = std::ios_base::in | std::ios_base::out)
|
||||||
{
|
{
|
||||||
return position_ = sp;
|
if (sp < 0)
|
||||||
|
{
|
||||||
|
position_ = 0;
|
||||||
|
}
|
||||||
|
else if (static_cast<std::size_t>(sp) > data_.size())
|
||||||
|
{
|
||||||
|
position_ = data_.size();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
position_ = static_cast<std::size_t>(sp);
|
||||||
|
}
|
||||||
|
|
||||||
|
return static_cast<std::ptrdiff_t>(position_);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const std::vector<std::uint8_t> &data_;
|
const std::vector<std::uint8_t> &data_;
|
||||||
std::streampos position_;
|
std::size_t position_;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -141,59 +167,91 @@ private:
|
||||||
position_ = data_.size() - 1;
|
position_ = data_.size() - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return traits_type::to_int_type(data_[position_]);
|
return traits_type::to_int_type(static_cast<char>(data_[position_]));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::streamsize xsputn(const char *s, std::streamsize n)
|
std::streamsize xsputn(const char *s, std::streamsize n)
|
||||||
{
|
{
|
||||||
if (data_.empty())
|
if (data_.empty())
|
||||||
{
|
{
|
||||||
data_.resize(n);
|
data_.resize(static_cast<std::size_t>(n));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
auto position_size = data_.size();
|
auto position_size = data_.size();
|
||||||
auto required_size = static_cast<std::size_t>(position_ + static_cast<std::streampos>(n));
|
auto required_size = static_cast<std::size_t>(position_ + static_cast<std::size_t>(n));
|
||||||
data_.resize(std::max(position_size, required_size));
|
data_.resize(std::max(position_size, required_size));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::copy(s, s + n, data_.begin() + position_);
|
std::copy(s, s + n, data_.begin() + static_cast<std::ptrdiff_t>(position_));
|
||||||
position_ += n;
|
position_ += static_cast<std::size_t>(n);
|
||||||
|
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::streampos seekoff(std::streamoff off, std::ios_base::seekdir way,
|
std::streampos seekoff(std::streamoff off,
|
||||||
|
std::ios_base::seekdir way,
|
||||||
std::ios_base::openmode which = std::ios_base::in | std::ios_base::out)
|
std::ios_base::openmode which = std::ios_base::in | std::ios_base::out)
|
||||||
{
|
{
|
||||||
if (way == std::ios_base::beg)
|
if (way == std::ios_base::beg)
|
||||||
{
|
{
|
||||||
position_ = off;
|
position_ = 0;
|
||||||
}
|
|
||||||
else if (way == std::ios_base::cur)
|
|
||||||
{
|
|
||||||
position_ += off;
|
|
||||||
}
|
}
|
||||||
else if (way == std::ios_base::end)
|
else if (way == std::ios_base::end)
|
||||||
{
|
{
|
||||||
position_ = data_.size();
|
position_ = data_.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
return (position_ < 0 || position_ > data_.size())
|
if (off < 0)
|
||||||
? std::streampos(-1) : position_;
|
{
|
||||||
|
if (static_cast<std::size_t>(-off) > position_)
|
||||||
|
{
|
||||||
|
position_ = 0;
|
||||||
|
return static_cast<std::ptrdiff_t>(-1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
position_ -= static_cast<std::size_t>(-off);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (off > 0)
|
||||||
|
{
|
||||||
|
if (static_cast<std::size_t>(off) + position_ > data_.size())
|
||||||
|
{
|
||||||
|
position_ = data_.size();
|
||||||
|
return static_cast<std::ptrdiff_t>(-1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
position_ += static_cast<std::size_t>(off);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return static_cast<std::ptrdiff_t>(position_);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::streampos seekpos(std::streampos sp,
|
std::streampos seekpos(std::streampos sp,
|
||||||
std::ios_base::openmode which = std::ios_base::in | std::ios_base::out)
|
std::ios_base::openmode which = std::ios_base::in | std::ios_base::out)
|
||||||
{
|
{
|
||||||
position_ = sp;
|
if (sp < 0)
|
||||||
return (position_ < 0 || position_ > data_.size())
|
{
|
||||||
? std::streampos(-1) : position_;
|
position_ = 0;
|
||||||
|
}
|
||||||
|
else if (static_cast<std::size_t>(sp) > data_.size())
|
||||||
|
{
|
||||||
|
position_ = data_.size();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
position_ = static_cast<std::size_t>(sp);
|
||||||
|
}
|
||||||
|
|
||||||
|
return static_cast<std::ptrdiff_t>(position_);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<std::uint8_t> &data_;
|
std::vector<std::uint8_t> &data_;
|
||||||
std::streampos position_;
|
std::size_t position_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
|
|
|
@ -99,13 +99,13 @@ xlnt::color read_color(xml::parser &parser)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<xlnt::relationship> read_relationships(const xlnt::path &part, Partio::ZipFileReader &archive)
|
std::vector<xlnt::relationship> read_relationships(const xlnt::path &part, xlnt::detail::ZipFileReader &archive)
|
||||||
{
|
{
|
||||||
std::vector<xlnt::relationship> relationships;
|
std::vector<xlnt::relationship> relationships;
|
||||||
if (!archive.Has_File(part.string())) return relationships;
|
if (!archive.has_file(part.string())) return relationships;
|
||||||
|
|
||||||
std::unique_ptr<std::istream> rels_stream(archive.Get_File(part.string(), true));
|
auto &rels_stream = archive.open(part.string());
|
||||||
xml::parser parser(*rels_stream, part.string());
|
xml::parser parser(rels_stream, part.string());
|
||||||
|
|
||||||
xlnt::uri source(part.string());
|
xlnt::uri source(part.string());
|
||||||
|
|
||||||
|
@ -152,7 +152,7 @@ xlsx_consumer::xlsx_consumer(workbook &target)
|
||||||
|
|
||||||
void xlsx_consumer::read(std::istream &source)
|
void xlsx_consumer::read(std::istream &source)
|
||||||
{
|
{
|
||||||
archive_.reset(new Partio::ZipFileReader(source));
|
archive_.reset(new ZipFileReader(source));
|
||||||
populate_workbook();
|
populate_workbook();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -170,8 +170,8 @@ void xlsx_consumer::populate_workbook()
|
||||||
|
|
||||||
for (const auto &rel : manifest.get_relationships(path("/")))
|
for (const auto &rel : manifest.get_relationships(path("/")))
|
||||||
{
|
{
|
||||||
std::unique_ptr<std::istream> parser_stream(archive_->Get_File(rel.get_target().get_path().string(), true));
|
xml::parser parser(archive_->open(rel.get_target().get_path().string()),
|
||||||
xml::parser parser(*parser_stream, rel.get_target().get_path().string());
|
rel.get_target().get_path().string());
|
||||||
parser_ = &parser;
|
parser_ = &parser;
|
||||||
|
|
||||||
switch (rel.get_type())
|
switch (rel.get_type())
|
||||||
|
@ -235,11 +235,10 @@ void xlsx_consumer::populate_workbook()
|
||||||
for (const auto &rel : manifest.get_relationships(workbook_rel.get_target().get_path()))
|
for (const auto &rel : manifest.get_relationships(workbook_rel.get_target().get_path()))
|
||||||
{
|
{
|
||||||
path part_path(rel.get_source().get_path().parent().append(rel.get_target().get_path()));
|
path part_path(rel.get_source().get_path().parent().append(rel.get_target().get_path()));
|
||||||
std::unique_ptr<std::istream> parser_stream(archive_->Get_File(part_path.string(), true));
|
|
||||||
auto using_namespaces = rel.get_type() == relationship::type::styles;
|
auto using_namespaces = rel.get_type() == relationship::type::styles;
|
||||||
auto receive = xml::parser::receive_default
|
auto receive = xml::parser::receive_default
|
||||||
| (using_namespaces ? xml::parser::receive_namespace_decls : 0);
|
| (using_namespaces ? xml::parser::receive_namespace_decls : 0);
|
||||||
xml::parser parser(*parser_stream, part_path.string(), receive);
|
xml::parser parser(archive_->open(part_path.string()), part_path.string(), receive);
|
||||||
parser_ = &parser;
|
parser_ = &parser;
|
||||||
|
|
||||||
switch (rel.get_type())
|
switch (rel.get_type())
|
||||||
|
@ -268,9 +267,8 @@ void xlsx_consumer::populate_workbook()
|
||||||
for (const auto &rel : manifest.get_relationships(workbook_rel.get_target().get_path()))
|
for (const auto &rel : manifest.get_relationships(workbook_rel.get_target().get_path()))
|
||||||
{
|
{
|
||||||
path part_path(rel.get_source().get_path().parent().append(rel.get_target().get_path()));
|
path part_path(rel.get_source().get_path().parent().append(rel.get_target().get_path()));
|
||||||
std::unique_ptr<std::istream> parser_stream(archive_->Get_File(part_path.string(), true));
|
|
||||||
auto receive = xml::parser::receive_default | xml::parser::receive_namespace_decls;
|
auto receive = xml::parser::receive_default | xml::parser::receive_namespace_decls;
|
||||||
xml::parser parser(*parser_stream, rel.get_target().get_path().string(), receive);
|
xml::parser parser(archive_->open(part_path.string()), rel.get_target().get_path().string(), receive);
|
||||||
parser_ = &parser;
|
parser_ = &parser;
|
||||||
|
|
||||||
switch (rel.get_type())
|
switch (rel.get_type())
|
||||||
|
@ -306,21 +304,17 @@ void xlsx_consumer::read_manifest()
|
||||||
{
|
{
|
||||||
path package_rels_path("_rels/.rels");
|
path package_rels_path("_rels/.rels");
|
||||||
|
|
||||||
if (!archive_->Has_File(package_rels_path.string()))
|
if (!archive_->has_file(package_rels_path.string()))
|
||||||
{
|
{
|
||||||
throw invalid_file("missing package rels");
|
throw invalid_file("missing package rels");
|
||||||
}
|
}
|
||||||
|
|
||||||
auto package_rels = read_relationships(package_rels_path, *archive_);
|
auto package_rels = read_relationships(package_rels_path, *archive_);
|
||||||
|
|
||||||
std::unique_ptr<std::istream> parser_stream(archive_->Get_File("[Content_Types].xml", true));
|
|
||||||
//std::string stream_string((std::istreambuf_iterator<char>(*parser_stream)), std::istreambuf_iterator<char>());
|
|
||||||
xml::parser parser(*parser_stream, "[Content_Types].xml");
|
|
||||||
|
|
||||||
auto &manifest = target_.get_manifest();
|
auto &manifest = target_.get_manifest();
|
||||||
|
|
||||||
static const auto xmlns = constants::get_namespace("content-types");
|
static const auto xmlns = constants::get_namespace("content-types");
|
||||||
|
|
||||||
|
xml::parser parser(archive_->open("[Content_Types].xml"), "[Content_Types].xml");
|
||||||
parser.next_expect(xml::parser::event_type::start_element, xmlns, "Types");
|
parser.next_expect(xml::parser::event_type::start_element, xmlns, "Types");
|
||||||
parser.content(xml::content::complex);
|
parser.content(xml::content::complex);
|
||||||
|
|
||||||
|
@ -355,10 +349,7 @@ void xlsx_consumer::read_manifest()
|
||||||
package_rel.get_id());
|
package_rel.get_id());
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string> file_list;
|
for (const auto &relationship_source_string : archive_->files())
|
||||||
archive_->Get_File_List(file_list);
|
|
||||||
|
|
||||||
for (const auto &relationship_source_string : file_list)
|
|
||||||
{
|
{
|
||||||
auto relationship_source = path(relationship_source_string);
|
auto relationship_source = path(relationship_source_string);
|
||||||
|
|
||||||
|
@ -2013,9 +2004,8 @@ void xlsx_consumer::read_worksheet(const std::string &rel_id)
|
||||||
part_path = std::accumulate(split_part_path.begin(), split_part_path.end(), path(""),
|
part_path = std::accumulate(split_part_path.begin(), split_part_path.end(), path(""),
|
||||||
[](const path &a, const std::string &b) { return a.append(b); });
|
[](const path &a, const std::string &b) { return a.append(b); });
|
||||||
|
|
||||||
std::unique_ptr<std::istream> parser_stream(archive_->Get_File(part_path.string(), true));
|
|
||||||
auto receive = xml::parser::receive_default;
|
auto receive = xml::parser::receive_default;
|
||||||
xml::parser parser(*parser_stream, rel.get_target().get_path().string(), receive);
|
xml::parser parser(archive_->open(part_path.string()), rel.get_target().get_path().string(), receive);
|
||||||
parser_ = &parser;
|
parser_ = &parser;
|
||||||
|
|
||||||
switch (rel.get_type())
|
switch (rel.get_type())
|
||||||
|
|
|
@ -30,10 +30,7 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include <detail/include_libstudxml.hpp>
|
#include <detail/include_libstudxml.hpp>
|
||||||
|
#include <detail/zip.hpp>
|
||||||
namespace Partio {
|
|
||||||
class ZipFileReader;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace xlnt {
|
namespace xlnt {
|
||||||
|
|
||||||
|
@ -44,6 +41,8 @@ class worksheet;
|
||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
|
||||||
|
class ZipFileReader;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Handles writing a workbook into an XLSX file.
|
/// Handles writing a workbook into an XLSX file.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -218,7 +217,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<Partio::ZipFileReader> archive_;
|
std::unique_ptr<ZipFileReader> archive_;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Map of sheet titles to relationship IDs.
|
/// Map of sheet titles to relationship IDs.
|
||||||
|
|
|
@ -33,10 +33,12 @@
|
||||||
namespace xlnt {
|
namespace xlnt {
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
|
||||||
static const std::size_t segment_length = 4096;
|
struct crypto_helper
|
||||||
|
|
||||||
enum class cipher_algorithm
|
|
||||||
{
|
{
|
||||||
|
static const std::size_t segment_length = 4096;
|
||||||
|
|
||||||
|
enum class cipher_algorithm
|
||||||
|
{
|
||||||
aes,
|
aes,
|
||||||
rc2,
|
rc2,
|
||||||
rc4,
|
rc4,
|
||||||
|
@ -44,23 +46,23 @@ enum class cipher_algorithm
|
||||||
desx,
|
desx,
|
||||||
triple_des,
|
triple_des,
|
||||||
triple_des_112
|
triple_des_112
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class cipher_chaining
|
enum class cipher_chaining
|
||||||
{
|
{
|
||||||
ecb, // electronic code book
|
ecb, // electronic code book
|
||||||
cbc, // cipher block chaining
|
cbc, // cipher block chaining
|
||||||
cfb // cipher feedback chaining
|
cfb // cipher feedback chaining
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class cipher_direction
|
enum class cipher_direction
|
||||||
{
|
{
|
||||||
encryption,
|
encryption,
|
||||||
decryption
|
decryption
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class hash_algorithm
|
enum class hash_algorithm
|
||||||
{
|
{
|
||||||
sha1,
|
sha1,
|
||||||
sha256,
|
sha256,
|
||||||
sha384,
|
sha384,
|
||||||
|
@ -71,13 +73,13 @@ enum class hash_algorithm
|
||||||
ripemd128,
|
ripemd128,
|
||||||
ripemd160,
|
ripemd160,
|
||||||
whirlpool
|
whirlpool
|
||||||
};
|
};
|
||||||
|
|
||||||
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> &encrypted,
|
const std::vector<std::uint8_t> &encrypted,
|
||||||
cipher_chaining chaining, cipher_direction direction)
|
cipher_chaining chaining, cipher_direction direction)
|
||||||
{
|
{
|
||||||
std::string cipher_name("AES-");
|
std::string cipher_name("AES-");
|
||||||
cipher_name.append(std::to_string(key.size() * 8));
|
cipher_name.append(std::to_string(key.size() * 8));
|
||||||
cipher_name.append(chaining == cipher_chaining::ecb
|
cipher_name.append(chaining == cipher_chaining::ecb
|
||||||
|
@ -90,48 +92,48 @@ std::vector<std::uint8_t> aes(const std::vector<std::uint8_t> &key,
|
||||||
auto decrypted = pipe.read_all();
|
auto decrypted = pipe.read_all();
|
||||||
|
|
||||||
return std::vector<std::uint8_t>(decrypted.begin(), decrypted.end());
|
return std::vector<std::uint8_t>(decrypted.begin(), decrypted.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::uint8_t> decode_base64(const std::string &encoded)
|
static std::vector<std::uint8_t> decode_base64(const std::string &encoded)
|
||||||
{
|
{
|
||||||
Botan::Pipe pipe(new Botan::Base64_Decoder);
|
Botan::Pipe pipe(new Botan::Base64_Decoder);
|
||||||
pipe.process_msg(encoded);
|
pipe.process_msg(encoded);
|
||||||
auto decoded = pipe.read_all();
|
auto decoded = pipe.read_all();
|
||||||
|
|
||||||
return std::vector<std::uint8_t>(decoded.begin(), decoded.end());
|
return std::vector<std::uint8_t>(decoded.begin(), decoded.end());
|
||||||
};
|
};
|
||||||
|
|
||||||
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)
|
||||||
{
|
{
|
||||||
Botan::Pipe pipe(new Botan::Hash_Filter(
|
Botan::Pipe pipe(new Botan::Hash_Filter(
|
||||||
algorithm == hash_algorithm::sha512 ? "SHA-512" : "SHA-1"));
|
algorithm == hash_algorithm::sha512 ? "SHA-512" : "SHA-1"));
|
||||||
pipe.process_msg(input);
|
pipe.process_msg(input);
|
||||||
auto hash = pipe.read_all();
|
auto hash = pipe.read_all();
|
||||||
|
|
||||||
return std::vector<std::uint8_t>(hash.begin(), hash.end());
|
return std::vector<std::uint8_t>(hash.begin(), hash.end());
|
||||||
};
|
};
|
||||||
|
|
||||||
std::vector<std::uint8_t> get_file(POLE::Storage &storage, const std::string &name)
|
static std::vector<std::uint8_t> get_file(POLE::Storage &storage, const std::string &name)
|
||||||
{
|
{
|
||||||
POLE::Stream stream(&storage, name.c_str());
|
POLE::Stream stream(&storage, name.c_str());
|
||||||
if (stream.fail()) return {};
|
if (stream.fail()) return {};
|
||||||
std::vector<std::uint8_t> bytes(stream.size(), 0);
|
std::vector<std::uint8_t> bytes(stream.size(), 0);
|
||||||
stream.read(bytes.data(), static_cast<unsigned long>(bytes.size()));
|
stream.read(bytes.data(), static_cast<unsigned long>(bytes.size()));
|
||||||
return bytes;
|
return bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
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]);
|
||||||
index += sizeof(T);
|
index += sizeof(T);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct standard_encryption_info
|
struct standard_encryption_info
|
||||||
{
|
{
|
||||||
const std::size_t spin_count = 50000;
|
const std::size_t spin_count = 50000;
|
||||||
std::size_t block_size;
|
std::size_t block_size;
|
||||||
std::size_t key_bits;
|
std::size_t key_bits;
|
||||||
|
@ -144,11 +146,11 @@ struct standard_encryption_info
|
||||||
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;
|
||||||
std::vector<std::uint8_t> encrypted_key_value;
|
std::vector<std::uint8_t> encrypted_key_value;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::vector<std::uint8_t> decrypt_xlsx_standard(const std::vector<std::uint8_t> &encryption_info,
|
static std::vector<std::uint8_t> decrypt_xlsx_standard(const std::vector<std::uint8_t> &encryption_info,
|
||||||
const std::string &password, const std::vector<std::uint8_t> &encrypted_package)
|
const std::string &password, const std::vector<std::uint8_t> &encrypted_package)
|
||||||
{
|
{
|
||||||
std::size_t offset = 0;
|
std::size_t offset = 0;
|
||||||
|
|
||||||
standard_encryption_info info;
|
standard_encryption_info info;
|
||||||
|
@ -191,8 +193,8 @@ std::vector<std::uint8_t> decrypt_xlsx_standard(const std::vector<std::uint8_t>
|
||||||
|
|
||||||
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() + 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() + 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")
|
||||||
|
@ -202,18 +204,18 @@ std::vector<std::uint8_t> decrypt_xlsx_standard(const std::vector<std::uint8_t>
|
||||||
offset += csp_name_length;
|
offset += csp_name_length;
|
||||||
|
|
||||||
const auto salt_size = read_int<std::uint32_t>(offset, encryption_info);
|
const auto salt_size = read_int<std::uint32_t>(offset, encryption_info);
|
||||||
std::vector<std::uint8_t> salt(encryption_info.begin() + offset,
|
std::vector<std::uint8_t> salt(encryption_info.begin() + static_cast<std::ptrdiff_t>(offset),
|
||||||
encryption_info.begin() + offset + salt_size);
|
encryption_info.begin() + static_cast<std::ptrdiff_t>(offset + salt_size));
|
||||||
offset += salt_size;
|
offset += salt_size;
|
||||||
|
|
||||||
static const auto verifier_size = std::size_t(16);
|
static const auto verifier_size = std::size_t(16);
|
||||||
std::vector<std::uint8_t> verifier_hash_input(encryption_info.begin() + offset,
|
std::vector<std::uint8_t> verifier_hash_input(encryption_info.begin() + static_cast<std::ptrdiff_t>(offset),
|
||||||
encryption_info.begin() + offset + verifier_size);
|
encryption_info.begin() + static_cast<std::ptrdiff_t>(offset + verifier_size));
|
||||||
offset += verifier_size;
|
offset += verifier_size;
|
||||||
|
|
||||||
const auto verifier_hash_size = read_int<std::uint32_t>(offset, encryption_info);
|
const auto verifier_hash_size = read_int<std::uint32_t>(offset, encryption_info);
|
||||||
std::vector<std::uint8_t> verifier_hash_value(encryption_info.begin() + offset,
|
std::vector<std::uint8_t> verifier_hash_value(encryption_info.begin() + static_cast<std::ptrdiff_t>(offset),
|
||||||
encryption_info.begin() + offset + 32);
|
encryption_info.begin() + static_cast<std::ptrdiff_t>(offset + verifier_hash_size));
|
||||||
offset += verifier_hash_size;
|
offset += verifier_hash_size;
|
||||||
|
|
||||||
// begin key generation algorithm
|
// begin key generation algorithm
|
||||||
|
@ -268,7 +270,7 @@ std::vector<std::uint8_t> decrypt_xlsx_standard(const std::vector<std::uint8_t>
|
||||||
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() + info.key_bytes);
|
auto key_derived = std::vector<std::uint8_t>(X3.begin(), X3.begin() + static_cast<std::ptrdiff_t>(info.key_bytes));
|
||||||
|
|
||||||
//todo: verify here
|
//todo: verify here
|
||||||
|
|
||||||
|
@ -280,11 +282,10 @@ std::vector<std::uint8_t> decrypt_xlsx_standard(const std::vector<std::uint8_t>
|
||||||
decrypted.resize(decrypted_size);
|
decrypted.resize(decrypted_size);
|
||||||
|
|
||||||
return decrypted;
|
return decrypted;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct agile_encryption_info
|
||||||
struct agile_encryption_info
|
{
|
||||||
{
|
|
||||||
// key data
|
// key data
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
|
@ -319,11 +320,11 @@ struct agile_encryption_info
|
||||||
std::vector<std::uint8_t> verifier_hash_value;
|
std::vector<std::uint8_t> verifier_hash_value;
|
||||||
std::vector<std::uint8_t> encrypted_key_value;
|
std::vector<std::uint8_t> encrypted_key_value;
|
||||||
} key_encryptor;
|
} key_encryptor;
|
||||||
};
|
};
|
||||||
|
|
||||||
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,
|
||||||
const std::string &password, const std::vector<std::uint8_t> &encrypted_package)
|
const std::string &password, const std::vector<std::uint8_t> &encrypted_package)
|
||||||
{
|
{
|
||||||
static const auto xmlns = std::string("http://schemas.microsoft.com/office/2006/encryption");
|
static const auto xmlns = std::string("http://schemas.microsoft.com/office/2006/encryption");
|
||||||
static const auto xmlns_p = std::string("http://schemas.microsoft.com/office/2006/keyEncryptor/password");
|
static const auto xmlns_p = std::string("http://schemas.microsoft.com/office/2006/keyEncryptor/password");
|
||||||
static const auto xmlns_c = std::string("http://schemas.microsoft.com/office/2006/keyEncryptor/certificate");
|
static const auto xmlns_c = std::string("http://schemas.microsoft.com/office/2006/keyEncryptor/certificate");
|
||||||
|
@ -496,8 +497,10 @@ std::vector<std::uint8_t> decrypt_xlsx_agile(const std::vector<std::uint8_t> &en
|
||||||
iv.resize(16);
|
iv.resize(16);
|
||||||
|
|
||||||
auto decrypted_segment = aes(key, iv, std::vector<std::uint8_t>(
|
auto decrypted_segment = aes(key, iv, std::vector<std::uint8_t>(
|
||||||
encrypted_package.begin() + i, encrypted_package.begin() + i + segment_length),
|
encrypted_package.begin() + static_cast<std::ptrdiff_t>(i),
|
||||||
|
encrypted_package.begin() + static_cast<std::ptrdiff_t>(i) + segment_length),
|
||||||
cipher_chaining::cbc, cipher_direction::decryption);
|
cipher_chaining::cbc, cipher_direction::decryption);
|
||||||
|
|
||||||
decrypted_package.insert(decrypted_package.end(),
|
decrypted_package.insert(decrypted_package.end(),
|
||||||
decrypted_segment.begin(), decrypted_segment.end());
|
decrypted_segment.begin(), decrypted_segment.end());
|
||||||
|
|
||||||
|
@ -507,10 +510,10 @@ std::vector<std::uint8_t> decrypt_xlsx_agile(const std::vector<std::uint8_t> &en
|
||||||
decrypted_package.resize(total_size);
|
decrypted_package.resize(total_size);
|
||||||
|
|
||||||
return decrypted_package;
|
return decrypted_package;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::uint8_t> decrypt_xlsx(const std::vector<std::uint8_t> &bytes, const std::string &password)
|
static std::vector<std::uint8_t> decrypt_xlsx(const std::vector<std::uint8_t> &bytes, const std::string &password)
|
||||||
{
|
{
|
||||||
if (bytes.empty())
|
if (bytes.empty())
|
||||||
{
|
{
|
||||||
throw xlnt::exception("empty file");
|
throw xlnt::exception("empty file");
|
||||||
|
@ -534,7 +537,8 @@ std::vector<std::uint8_t> decrypt_xlsx(const std::vector<std::uint8_t> &bytes, c
|
||||||
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.begin() + index);
|
encryption_info.erase(encryption_info.begin(),
|
||||||
|
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)
|
||||||
|
@ -571,13 +575,14 @@ std::vector<std::uint8_t> decrypt_xlsx(const std::vector<std::uint8_t> &bytes, c
|
||||||
}
|
}
|
||||||
|
|
||||||
return decrypt_xlsx_standard(encryption_info, password, encrypted_package);
|
return decrypt_xlsx_standard(encryption_info, password, encrypted_package);
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
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 = 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);
|
||||||
|
|
|
@ -24,10 +24,12 @@
|
||||||
#include <numeric> // for std::accumulate
|
#include <numeric> // for std::accumulate
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include <detail/custom_value_traits.hpp>
|
|
||||||
#include <detail/xlsx_producer.hpp>
|
|
||||||
#include <detail/constants.hpp>
|
#include <detail/constants.hpp>
|
||||||
|
#include <detail/custom_value_traits.hpp>
|
||||||
|
#include <detail/vector_streambuf.hpp>
|
||||||
#include <detail/workbook_impl.hpp>
|
#include <detail/workbook_impl.hpp>
|
||||||
|
#include <detail/xlsx_producer.hpp>
|
||||||
|
#include <detail/zip.hpp>
|
||||||
#include <xlnt/cell/cell.hpp>
|
#include <xlnt/cell/cell.hpp>
|
||||||
#include <xlnt/utils/path.hpp>
|
#include <xlnt/utils/path.hpp>
|
||||||
#include <xlnt/packaging/manifest.hpp>
|
#include <xlnt/packaging/manifest.hpp>
|
||||||
|
@ -84,7 +86,7 @@ xlsx_producer::xlsx_producer(const workbook &target) : source_(target)
|
||||||
|
|
||||||
void xlsx_producer::write(std::ostream &destination)
|
void xlsx_producer::write(std::ostream &destination)
|
||||||
{
|
{
|
||||||
Partio::ZipFileWriter archive(destination);
|
ZipFileWriter archive(destination);
|
||||||
archive_ = &archive;
|
archive_ = &archive;
|
||||||
populate_archive();
|
populate_archive();
|
||||||
}
|
}
|
||||||
|
@ -100,6 +102,13 @@ void xlsx_producer::populate_archive()
|
||||||
|
|
||||||
for (auto &rel : root_rels)
|
for (auto &rel : root_rels)
|
||||||
{
|
{
|
||||||
|
// thumbnail is binary content so we don't want to open an xml serializer stream
|
||||||
|
if (rel.get_type() == relationship::type::thumbnail)
|
||||||
|
{
|
||||||
|
write_thumbnail(rel);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
begin_part(rel.get_target().get_path());
|
begin_part(rel.get_target().get_path());
|
||||||
|
|
||||||
switch (rel.get_type())
|
switch (rel.get_type())
|
||||||
|
@ -120,10 +129,6 @@ void xlsx_producer::populate_archive()
|
||||||
write_workbook(rel);
|
write_workbook(rel);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case relationship::type::thumbnail:
|
|
||||||
write_thumbnail(rel);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -154,7 +159,7 @@ void xlsx_producer::begin_part(const path &part)
|
||||||
{
|
{
|
||||||
end_part();
|
end_part();
|
||||||
|
|
||||||
current_part_stream_.reset(archive_->Add_File(part.string(), true));
|
current_part_stream_.reset(archive_->open(part.string()));
|
||||||
current_part_serializer_.reset(new xml::serializer(*current_part_stream_, part.string()));
|
current_part_serializer_.reset(new xml::serializer(*current_part_stream_, part.string()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2498,11 +2503,12 @@ void xlsx_producer::write_unknown_relationships()
|
||||||
|
|
||||||
void xlsx_producer::write_thumbnail(const relationship &rel)
|
void xlsx_producer::write_thumbnail(const relationship &rel)
|
||||||
{
|
{
|
||||||
|
end_part();
|
||||||
|
|
||||||
const auto &thumbnail = source_.get_thumbnail();
|
const auto &thumbnail = source_.get_thumbnail();
|
||||||
std::unique_ptr<std::ostream> thumbnail_stream(
|
current_part_stream_.reset(archive_->open(rel.get_target().get_path().string()));
|
||||||
archive_->Add_File(rel.get_target().get_path().string(), true));
|
vector_istreambuf thumbnail_buffer(thumbnail);
|
||||||
std::for_each(thumbnail.begin(), thumbnail.end(),
|
*current_part_stream_ << &thumbnail_buffer;
|
||||||
[&thumbnail_stream](std::uint8_t b) { *thumbnail_stream << b; });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
xml::serializer &xlsx_producer::serializer()
|
xml::serializer &xlsx_producer::serializer()
|
||||||
|
|
|
@ -28,11 +28,6 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include <detail/include_libstudxml.hpp>
|
#include <detail/include_libstudxml.hpp>
|
||||||
#include <detail/zip.hpp>
|
|
||||||
|
|
||||||
namespace Partio {
|
|
||||||
class ZipFileWriter;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace xml {
|
namespace xml {
|
||||||
class serializer;
|
class serializer;
|
||||||
|
@ -49,6 +44,8 @@ class worksheet;
|
||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
|
||||||
|
class ZipFileWriter;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Handles writing a workbook into an XLSX file.
|
/// Handles writing a workbook into an XLSX file.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -138,7 +135,7 @@ private:
|
||||||
/// </summary>
|
/// </summary>
|
||||||
const workbook &source_;
|
const workbook &source_;
|
||||||
|
|
||||||
Partio::ZipFileWriter *archive_;
|
ZipFileWriter *archive_;
|
||||||
std::unique_ptr<std::ostream> current_part_stream_;
|
std::unique_ptr<std::ostream> current_part_stream_;
|
||||||
std::unique_ptr<xml::serializer> current_part_serializer_;
|
std::unique_ptr<xml::serializer> current_part_serializer_;
|
||||||
};
|
};
|
||||||
|
|
|
@ -33,10 +33,6 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
extern "C"{
|
|
||||||
#include <zlib.h>
|
|
||||||
}
|
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
@ -46,123 +42,129 @@ extern "C"{
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
#include <zlib.h>
|
||||||
|
|
||||||
#include <detail/zip.hpp>
|
#include <detail/zip.hpp>
|
||||||
|
|
||||||
namespace Partio{
|
namespace xlnt {
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
inline void Swap_Endianity(T& x)
|
inline T read_int(std::istream &stream)
|
||||||
{
|
{
|
||||||
assert(sizeof(T)<=8);
|
T value;
|
||||||
if(sizeof(T)>1) {
|
stream.read(reinterpret_cast<char *>(&value), sizeof(T));
|
||||||
T old=x;
|
return value;
|
||||||
for(unsigned int k=1;k<=sizeof(T);k++) ((char*)&x)[k-1]=((char*)&old)[sizeof(T)-k];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
inline void Read_Primitive(std::istream& stream,T& x)
|
inline void write_int(std::ostream &stream, T value)
|
||||||
{
|
{
|
||||||
stream.read(&(char&)x,sizeof(T));
|
stream.write(reinterpret_cast<char *>(&value), sizeof(T));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class T>
|
struct zip_file_header
|
||||||
inline void Write_Primitive(std::ostream& stream,const T& x)
|
|
||||||
{
|
{
|
||||||
stream.write(&(char&)x,sizeof(T));
|
std::uint16_t version = 20;
|
||||||
}
|
std::uint16_t flags = 0;
|
||||||
|
std::uint16_t compression_type = 8;
|
||||||
//#####################################################################
|
std::uint16_t stamp_date,stamp_time = 0;
|
||||||
// class ZipFileHeader
|
std::uint32_t crc = 0;
|
||||||
//#####################################################################
|
std::uint32_t compressed_size = 0;
|
||||||
struct ZipFileHeader
|
std::uint32_t uncompressed_size = 0;
|
||||||
{
|
|
||||||
unsigned short version;
|
|
||||||
unsigned short flags;
|
|
||||||
unsigned short compression_type;
|
|
||||||
unsigned short stamp_date,stamp_time;
|
|
||||||
unsigned int crc;
|
|
||||||
unsigned int compressed_size,uncompressed_size;
|
|
||||||
std::string filename;
|
std::string filename;
|
||||||
unsigned int header_offset; // local header offset
|
std::string comment;
|
||||||
|
std::vector<std::uint8_t> extra;
|
||||||
|
std::uint32_t header_offset = 0; // local header offset
|
||||||
|
|
||||||
ZipFileHeader()
|
zip_file_header()
|
||||||
{}
|
{
|
||||||
|
}
|
||||||
|
|
||||||
ZipFileHeader(const std::string& filename_input)
|
bool read(std::istream& istream,const bool global)
|
||||||
:version(20),flags(0),compression_type(8),stamp_date(0),stamp_time(0),crc(0),
|
{
|
||||||
compressed_size(0),uncompressed_size(0),filename(filename_input),header_offset(0)
|
auto sig = read_int<std::uint32_t>(istream);
|
||||||
{}
|
|
||||||
|
|
||||||
bool Read(std::istream& istream,const bool global)
|
|
||||||
{unsigned int sig;
|
|
||||||
unsigned short version,flags;
|
|
||||||
// read and check for local/global magic
|
// read and check for local/global magic
|
||||||
if(global){
|
if(global)
|
||||||
Read_Primitive(istream,sig);
|
{
|
||||||
if(sig!=0x02014b50){std::cerr<<"Did not find global header signature"<<std::endl;return false;}
|
if(sig!=0x02014b50)
|
||||||
Read_Primitive(istream,version);}
|
{
|
||||||
else{
|
std::cerr<<"Did not find global header signature"<<std::endl;
|
||||||
Read_Primitive(istream,sig);
|
return false;
|
||||||
if(sig!=0x04034b50){std::cerr<<"Did not find local header signature"<<std::endl;return false;}}
|
}
|
||||||
|
|
||||||
|
version = read_int<std::uint16_t>(istream);
|
||||||
|
}
|
||||||
|
else if(sig!=0x04034b50)
|
||||||
|
{
|
||||||
|
std::cerr<<"Did not find local header signature"<<std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// Read rest of header
|
// Read rest of header
|
||||||
Read_Primitive(istream,version);
|
version = read_int<std::uint16_t>(istream);
|
||||||
Read_Primitive(istream,flags);
|
flags = read_int<std::uint16_t>(istream);
|
||||||
Read_Primitive(istream,compression_type);
|
compression_type = read_int<std::uint16_t>(istream);
|
||||||
Read_Primitive(istream,stamp_date);
|
stamp_date = read_int<std::uint16_t>(istream);
|
||||||
Read_Primitive(istream,stamp_time);
|
stamp_time = read_int<std::uint16_t>(istream);
|
||||||
Read_Primitive(istream,crc);
|
crc = read_int<std::uint32_t>(istream);
|
||||||
Read_Primitive(istream,compressed_size);
|
compressed_size = read_int<std::uint32_t>(istream);
|
||||||
Read_Primitive(istream,uncompressed_size);
|
uncompressed_size = read_int<std::uint32_t>(istream);
|
||||||
unsigned short filename_length,extra_length;
|
|
||||||
Read_Primitive(istream,filename_length);
|
auto filename_length = read_int<std::uint16_t>(istream);
|
||||||
Read_Primitive(istream,extra_length);
|
auto extra_length = read_int<std::uint16_t>(istream);
|
||||||
unsigned short comment_length=0;
|
|
||||||
if(global){
|
std::uint16_t comment_length = 0;
|
||||||
Read_Primitive(istream,comment_length); // filecomment
|
|
||||||
unsigned short disk_number_start,int_file_attrib;
|
if(global)
|
||||||
unsigned int ext_file_attrib;
|
{
|
||||||
Read_Primitive(istream,disk_number_start); // disk# start
|
comment_length = read_int<std::uint16_t>(istream);
|
||||||
Read_Primitive(istream,int_file_attrib); // internal file
|
/*std::uint16_t disk_number_start = */read_int<std::uint16_t>(istream);
|
||||||
Read_Primitive(istream,ext_file_attrib); // ext final
|
/*std::uint16_t int_file_attrib = */read_int<std::uint16_t>(istream);
|
||||||
Read_Primitive(istream,header_offset);} // rel offset
|
/*std::uint32_t ext_file_attrib = */read_int<std::uint32_t>(istream);
|
||||||
char* buf=new char[std::max(comment_length,std::max(filename_length,extra_length))+1];
|
header_offset = read_int<std::uint32_t>(istream);
|
||||||
istream.read(buf,filename_length);
|
}
|
||||||
buf[filename_length]=0;
|
|
||||||
filename=std::string(buf, buf + filename_length);
|
filename.resize(filename_length, '\0');
|
||||||
istream.read(buf,extra_length);
|
istream.read(&filename[0], filename_length);
|
||||||
if(global) istream.read(buf,comment_length);
|
|
||||||
delete [] buf;
|
extra.resize(extra_length, 0);
|
||||||
return true;}
|
istream.read(reinterpret_cast<char *>(extra.data()), extra_length);
|
||||||
|
|
||||||
|
if (global)
|
||||||
|
{
|
||||||
|
comment.resize(comment_length, '\0');
|
||||||
|
istream.read(&comment[0], comment_length);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void Write(std::ostream& ostream,const bool global) const
|
void Write(std::ostream& ostream,const bool global) const
|
||||||
{if(global){
|
{if(global){
|
||||||
Write_Primitive(ostream,(unsigned int)0x02014b50); // header sig
|
write_int(ostream,(unsigned int)0x02014b50); // header sig
|
||||||
Write_Primitive(ostream,(unsigned short)00);} // version made by
|
write_int(ostream,(unsigned short)00);} // version made by
|
||||||
else Write_Primitive(ostream,(unsigned int)0x04034b50);
|
else write_int(ostream,(unsigned int)0x04034b50);
|
||||||
Write_Primitive(ostream,version);
|
write_int(ostream,version);
|
||||||
Write_Primitive(ostream,flags);
|
write_int(ostream,flags);
|
||||||
Write_Primitive(ostream,compression_type);
|
write_int(ostream,compression_type);
|
||||||
Write_Primitive(ostream,stamp_date);
|
write_int(ostream,stamp_date);
|
||||||
Write_Primitive(ostream,stamp_time);
|
write_int(ostream,stamp_time);
|
||||||
Write_Primitive(ostream,crc);
|
write_int(ostream,crc);
|
||||||
Write_Primitive(ostream,compressed_size);
|
write_int(ostream,compressed_size);
|
||||||
Write_Primitive(ostream,uncompressed_size);
|
write_int(ostream,uncompressed_size);
|
||||||
Write_Primitive(ostream,(unsigned short)filename.length());
|
write_int(ostream,(unsigned short)filename.length());
|
||||||
Write_Primitive(ostream,(unsigned short)0); // extra lengthx
|
write_int(ostream,(unsigned short)0); // extra lengthx
|
||||||
if(global){
|
if(global){
|
||||||
Write_Primitive(ostream,(unsigned short)0); // filecomment
|
write_int(ostream,(unsigned short)0); // filecomment
|
||||||
Write_Primitive(ostream,(unsigned short)0); // disk# start
|
write_int(ostream,(unsigned short)0); // disk# start
|
||||||
Write_Primitive(ostream,(unsigned short)0); // internal file
|
write_int(ostream,(unsigned short)0); // internal file
|
||||||
Write_Primitive(ostream,(unsigned int)0); // ext final
|
write_int(ostream,(unsigned int)0); // ext final
|
||||||
Write_Primitive(ostream,(unsigned int)header_offset);} // rel offset
|
write_int(ostream,(unsigned int)header_offset);} // rel offset
|
||||||
for(unsigned int i=0;i<filename.length();i++) Write_Primitive(ostream,filename.c_str()[i]);}
|
for(unsigned int i=0;i<filename.length();i++) write_int(ostream,filename.c_str()[i]);}
|
||||||
//#####################################################################
|
|
||||||
};
|
};
|
||||||
|
|
||||||
//#####################################################################
|
|
||||||
// class ZipStreambufDecompress
|
|
||||||
//#####################################################################
|
|
||||||
class ZipStreambufDecompress:public std::streambuf
|
class ZipStreambufDecompress:public std::streambuf
|
||||||
{
|
{
|
||||||
static const unsigned int buffer_size=512;
|
static const unsigned int buffer_size=512;
|
||||||
|
@ -170,23 +172,23 @@ class ZipStreambufDecompress:public std::streambuf
|
||||||
|
|
||||||
z_stream strm;
|
z_stream strm;
|
||||||
unsigned char in[buffer_size],out[buffer_size];
|
unsigned char in[buffer_size],out[buffer_size];
|
||||||
ZipFileHeader header;
|
zip_file_header header;
|
||||||
int total_read,total_uncompressed;
|
int total_read,total_uncompressed;
|
||||||
bool own_istream;
|
//bool own_istream;
|
||||||
bool valid;
|
bool valid;
|
||||||
bool compressed_data;
|
bool compressed_data;
|
||||||
|
|
||||||
static const unsigned short DEFLATE=8;
|
static const unsigned short DEFLATE=8;
|
||||||
static const unsigned short UNCOMPRESSED=0;
|
static const unsigned short UNCOMPRESSED=0;
|
||||||
public:
|
public:
|
||||||
ZipStreambufDecompress(std::istream& stream,ZipFileHeader central_header)
|
ZipStreambufDecompress(std::istream& stream,zip_file_header central_header)
|
||||||
:istream(stream),total_read(0),total_uncompressed(0),valid(true),header(central_header)
|
:istream(stream),header(central_header),total_read(0),total_uncompressed(0),valid(true)
|
||||||
{
|
{
|
||||||
strm.zalloc=Z_NULL;strm.zfree=Z_NULL;strm.opaque=Z_NULL;strm.avail_in=0;strm.next_in=Z_NULL;
|
strm.zalloc=Z_NULL;strm.zfree=Z_NULL;strm.opaque=Z_NULL;strm.avail_in=0;strm.next_in=Z_NULL;
|
||||||
setg((char*)in,(char*)in,(char*)in);
|
setg((char*)in,(char*)in,(char*)in);
|
||||||
setp(0,0);
|
setp(0,0);
|
||||||
// skip the header
|
// skip the header
|
||||||
valid=header.Read(istream,false);
|
valid=header.read(istream,false);
|
||||||
if(header.compression_type==DEFLATE) compressed_data=true;
|
if(header.compression_type==DEFLATE) compressed_data=true;
|
||||||
else if(header.compression_type==UNCOMPRESSED) compressed_data=false;
|
else if(header.compression_type==UNCOMPRESSED) compressed_data=false;
|
||||||
else{
|
else{
|
||||||
|
@ -246,13 +248,8 @@ public:
|
||||||
|
|
||||||
virtual int overflow(int c=EOF)
|
virtual int overflow(int c=EOF)
|
||||||
{assert(false);return EOF;}
|
{assert(false);return EOF;}
|
||||||
|
|
||||||
//#####################################################################
|
|
||||||
};
|
};
|
||||||
|
|
||||||
//#####################################################################
|
|
||||||
// class ZipStreambufCompress
|
|
||||||
//#####################################################################
|
|
||||||
class ZipStreambufCompress:public std::streambuf
|
class ZipStreambufCompress:public std::streambuf
|
||||||
{
|
{
|
||||||
static const int buffer_size=512;
|
static const int buffer_size=512;
|
||||||
|
@ -261,16 +258,15 @@ class ZipStreambufCompress:public std::streambuf
|
||||||
z_stream strm;
|
z_stream strm;
|
||||||
unsigned char in[buffer_size],out[buffer_size];
|
unsigned char in[buffer_size],out[buffer_size];
|
||||||
|
|
||||||
ZipFileHeader* header;
|
zip_file_header* header;
|
||||||
unsigned int header_offset;
|
|
||||||
unsigned int uncompressed_size;
|
unsigned int uncompressed_size;
|
||||||
unsigned int crc;
|
unsigned int crc;
|
||||||
|
|
||||||
bool valid;
|
bool valid;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ZipStreambufCompress(ZipFileHeader* header,std::ostream& stream)
|
ZipStreambufCompress(zip_file_header* central_header,std::ostream& stream)
|
||||||
:ostream(stream),header(header),valid(true)
|
:ostream(stream),header(central_header),valid(true)
|
||||||
{
|
{
|
||||||
strm.zalloc=Z_NULL;strm.zfree=Z_NULL;strm.opaque=Z_NULL;
|
strm.zalloc=Z_NULL;strm.zfree=Z_NULL;strm.opaque=Z_NULL;
|
||||||
int ret=deflateInit2(&strm,Z_DEFAULT_COMPRESSION,Z_DEFLATED,-MAX_WBITS,8,Z_DEFAULT_STRATEGY);
|
int ret=deflateInit2(&strm,Z_DEFAULT_COMPRESSION,Z_DEFLATED,-MAX_WBITS,8,Z_DEFAULT_STRATEGY);
|
||||||
|
@ -293,7 +289,7 @@ public:
|
||||||
ostream.seekp(header->header_offset);
|
ostream.seekp(header->header_offset);
|
||||||
header->Write(ostream,false);
|
header->Write(ostream,false);
|
||||||
ostream.seekp(final_position);}
|
ostream.seekp(final_position);}
|
||||||
else{Write_Primitive(ostream,crc);Write_Primitive(ostream,uncompressed_size);}}
|
else{write_int(ostream,crc);write_int(ostream,uncompressed_size);}}
|
||||||
if(!header) delete &ostream;}
|
if(!header) delete &ostream;}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -329,174 +325,189 @@ protected:
|
||||||
{if(c!=EOF){*pptr()=c;pbump(1);}
|
{if(c!=EOF){*pptr()=c;pbump(1);}
|
||||||
if(process(false)==EOF) return EOF;
|
if(process(false)==EOF) return EOF;
|
||||||
return c;}
|
return c;}
|
||||||
|
|
||||||
//#####################################################################
|
|
||||||
};
|
};
|
||||||
//#####################################################################
|
|
||||||
// Class ZIP_FILE_ISTREAM
|
|
||||||
//#####################################################################
|
|
||||||
// Class needed because istream cannot own its streambuf
|
|
||||||
class ZIP_FILE_ISTREAM:public std::istream
|
class ZIP_FILE_ISTREAM:public std::istream
|
||||||
{
|
{
|
||||||
ZipStreambufDecompress buf;
|
ZipStreambufDecompress buf;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ZIP_FILE_ISTREAM(std::istream& istream,ZipFileHeader header)
|
ZIP_FILE_ISTREAM(std::istream& istream,zip_file_header header)
|
||||||
:std::istream(&buf),buf(istream,header)
|
:std::istream(&buf),buf(istream,header)
|
||||||
{}
|
{
|
||||||
|
}
|
||||||
|
|
||||||
virtual ~ZIP_FILE_ISTREAM()
|
virtual ~ZIP_FILE_ISTREAM()
|
||||||
{}
|
{
|
||||||
|
}
|
||||||
//#####################################################################
|
|
||||||
};
|
};
|
||||||
//#####################################################################
|
|
||||||
// Class ZIP_FILE_OSTREAM
|
|
||||||
//#####################################################################
|
|
||||||
// Class needed because ostream cannot own its streambuf
|
|
||||||
class ZIP_FILE_OSTREAM:public std::ostream
|
class ZIP_FILE_OSTREAM:public std::ostream
|
||||||
{
|
{
|
||||||
ZipStreambufCompress buf;
|
ZipStreambufCompress buf;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ZIP_FILE_OSTREAM(ZipFileHeader* header,std::ostream& ostream)
|
ZIP_FILE_OSTREAM(zip_file_header* header,std::ostream& ostream)
|
||||||
:std::ostream(&buf),buf(header,ostream)
|
:std::ostream(&buf),buf(header,ostream)
|
||||||
{}
|
{
|
||||||
|
}
|
||||||
|
|
||||||
virtual ~ZIP_FILE_OSTREAM()
|
virtual ~ZIP_FILE_OSTREAM()
|
||||||
{}
|
{
|
||||||
|
}
|
||||||
//#####################################################################
|
|
||||||
};
|
};
|
||||||
//#####################################################################
|
|
||||||
// Function ZipFileWriter
|
ZipFileWriter::ZipFileWriter(std::ostream& stream) : target_stream_(stream)
|
||||||
//#####################################################################
|
|
||||||
ZipFileWriter::
|
|
||||||
ZipFileWriter(std::ostream& stream) : ostream(stream)
|
|
||||||
{
|
{
|
||||||
if(!ostream) throw std::runtime_error("ZIP: Invalid file handle");
|
if(!target_stream_) throw std::runtime_error("ZIP: Invalid file handle");
|
||||||
}
|
}
|
||||||
//#####################################################################
|
|
||||||
// Function ZipFileWriter
|
ZipFileWriter::~ZipFileWriter()
|
||||||
//#####################################################################
|
|
||||||
ZipFileWriter::
|
|
||||||
~ZipFileWriter()
|
|
||||||
{
|
{
|
||||||
// Write all file headers
|
// Write all file headers
|
||||||
std::ios::streampos final_position=ostream.tellp();
|
std::ios::streampos final_position=target_stream_.tellp();
|
||||||
for(unsigned int i=0;i<files.size();i++){files[i]->Write(ostream,true);delete files[i];}
|
for(unsigned int i=0;i<file_headers_.size();i++)
|
||||||
std::ios::streampos central_end=ostream.tellp();
|
{
|
||||||
|
file_headers_[i].Write(target_stream_,true);
|
||||||
|
}
|
||||||
|
std::ios::streampos central_end=target_stream_.tellp();
|
||||||
// Write end of central
|
// Write end of central
|
||||||
Write_Primitive(ostream,(unsigned int)0x06054b50); // end of central
|
write_int(target_stream_,(unsigned int)0x06054b50); // end of central
|
||||||
Write_Primitive(ostream,(unsigned short)0); // this disk number
|
write_int(target_stream_,(unsigned short)0); // this disk number
|
||||||
Write_Primitive(ostream,(unsigned short)0); // this disk number
|
write_int(target_stream_,(unsigned short)0); // this disk number
|
||||||
Write_Primitive(ostream,(unsigned short)files.size()); // one entry in center in this disk
|
write_int(target_stream_,(unsigned short)file_headers_.size()); // one entry in center in this disk
|
||||||
Write_Primitive(ostream,(unsigned short)files.size()); // one entry in center
|
write_int(target_stream_,(unsigned short)file_headers_.size()); // one entry in center
|
||||||
Write_Primitive(ostream,(unsigned int)(central_end-final_position)); // size of header
|
write_int(target_stream_,(unsigned int)(central_end - final_position)); // size of header
|
||||||
Write_Primitive(ostream,(unsigned int)final_position); // offset to header
|
write_int(target_stream_,(unsigned int)final_position); // offset to header
|
||||||
Write_Primitive(ostream,(unsigned short)0); // zip comment
|
write_int(target_stream_,(unsigned short)0); // zip comment
|
||||||
}
|
}
|
||||||
//#####################################################################
|
|
||||||
// Function ZipFileWriter
|
std::ostream* ZipFileWriter::open(const std::string& filename)
|
||||||
//#####################################################################
|
|
||||||
std::ostream* ZipFileWriter::
|
|
||||||
Add_File(const std::string& filename,const bool binary)
|
|
||||||
{
|
{
|
||||||
files.push_back(new ZipFileHeader(filename));
|
zip_file_header header;
|
||||||
return new ZIP_FILE_OSTREAM(files.back(),ostream);
|
header.filename = filename;
|
||||||
|
file_headers_.push_back(header);
|
||||||
|
return new ZIP_FILE_OSTREAM(&file_headers_.back(),target_stream_);
|
||||||
}
|
}
|
||||||
//#####################################################################
|
|
||||||
// Function ZipFileReader
|
ZipFileReader::ZipFileReader(std::istream &stream) : source_stream_(stream)
|
||||||
//#####################################################################
|
|
||||||
ZipFileReader::
|
|
||||||
ZipFileReader(std::istream &stream) : istream(stream)
|
|
||||||
{
|
{
|
||||||
if(!istream) throw std::runtime_error("ZIP: Invalid file handle");
|
if(!stream)
|
||||||
Find_And_Read_Central_Header();
|
{
|
||||||
|
throw std::runtime_error("ZIP: Invalid file handle");
|
||||||
|
}
|
||||||
|
|
||||||
|
read_central_header();
|
||||||
}
|
}
|
||||||
//#####################################################################
|
|
||||||
// Function ZipFileReader
|
ZipFileReader::~ZipFileReader()
|
||||||
//#####################################################################
|
|
||||||
ZipFileReader::
|
|
||||||
~ZipFileReader()
|
|
||||||
{
|
{
|
||||||
std::map<std::string,ZipFileHeader*>::iterator i=filename_to_header.begin();
|
|
||||||
for(;i!=filename_to_header.end();++i)
|
|
||||||
delete i->second;
|
|
||||||
}
|
}
|
||||||
//#####################################################################
|
|
||||||
// Function Find_And_Read_Central_Header
|
bool ZipFileReader::read_central_header()
|
||||||
//#####################################################################
|
|
||||||
bool ZipFileReader::
|
|
||||||
Find_And_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...
|
||||||
istream.seekg(0,std::ios_base::end);
|
source_stream_.seekg(0,std::ios_base::end);
|
||||||
std::ios::streampos end_position=istream.tellg();
|
std::ios::streampos end_position=source_stream_.tellg();
|
||||||
unsigned int max_comment_size=0xffff; // max size of header
|
|
||||||
unsigned int read_size_before_comment=22;
|
auto max_comment_size = std::uint32_t(0xffff); // max size of header
|
||||||
|
auto read_size_before_comment = std::uint32_t(22);
|
||||||
|
|
||||||
std::ios::streamoff read_start=max_comment_size+read_size_before_comment;
|
std::ios::streamoff read_start=max_comment_size+read_size_before_comment;
|
||||||
|
|
||||||
if(read_start>end_position) read_start=end_position;
|
if(read_start>end_position) read_start=end_position;
|
||||||
istream.seekg(end_position-read_start);
|
source_stream_.seekg(end_position-read_start);
|
||||||
char *buf=new char[read_start];
|
std::vector<char> buf(static_cast<std::size_t>(read_start), '\0');
|
||||||
if(read_start<=0){std::cerr<<"ZIP: Invalid read buffer size"<<std::endl;return false;}
|
if(read_start<=0){std::cerr<<"ZIP: Invalid read buffer size"<<std::endl;return false;}
|
||||||
istream.read(buf,read_start);
|
source_stream_.read(buf.data(), read_start);
|
||||||
int found=-1;
|
|
||||||
for(unsigned int i=0;i<read_start-3;i++){
|
auto found_header = false;
|
||||||
if(buf[i]==0x50 && buf[i+1]==0x4b && buf[i+2]==0x05 && buf[i+3]==0x06){found=i;break;}}
|
std::size_t header_index = 0;
|
||||||
delete [] buf;
|
|
||||||
if(found==-1){std::cerr<<"ZIP: Failed to find zip header"<<std::endl;return false;}
|
for(std::size_t i = 0; i < read_start - 3; ++i)
|
||||||
|
{
|
||||||
|
if(buf[i] == 0x50 && buf[i + 1] == 0x4b && buf[i + 2] == 0x05 && buf[i + 3] == 0x06)
|
||||||
|
{
|
||||||
|
found_header = true;
|
||||||
|
header_index = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!found_header)
|
||||||
|
{
|
||||||
|
std::cerr<<"ZIP: Failed to find zip header"<<std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// seek to end of central header and read
|
// seek to end of central header and read
|
||||||
istream.seekg(end_position-(read_start-found));
|
source_stream_.seekg(end_position - (read_start - static_cast<std::ptrdiff_t>(header_index)));
|
||||||
unsigned int word;
|
|
||||||
unsigned short disk_number1,disk_number2,num_files,num_files_this_disk;
|
/*auto word = */read_int<std::uint32_t>(source_stream_);
|
||||||
Read_Primitive(istream,word); // end of central
|
auto disk_number1 = read_int<std::uint16_t>(source_stream_);
|
||||||
Read_Primitive(istream,disk_number1); // this disk number
|
auto disk_number2 = read_int<std::uint16_t>(source_stream_);
|
||||||
Read_Primitive(istream,disk_number2); // this disk number
|
|
||||||
if(disk_number1!=disk_number2 || disk_number1!=0){
|
if(disk_number1 != disk_number2 || disk_number1 != 0)
|
||||||
std::cerr<<"ZIP: multiple disk zip files are not supported"<<std::endl;return false;}
|
{
|
||||||
Read_Primitive(istream,num_files); // one entry in center in this disk
|
std::cerr<<"ZIP: multiple disk zip files are not supported"<<std::endl;
|
||||||
Read_Primitive(istream,num_files_this_disk); // one entry in center
|
return false;
|
||||||
if(num_files != num_files_this_disk){
|
}
|
||||||
std::cerr<<"ZIP: multi disk zip files are not supported"<<std::endl;return false;}
|
|
||||||
unsigned int size_of_header,header_offset;
|
auto num_files = read_int<std::uint16_t>(source_stream_); // one entry in center in this disk
|
||||||
Read_Primitive(istream,size_of_header); // size of header
|
auto num_files_this_disk = read_int<std::uint16_t>(source_stream_); // one entry in center
|
||||||
Read_Primitive(istream,header_offset); // offset to header
|
|
||||||
|
if(num_files != num_files_this_disk)
|
||||||
|
{
|
||||||
|
std::cerr<<"ZIP: multi disk zip files are not supported"<<std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*auto size_of_header = */read_int<std::uint32_t>(source_stream_); // size of header
|
||||||
|
auto header_offset = read_int<std::uint32_t>(source_stream_); // offset to header
|
||||||
|
|
||||||
// go to header and read all file headers
|
// go to header and read all file headers
|
||||||
istream.seekg(header_offset);
|
source_stream_.seekg(header_offset);
|
||||||
for(int i=0;i<num_files;i++){
|
|
||||||
ZipFileHeader* header=new ZipFileHeader;
|
for (std::uint16_t i = 0; i < num_files; ++i)
|
||||||
bool valid=header->Read(istream,true);
|
{
|
||||||
if(valid) filename_to_header[header->filename]=header;}
|
zip_file_header header;
|
||||||
|
|
||||||
|
if (header.read(source_stream_, true))
|
||||||
|
{
|
||||||
|
file_headers_[header.filename] = header;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
//#####################################################################
|
|
||||||
// Function Get_File
|
std::istream &ZipFileReader::open(const std::string &filename)
|
||||||
//#####################################################################
|
|
||||||
std::istream* ZipFileReader::Get_File(const std::string& filename,const bool binary)
|
|
||||||
{
|
{
|
||||||
std::map<std::string,ZipFileHeader*>::iterator i=filename_to_header.find(filename);
|
if (!has_file(filename))
|
||||||
if(i!=filename_to_header.end()){
|
{
|
||||||
ZipFileHeader* header=i->second;
|
throw "not found";
|
||||||
istream.seekg((*header).header_offset);return new ZIP_FILE_ISTREAM(istream,*header);
|
|
||||||
}
|
}
|
||||||
return 0;
|
|
||||||
}
|
auto header = file_headers_.at(filename);
|
||||||
//#####################################################################
|
source_stream_.seekg(header.header_offset);
|
||||||
// Function Get_File_List
|
read_stream_.reset(new ZIP_FILE_ISTREAM(source_stream_, header));
|
||||||
//#####################################################################
|
|
||||||
void ZipFileReader::Get_File_List(std::vector<std::string>& filenames) const
|
return *read_stream_;
|
||||||
{
|
|
||||||
filenames.clear();
|
|
||||||
std::map<std::string,ZipFileHeader*>::const_iterator i=filename_to_header.begin();
|
|
||||||
for(;i!=filename_to_header.end();++i)
|
|
||||||
filenames.push_back(i->first);
|
|
||||||
}
|
|
||||||
//#####################################################################
|
|
||||||
// Function Has_File
|
|
||||||
//#####################################################################
|
|
||||||
bool ZipFileReader::Has_File(const std::string &filename) const
|
|
||||||
{
|
|
||||||
return filename_to_header.find(filename) != filename_to_header.end();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Partio
|
std::vector<std::string> ZipFileReader::files() const
|
||||||
|
{
|
||||||
|
std::vector<std::string> 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; });
|
||||||
|
return filenames;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ZipFileReader::has_file(const std::string &filename) const
|
||||||
|
{
|
||||||
|
return file_headers_.count(filename) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
} // namespace xlnt
|
||||||
|
|
|
@ -33,56 +33,46 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __ZIP__
|
#pragma once
|
||||||
#define __ZIP__
|
|
||||||
|
|
||||||
#include <fstream>
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <map>
|
#include <memory>
|
||||||
#include <stdexcept>
|
#include <unordered_map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace Partio{
|
namespace xlnt {
|
||||||
struct ZipFileHeader;
|
namespace detail {
|
||||||
//#####################################################################
|
|
||||||
// Functions Gzip_Out/Gzip_In - Create streams that read/write .gz
|
struct zip_file_header;
|
||||||
//#####################################################################
|
|
||||||
std::istream* Gzip_In(const std::string& filename,std::ios::openmode mode);
|
|
||||||
std::ostream* Gzip_Out(const std::string& filename,std::ios::openmode mode);
|
|
||||||
//#####################################################################
|
|
||||||
// Class ZipFileWriter
|
|
||||||
//#####################################################################
|
|
||||||
class ZipFileWriter
|
class ZipFileWriter
|
||||||
{
|
{
|
||||||
std::ostream &ostream;
|
|
||||||
std::vector<ZipFileHeader*> files;
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
//#####################################################################
|
|
||||||
ZipFileWriter(std::ostream &filename);
|
ZipFileWriter(std::ostream &filename);
|
||||||
virtual ~ZipFileWriter();
|
virtual ~ZipFileWriter();
|
||||||
std::ostream* Add_File(const std::string& filename,const bool binary=true);
|
std::ostream* open(const std::string& filename);
|
||||||
//#####################################################################
|
|
||||||
|
private:
|
||||||
|
std::ostream &target_stream_;
|
||||||
|
std::vector<zip_file_header> file_headers_;
|
||||||
};
|
};
|
||||||
|
|
||||||
//#####################################################################
|
|
||||||
// Class ZipFileReader
|
|
||||||
//#####################################################################
|
|
||||||
class ZipFileReader
|
class ZipFileReader
|
||||||
{
|
{
|
||||||
std::istream &istream;
|
|
||||||
public:
|
public:
|
||||||
std::map<std::string,ZipFileHeader*> filename_to_header;
|
|
||||||
|
|
||||||
//#####################################################################
|
|
||||||
ZipFileReader(std::istream &stream);
|
ZipFileReader(std::istream &stream);
|
||||||
virtual ~ZipFileReader();
|
virtual ~ZipFileReader();
|
||||||
std::istream* Get_File(const std::string& filename,const bool binary=true);
|
std::istream &open(const std::string &filename);
|
||||||
void Get_File_List(std::vector<std::string>& filenames) const;
|
std::vector<std::string> files() const;
|
||||||
bool Has_File(const std::string &filename) const;
|
bool has_file(const std::string &filename) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool Find_And_Read_Central_Header();
|
bool read_central_header();
|
||||||
//#####################################################################
|
|
||||||
|
std::unordered_map<std::string, zip_file_header> file_headers_;
|
||||||
|
std::istream &source_stream_;
|
||||||
|
std::unique_ptr<std::istream> read_stream_;
|
||||||
};
|
};
|
||||||
}
|
|
||||||
#endif
|
} // namespace detail
|
||||||
|
} // namespace xlnt
|
||||||
|
|
|
@ -92,18 +92,87 @@ optional<int> alignment::rotation() const
|
||||||
return text_rotation_;
|
return text_rotation_;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string alignment::to_hash_string() const
|
bool operator==(const alignment &left, const alignment &right)
|
||||||
{
|
{
|
||||||
std::string hash_string;
|
if (left.horizontal().is_set() != right.horizontal().is_set())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
hash_string.append(wrap_text_ ? "1" : "0");
|
if (left.horizontal().is_set())
|
||||||
hash_string.append(shrink_to_fit_ ? "1" : "0");
|
{
|
||||||
hash_string.append(std::to_string(static_cast<std::size_t>(horizontal_)));
|
if (left.horizontal().get() != right.horizontal().get())
|
||||||
hash_string.append(std::to_string(static_cast<std::size_t>(vertical_)));
|
{
|
||||||
hash_string.append(std::to_string(text_rotation_));
|
return false;
|
||||||
hash_string.append(std::to_string(indent_));
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return hash_string;
|
if (left.indent().is_set() != right.indent().is_set())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (left.indent().is_set())
|
||||||
|
{
|
||||||
|
if (left.indent().get() != right.indent().get())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (left.rotation().is_set() != right.rotation().is_set())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (left.rotation().is_set())
|
||||||
|
{
|
||||||
|
if (left.rotation().get() != right.rotation().get())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (left.shrink().is_set() != right.shrink().is_set())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (left.shrink().is_set())
|
||||||
|
{
|
||||||
|
if (left.shrink().get() != right.shrink().get())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (left.vertical().is_set() != right.vertical().is_set())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (left.vertical().is_set())
|
||||||
|
{
|
||||||
|
if (left.vertical().get() != right.vertical().get())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (left.wrap().is_set() != right.wrap().is_set())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (left.wrap().is_set())
|
||||||
|
{
|
||||||
|
if (left.wrap().get() != right.wrap().get())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace xlnt
|
} // namespace xlnt
|
||||||
|
|
|
@ -49,6 +49,38 @@ border::border_property &border::border_property::style(border_style s)
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool operator==(const border::border_property &left,
|
||||||
|
const border::border_property &right)
|
||||||
|
{
|
||||||
|
if (left.style().is_set() != right.style().is_set())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (left.style().is_set())
|
||||||
|
{
|
||||||
|
if (left.style().get() != right.style().get())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (left.color().is_set() != right.color().is_set())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (left.color().is_set())
|
||||||
|
{
|
||||||
|
if (left.color().get() != right.color().get())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
border::border()
|
border::border()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -112,45 +144,25 @@ optional<diagonal_direction> border::diagonal() const
|
||||||
return diagonal_direction_;
|
return diagonal_direction_;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string border::to_hash_string() const
|
bool operator==(const border &left, const border &right)
|
||||||
{
|
{
|
||||||
std::string hash_string;
|
for (auto side : border::all_sides())
|
||||||
|
|
||||||
for (const auto &side_type : all_sides())
|
|
||||||
{
|
{
|
||||||
hash_string.append(std::to_string(static_cast<std::size_t>(side_type)));
|
if (left.side(side).is_set() != right.side(side).is_set())
|
||||||
|
|
||||||
if (side(side_type))
|
|
||||||
{
|
{
|
||||||
const auto side_properties = *side(side_type);
|
return false;
|
||||||
|
|
||||||
if (side_properties.style())
|
|
||||||
{
|
|
||||||
hash_string.append(std::to_string(static_cast<std::size_t>(*side_properties.style())));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
hash_string.push_back(' ');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (side_properties.color())
|
if (left.side(side).is_set())
|
||||||
{
|
{
|
||||||
hash_string.append(std::to_string(std::hash<xlnt::hashable>()(*side_properties.color())));
|
if (left.side(side).get() != right.side(side).get())
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
hash_string.push_back(' ');
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
hash_string.push_back(' ');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
hash_string.push_back(' ');
|
return true;
|
||||||
}
|
|
||||||
|
|
||||||
return hash_string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace xlnt
|
} // namespace xlnt
|
||||||
|
|
|
@ -206,32 +206,6 @@ void color::set_tint(double tint)
|
||||||
tint_ = tint;
|
tint_ = tint;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string color::to_hash_string() const
|
|
||||||
{
|
|
||||||
std::string hash_string = "color";
|
|
||||||
|
|
||||||
hash_string.append(std::to_string(static_cast<std::size_t>(type_)));
|
|
||||||
hash_string.append(std::to_string(static_cast<double>(tint_)));
|
|
||||||
|
|
||||||
if (type_ == type::indexed)
|
|
||||||
{
|
|
||||||
hash_string.append("indexed");
|
|
||||||
hash_string.append(std::to_string(indexed_.get_index()));
|
|
||||||
}
|
|
||||||
else if (type_ == type::theme)
|
|
||||||
{
|
|
||||||
hash_string.append("theme");
|
|
||||||
hash_string.append(std::to_string(theme_.get_index()));
|
|
||||||
}
|
|
||||||
else if (type_ == type::rgb)
|
|
||||||
{
|
|
||||||
hash_string.append("rgb");
|
|
||||||
hash_string.append(rgb_.get_hex_string());
|
|
||||||
}
|
|
||||||
|
|
||||||
return hash_string;
|
|
||||||
}
|
|
||||||
|
|
||||||
void color::assert_type(type t) const
|
void color::assert_type(type t) const
|
||||||
{
|
{
|
||||||
if (t != type_)
|
if (t != type_)
|
||||||
|
|
|
@ -72,25 +72,40 @@ pattern_fill &pattern_fill::background(const color &new_background)
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string pattern_fill::to_hash_string() const
|
bool operator==(const pattern_fill &left, const pattern_fill &right)
|
||||||
{
|
{
|
||||||
std::string hash_string = "pattern_fill";
|
if (left.background().is_set() != right.background().is_set())
|
||||||
|
|
||||||
hash_string.append(background_ ? "1" : "0");
|
|
||||||
|
|
||||||
if (background_)
|
|
||||||
{
|
{
|
||||||
hash_string.append(std::to_string(background_->hash()));
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
hash_string.append(background_ ? "1" : "0");
|
if (left.background().is_set())
|
||||||
|
|
||||||
if (background_)
|
|
||||||
{
|
{
|
||||||
hash_string.append(std::to_string(background_->hash()));
|
if (left.background().get() != right.background().get())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return hash_string;
|
if (left.foreground().is_set() != right.foreground().is_set())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (left.foreground().is_set())
|
||||||
|
{
|
||||||
|
if (left.foreground().get() != right.foreground().get())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (left.type() != right.type())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// gradient_fill
|
// gradient_fill
|
||||||
|
@ -166,21 +181,6 @@ gradient_fill &gradient_fill::bottom(double value)
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string gradient_fill::to_hash_string() const
|
|
||||||
{
|
|
||||||
std::string hash_string = "gradient_fill";
|
|
||||||
|
|
||||||
hash_string.append(std::to_string(static_cast<std::size_t>(type_)));
|
|
||||||
hash_string.append(std::to_string(stops_.size()));
|
|
||||||
hash_string.append(std::to_string(degree_));
|
|
||||||
hash_string.append(std::to_string(left_));
|
|
||||||
hash_string.append(std::to_string(right_));
|
|
||||||
hash_string.append(std::to_string(top_));
|
|
||||||
hash_string.append(std::to_string(bottom_));
|
|
||||||
|
|
||||||
return hash_string;
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
||||||
|
@ -198,6 +198,46 @@ std::unordered_map<double, color> gradient_fill::stops() const
|
||||||
return stops_;
|
return stops_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool operator==(const gradient_fill &left, const gradient_fill &right)
|
||||||
|
{
|
||||||
|
if (left.type() != right.type())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (left.degree() != right.degree())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (left.bottom() != right.bottom())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (left.right() != right.right())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (left.top() != right.top())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (left.left() != right.left())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (left.stops() != right.stops())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// fill
|
// fill
|
||||||
|
|
||||||
fill fill::solid(const color &fill_color)
|
fill fill::solid(const color &fill_color)
|
||||||
|
@ -249,27 +289,19 @@ pattern_fill fill::pattern_fill() const
|
||||||
return pattern_;
|
return pattern_;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string fill::to_hash_string() const
|
bool operator==(const fill &left, const fill &right)
|
||||||
{
|
{
|
||||||
std::string hash_string = "fill";
|
if (left.type() != right.type())
|
||||||
|
|
||||||
hash_string.append(std::to_string(static_cast<std::size_t>(type_)));
|
|
||||||
|
|
||||||
switch (type_)
|
|
||||||
{
|
{
|
||||||
case fill_type::pattern:
|
return false;
|
||||||
hash_string.append(std::to_string(pattern_.hash()));
|
}
|
||||||
break;
|
|
||||||
|
|
||||||
case fill_type::gradient:
|
if (left.type() == fill_type::gradient)
|
||||||
hash_string.append(std::to_string(gradient_.hash()));
|
{
|
||||||
break;
|
return left.gradient_fill() == right.gradient_fill();
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
return left.pattern_fill() == right.pattern_fill();
|
||||||
break;
|
|
||||||
} // switch (type_)
|
|
||||||
|
|
||||||
return hash_string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace xlnt
|
} // namespace xlnt
|
||||||
|
|
|
@ -153,22 +153,83 @@ optional<std::string> font::scheme() const
|
||||||
return scheme_;
|
return scheme_;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string font::to_hash_string() const
|
bool operator==(const font &left, const font &right)
|
||||||
{
|
{
|
||||||
std::string hash_string = "font";
|
if (left.bold() != right.bold())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
hash_string.append(std::to_string(bold_));
|
if (left.color().is_set() != right.color().is_set())
|
||||||
hash_string.append(std::to_string(italic_));
|
{
|
||||||
hash_string.append(std::to_string(superscript_));
|
return false;
|
||||||
hash_string.append(std::to_string(subscript_));
|
}
|
||||||
hash_string.append(std::to_string(strikethrough_));
|
|
||||||
hash_string.append(name_);
|
|
||||||
hash_string.append(std::to_string(size_));
|
|
||||||
hash_string.append(std::to_string(static_cast<std::size_t>(underline_)));
|
|
||||||
hash_string.append(family_ ? std::to_string(*family_) : "");
|
|
||||||
hash_string.append(scheme_ ? *scheme_ : "");
|
|
||||||
|
|
||||||
return hash_string;
|
if (left.color().is_set())
|
||||||
|
{
|
||||||
|
if (left.color().get() != right.color().get())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (left.family().is_set() != right.family().is_set())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (left.family().is_set())
|
||||||
|
{
|
||||||
|
if (left.family().get() != right.family().get())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (left.italic() != right.italic())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (left.name() != right.name())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (left.scheme().is_set() != right.scheme().is_set())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (left.scheme().is_set())
|
||||||
|
{
|
||||||
|
if (left.scheme().get() != right.scheme().get())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (left.size() != right.size())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (left.strikethrough() != right.strikethrough())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (left.superscript() != right.superscript())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (left.underline() != right.underline())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace xlnt
|
} // namespace xlnt
|
||||||
|
|
|
@ -273,17 +273,6 @@ std::string number_format::get_format_string() const
|
||||||
return format_string_;
|
return format_string_;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string number_format::to_hash_string() const
|
|
||||||
{
|
|
||||||
std::string hash_string("number_format");
|
|
||||||
hash_string.append(format_string_);
|
|
||||||
hash_string.append("|||");
|
|
||||||
hash_string.append(std::to_string(id_));
|
|
||||||
|
|
||||||
return hash_string;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void number_format::set_format_string(const std::string &format_string)
|
void number_format::set_format_string(const std::string &format_string)
|
||||||
{
|
{
|
||||||
format_string_ = format_string;
|
format_string_ = format_string;
|
||||||
|
@ -364,4 +353,11 @@ std::string number_format::format(long double number, calendar base_date) const
|
||||||
return detail::number_formatter(format_string_, base_date).format_number(number);
|
return detail::number_formatter(format_string_, base_date).format_number(number);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool operator==(const number_format &left, const number_format &right)
|
||||||
|
{
|
||||||
|
return left.id_set_ == right.id_set_
|
||||||
|
&& left.id_ == right.id_
|
||||||
|
&& left.format_string_ == right.format_string_;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace xlnt
|
} // namespace xlnt
|
||||||
|
|
|
@ -52,14 +52,9 @@ protection &protection::hidden(bool hidden)
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string protection::to_hash_string() const
|
bool operator==(const protection &left, const protection &right)
|
||||||
{
|
{
|
||||||
std::string hash_string = "protection";
|
return left.locked_ == right.locked_ && left.hidden_ == right.hidden_;
|
||||||
|
|
||||||
hash_string.append(locked_ ? "1" : "0");
|
|
||||||
hash_string.append(hidden_ ? "1" : "0");
|
|
||||||
|
|
||||||
return hash_string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace xlnt
|
} // namespace xlnt
|
||||||
|
|
|
@ -43,14 +43,14 @@ public:
|
||||||
TS_ASSERT(const_fill.pattern_fill().background());
|
TS_ASSERT(const_fill.pattern_fill().background());
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_hash()
|
void test_comparison()
|
||||||
{
|
{
|
||||||
xlnt::fill pattern_fill = xlnt::pattern_fill().type(xlnt::pattern_fill_type::solid);
|
xlnt::fill pattern_fill = xlnt::pattern_fill().type(xlnt::pattern_fill_type::solid);
|
||||||
xlnt::fill gradient_fill_linear = xlnt::gradient_fill().type(xlnt::gradient_fill_type::linear);
|
xlnt::fill gradient_fill_linear = xlnt::gradient_fill().type(xlnt::gradient_fill_type::linear);
|
||||||
xlnt::fill gradient_fill_path = xlnt::gradient_fill().type(xlnt::gradient_fill_type::path);
|
xlnt::fill gradient_fill_path = xlnt::gradient_fill().type(xlnt::gradient_fill_type::path);
|
||||||
|
|
||||||
TS_ASSERT_DIFFERS(pattern_fill.hash(), gradient_fill_linear.hash());
|
TS_ASSERT_DIFFERS(pattern_fill, gradient_fill_linear);
|
||||||
TS_ASSERT_DIFFERS(gradient_fill_linear.hash(), gradient_fill_path.hash());
|
TS_ASSERT_DIFFERS(gradient_fill_linear, gradient_fill_path);
|
||||||
TS_ASSERT_DIFFERS(gradient_fill_path.hash(), pattern_fill.hash());
|
TS_ASSERT_DIFFERS(gradient_fill_path, pattern_fill);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -32,6 +32,10 @@ exception::exception(const std::string &message)
|
||||||
set_message(message);
|
set_message(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
exception::~exception()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
void exception::set_message(const std::string &message)
|
void exception::set_message(const std::string &message)
|
||||||
{
|
{
|
||||||
message_ = message;
|
message_ = message;
|
||||||
|
@ -47,6 +51,10 @@ invalid_column_string_index::invalid_column_string_index()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
invalid_column_string_index::~invalid_column_string_index()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
invalid_data_type::invalid_data_type()
|
invalid_data_type::invalid_data_type()
|
||||||
: exception("data type error")
|
: exception("data type error")
|
||||||
{
|
{
|
||||||
|
@ -68,6 +76,10 @@ invalid_cell_reference::invalid_cell_reference(const std::string &coord_string)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
invalid_cell_reference::~invalid_cell_reference()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
illegal_character::illegal_character(char c)
|
illegal_character::illegal_character(char c)
|
||||||
: exception(std::string("illegal character: (") + std::to_string(static_cast<unsigned char>(c)) + ")")
|
: exception(std::string("illegal character: (") + std::to_string(static_cast<unsigned char>(c)) + ")")
|
||||||
{
|
{
|
||||||
|
@ -83,6 +95,10 @@ invalid_attribute::invalid_attribute()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
invalid_attribute::~invalid_attribute()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
key_not_found::key_not_found()
|
key_not_found::key_not_found()
|
||||||
: exception("key not found in container")
|
: exception("key not found in container")
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,39 +0,0 @@
|
||||||
// Copyright (c) 2014-2016 Thomas Fussell
|
|
||||||
// Copyright (c) 2010-2015 openpyxl
|
|
||||||
//
|
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
// of this software and associated documentation files (the "Software"), to deal
|
|
||||||
// in the Software without restriction, including without limitation the rights
|
|
||||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
// copies of the Software, and to permit persons to whom the Software is
|
|
||||||
// furnished to do so, subject to the following conditions:
|
|
||||||
//
|
|
||||||
// The above copyright notice and this permission notice shall be included in
|
|
||||||
// all copies or substantial portions of the Software.
|
|
||||||
//
|
|
||||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, WRISING FROM,
|
|
||||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
// THE SOFTWARE
|
|
||||||
//
|
|
||||||
// @license: http://www.opensource.org/licenses/mit-license.php
|
|
||||||
// @author: see AUTHORS file
|
|
||||||
#include <xlnt/utils/hashable.hpp>
|
|
||||||
|
|
||||||
namespace xlnt {
|
|
||||||
|
|
||||||
std::size_t hashable::hash() const
|
|
||||||
{
|
|
||||||
static std::hash<std::string> hasher;
|
|
||||||
return hasher.operator()(to_hash_string());
|
|
||||||
}
|
|
||||||
|
|
||||||
bool hashable::operator==(const xlnt::hashable &other) const
|
|
||||||
{
|
|
||||||
return hash() == other.hash();
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace xlnt
|
|
|
@ -20,6 +20,12 @@
|
||||||
//
|
//
|
||||||
// @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
|
||||||
|
|
||||||
|
#pragma clang diagnostic push
|
||||||
|
#pragma clang diagnostic ignored "-Wshadow"
|
||||||
|
#include <utf8.h>
|
||||||
|
#pragma clang diagnostic pop
|
||||||
|
|
||||||
#include <xlnt/utils/utf8string.hpp>
|
#include <xlnt/utils/utf8string.hpp>
|
||||||
|
|
||||||
namespace xlnt {
|
namespace xlnt {
|
||||||
|
|
|
@ -70,6 +70,10 @@ public:
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
xlnt::workbook wb;
|
xlnt::workbook wb;
|
||||||
wb.load(L"data\\19_unicode_Λ.xlsx");
|
wb.load(L"data\\19_unicode_Λ.xlsx");
|
||||||
|
#else
|
||||||
|
xlnt::workbook wb;
|
||||||
|
wb.load("data/19_unicode_Λ.xlsx");
|
||||||
#endif
|
#endif
|
||||||
|
TS_ASSERT_EQUALS(wb.get_active_sheet().get_cell("A1").get_value<std::string>(), "unicode!");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -637,7 +637,7 @@ std::size_t workbook::get_index(worksheet ws)
|
||||||
throw invalid_parameter();
|
throw invalid_parameter();
|
||||||
}
|
}
|
||||||
|
|
||||||
return std::distance(begin(), match);
|
return static_cast<std::size_t>(std::distance(begin(), match));
|
||||||
}
|
}
|
||||||
|
|
||||||
void workbook::create_named_range(const std::string &name, worksheet range_owner, const std::string &reference_string)
|
void workbook::create_named_range(const std::string &name, worksheet range_owner, const std::string &reference_string)
|
||||||
|
|
|
@ -521,11 +521,11 @@ public:
|
||||||
xlnt::workbook wb;
|
xlnt::workbook wb;
|
||||||
|
|
||||||
auto ws = wb.get_active_sheet();
|
auto ws = wb.get_active_sheet();
|
||||||
ws.add_print_title(3);
|
ws.set_print_title_rows(3);
|
||||||
TS_ASSERT_EQUALS(ws.get_print_titles(), "Sheet1!1:3");
|
TS_ASSERT_EQUALS(ws.get_print_titles(), "Sheet1!1:3");
|
||||||
|
|
||||||
auto ws2 = wb.create_sheet();
|
auto ws2 = wb.create_sheet();
|
||||||
ws2.add_print_title(4, "cols");
|
ws2.set_print_title_cols(4);
|
||||||
TS_ASSERT_EQUALS(ws2.get_print_titles(), "Sheet2!A:D");
|
TS_ASSERT_EQUALS(ws2.get_print_titles(), "Sheet2!A:D");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -534,17 +534,17 @@ public:
|
||||||
xlnt::workbook wb;
|
xlnt::workbook wb;
|
||||||
|
|
||||||
auto ws = wb.get_active_sheet();
|
auto ws = wb.get_active_sheet();
|
||||||
ws.set_print_title_rows("1:4");
|
ws.set_print_title_rows(4);
|
||||||
TS_ASSERT_EQUALS(ws.get_print_titles(), "Sheet1!1:4");
|
TS_ASSERT_EQUALS(ws.get_print_titles(), "Sheet1!1:4");
|
||||||
|
|
||||||
auto ws2 = wb.create_sheet();
|
auto ws2 = wb.create_sheet();
|
||||||
ws2.set_print_title_cols("A:F");
|
ws2.set_print_title_cols("F");
|
||||||
TS_ASSERT_EQUALS(ws2.get_print_titles(), "Sheet2!A:F");
|
TS_ASSERT_EQUALS(ws2.get_print_titles(), "Sheet2!A:F");
|
||||||
|
|
||||||
auto ws3 = wb.create_sheet();
|
auto ws3 = wb.create_sheet();
|
||||||
ws3.set_print_title_rows("1:2");
|
ws3.set_print_title_rows(2, 3);
|
||||||
ws3.set_print_title_cols("C:D");
|
ws3.set_print_title_cols("C", "D");
|
||||||
TS_ASSERT_EQUALS(ws3.get_print_titles(), "Sheet3!1:2,Sheet3!C:D");
|
TS_ASSERT_EQUALS(ws3.get_print_titles(), "Sheet3!2:3,Sheet3!C:D");
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_print_area()
|
void test_print_area()
|
||||||
|
|
|
@ -624,7 +624,7 @@ void worksheet::append(const std::unordered_map<int, std::string> &cells)
|
||||||
|
|
||||||
for (auto cell : cells)
|
for (auto cell : cells)
|
||||||
{
|
{
|
||||||
get_cell(cell_reference(static_cast<column_t>(cell.first), row)).set_value(cell.second);
|
get_cell(cell_reference(static_cast<column_t::index_t>(cell.first), row)).set_value(cell.second);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -985,31 +985,24 @@ range worksheet::iter_cells(bool skip_null)
|
||||||
return range(*this, calculate_dimension(), major_order::row, skip_null);
|
return range(*this, calculate_dimension(), major_order::row, skip_null);
|
||||||
}
|
}
|
||||||
|
|
||||||
void worksheet::add_print_title(int i)
|
void worksheet::set_print_title_rows(row_t last_row)
|
||||||
{
|
{
|
||||||
add_print_title(i, "rows");
|
set_print_title_rows(1, last_row);
|
||||||
}
|
}
|
||||||
|
|
||||||
void worksheet::add_print_title(int i, const std::string &rows_or_cols)
|
void worksheet::set_print_title_rows(row_t first_row, row_t last_row)
|
||||||
{
|
{
|
||||||
if(rows_or_cols == "cols")
|
d_->print_title_rows_ = std::to_string(first_row) + ":" + std::to_string(last_row);
|
||||||
{
|
|
||||||
set_print_title_cols("A:" + column_t::column_string_from_index(i));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
set_print_title_rows("1:" + std::to_string(i));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void worksheet::set_print_title_rows(const std::string &rows)
|
void worksheet::set_print_title_cols(column_t last_column)
|
||||||
{
|
{
|
||||||
d_->print_title_rows_ = rows;
|
set_print_title_cols(1, last_column);
|
||||||
}
|
}
|
||||||
|
|
||||||
void worksheet::set_print_title_cols(const std::string &cols)
|
void worksheet::set_print_title_cols(column_t first_column, column_t last_column)
|
||||||
{
|
{
|
||||||
d_->print_title_cols_ = cols;
|
d_->print_title_cols_ = first_column.column_string() + ":" + last_column.column_string();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string worksheet::get_print_titles() const
|
std::string worksheet::get_print_titles() const
|
||||||
|
|
|
@ -26,15 +26,21 @@ file(GLOB UTILS_TESTS ${LIBRARY_SOURCE_DIR}/utils/tests/test_*.hpp)
|
||||||
file(GLOB WORKBOOK_TESTS ${LIBRARY_SOURCE_DIR}/workbook/tests/test_*.hpp)
|
file(GLOB WORKBOOK_TESTS ${LIBRARY_SOURCE_DIR}/workbook/tests/test_*.hpp)
|
||||||
file(GLOB WORKSHEET_TESTS ${LIBRARY_SOURCE_DIR}/worksheet/tests/test_*.hpp)
|
file(GLOB WORKSHEET_TESTS ${LIBRARY_SOURCE_DIR}/worksheet/tests/test_*.hpp)
|
||||||
|
|
||||||
set(ZIP ${LIBRARY_SOURCE_DIR}/detail/zip.cpp)
|
set(XLNT_ZIP
|
||||||
|
${LIBRARY_SOURCE_DIR}/detail/zip.cpp
|
||||||
|
${LIBRARY_SOURCE_DIR}/detail/zip.hpp)
|
||||||
|
|
||||||
set(TESTS ${CELL_TESTS} ${CHARTS_TESTS} ${CHARTSHEET_TESTS} ${DRAWING_TESTS}
|
set(TESTS ${CELL_TESTS} ${CHARTS_TESTS} ${CHARTSHEET_TESTS} ${DRAWING_TESTS}
|
||||||
${FORMULA_TESTS} ${PACKAGING_TESTS} ${STYLES_TESTS} ${UTILS_TESTS}
|
${FORMULA_TESTS} ${PACKAGING_TESTS} ${STYLES_TESTS} ${UTILS_TESTS}
|
||||||
${WORKBOOK_TESTS} ${WORKSHEET_TESTS})
|
${WORKBOOK_TESTS} ${WORKSHEET_TESTS})
|
||||||
set(PUGIXML ${THIRD_PARTY_DIR}/pugixml/src/pugixml.cpp)
|
|
||||||
|
|
||||||
file(GLOB TEST_HELPERS_HEADERS ${XLNT_TESTS_DIR}/helpers/*.hpp)
|
set(PUGIXML
|
||||||
file(GLOB TEST_HELPERS_SOURCES ${XLNT_TESTS_DIR}/helpers/*.cpp)
|
${THIRD_PARTY_DIR}/pugixml/src/pugixml.cpp
|
||||||
|
${THIRD_PARTY_DIR}/pugixml/src/pugixml.hpp
|
||||||
|
${THIRD_PARTY_DIR}/pugixml/src/pugiconfig.hpp)
|
||||||
|
|
||||||
|
file(GLOB TEST_HELPERS_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/helpers/*.hpp)
|
||||||
|
file(GLOB TEST_HELPERS_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/helpers/*.cpp)
|
||||||
|
|
||||||
SET(TEST_HELPERS ${TEST_HELPERS_HEADERS} ${TEST_HELPERS_SOURCES})
|
SET(TEST_HELPERS ${TEST_HELPERS_HEADERS} ${TEST_HELPERS_SOURCES})
|
||||||
|
|
||||||
|
@ -42,9 +48,11 @@ file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/tests")
|
||||||
set(RUNNER "${CMAKE_CURRENT_BINARY_DIR}/runner-autogen.cpp")
|
set(RUNNER "${CMAKE_CURRENT_BINARY_DIR}/runner-autogen.cpp")
|
||||||
set_source_files_properties(${RUNNER} PROPERTIES GENERATED TRUE)
|
set_source_files_properties(${RUNNER} PROPERTIES GENERATED TRUE)
|
||||||
|
|
||||||
add_executable(${PROJECT_NAME} ${TEST_HELPERS} ${TESTS} ${RUNNER} ${PUGIXML} $<TARGET_OBJECTS:xlnt.third-party> ${ZIP})
|
add_executable(${PROJECT_NAME} ${TEST_HELPERS} ${TESTS} ${RUNNER} ${PUGIXML} $<TARGET_OBJECTS:xlnt.third-party> ${XLNT_ZIP})
|
||||||
|
|
||||||
source_group(helpers FILES ${TEST_HELPERS})
|
source_group(helpers FILES ${TEST_HELPERS})
|
||||||
|
source_group(xlnt\\detail FILES ${XLNT_ZIP})
|
||||||
|
source_group(third-party\\pugixml FILES ${PUGIXML})
|
||||||
source_group(tests\\cell FILES ${CELL_TESTS})
|
source_group(tests\\cell FILES ${CELL_TESTS})
|
||||||
source_group(tests\\charts FILES ${CHARTS_TESTS})
|
source_group(tests\\charts FILES ${CHARTS_TESTS})
|
||||||
source_group(tests\\chartsheet FILES ${CHARTSHEET_TESTS})
|
source_group(tests\\chartsheet FILES ${CHARTSHEET_TESTS})
|
||||||
|
|
Binary file not shown.
|
@ -276,7 +276,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()));
|
||||||
Partio::ZipFileReader archive(file_stream);
|
xlnt::detail::ZipFileReader archive(file_stream);
|
||||||
|
|
||||||
return string_matches_archive_member(expected, archive, part, content_type);
|
return string_matches_archive_member(expected, archive, part, content_type);
|
||||||
}
|
}
|
||||||
|
@ -287,33 +287,32 @@ 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()));
|
||||||
Partio::ZipFileReader archive(file_stream);
|
xlnt::detail::ZipFileReader 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,
|
||||||
Partio::ZipFileReader &archive,
|
xlnt::detail::ZipFileReader &archive,
|
||||||
const xlnt::path &member,
|
const xlnt::path &member,
|
||||||
const std::string &content_type)
|
const std::string &content_type)
|
||||||
{
|
{
|
||||||
auto stream = archive.Get_File(member.string(), true);
|
auto &stream = archive.open(member.string());
|
||||||
std::string contents((std::istreambuf_iterator<char>(*stream)), (std::istreambuf_iterator<char>()));
|
std::string contents((std::istreambuf_iterator<char>(stream)), (std::istreambuf_iterator<char>()));
|
||||||
delete stream;
|
|
||||||
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,
|
||||||
Partio::ZipFileReader &archive,
|
xlnt::detail::ZipFileReader &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.string())) 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);
|
||||||
std::unique_ptr<std::istream> member_stream(archive.Get_File(member.string(), true));
|
auto &member_stream = archive.open(member.string());
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
@ -337,15 +336,15 @@ 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);
|
||||||
Partio::ZipFileReader left_archive(left_stream);
|
xlnt::detail::ZipFileReader left_archive(left_stream);
|
||||||
|
|
||||||
const auto left_info = left_archive.filename_to_header;
|
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);
|
||||||
Partio::ZipFileReader right_archive(right_stream);
|
xlnt::detail::ZipFileReader right_archive(right_stream);
|
||||||
|
|
||||||
const auto right_info = right_archive.filename_to_header;
|
const auto right_info = right_archive.files();
|
||||||
|
|
||||||
if (left_info.size() != right_info.size())
|
if (left_info.size() != right_info.size())
|
||||||
{
|
{
|
||||||
|
@ -354,14 +353,14 @@ public:
|
||||||
std::cout << "left has: ";
|
std::cout << "left has: ";
|
||||||
for (auto &info : left_info)
|
for (auto &info : left_info)
|
||||||
{
|
{
|
||||||
std::cout << info.first << ", ";
|
std::cout << info << ", ";
|
||||||
}
|
}
|
||||||
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.first << ", ";
|
std::cout << info << ", ";
|
||||||
}
|
}
|
||||||
std::cout << std::endl;
|
std::cout << std::endl;
|
||||||
}
|
}
|
||||||
|
@ -379,33 +378,33 @@ public:
|
||||||
|
|
||||||
for (auto left_member : left_info)
|
for (auto left_member : left_info)
|
||||||
{
|
{
|
||||||
if (!right_archive.Has_File(left_member.first))
|
if (!right_archive.has_file(left_member))
|
||||||
{
|
{
|
||||||
match = false;
|
match = false;
|
||||||
std::cout << "right is missing file: " << left_member.first << std::endl;
|
std::cout << "right is missing file: " << left_member << std::endl;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<std::istream> left_member_stream(left_archive.Get_File(left_member.first));
|
auto &left_member_stream = left_archive.open(left_member);
|
||||||
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());
|
||||||
|
|
||||||
std::unique_ptr<std::istream> right_member_stream(left_archive.Get_File(left_member.first));
|
auto &right_member_stream = left_archive.open(left_member);
|
||||||
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);
|
||||||
right_contents_stream << right_member_stream->rdbuf();
|
right_contents_stream << right_member_stream.rdbuf();
|
||||||
std::string right_member_contents(right_contents_raw.begin(), right_contents_raw.end());
|
std::string right_member_contents(right_contents_raw.begin(), right_contents_raw.end());
|
||||||
|
|
||||||
std::string left_content_type, right_content_type;
|
std::string left_content_type, right_content_type;
|
||||||
|
|
||||||
if (left_member.first != "[Content_Types].xml")
|
if (left_member != "[Content_Types].xml")
|
||||||
{
|
{
|
||||||
left_content_type = left_manifest.get_content_type(xlnt::path(left_member.first));
|
left_content_type = left_manifest.get_content_type(xlnt::path(left_member));
|
||||||
right_content_type = right_manifest.get_content_type(xlnt::path(left_member.first));
|
right_content_type = right_manifest.get_content_type(xlnt::path(left_member));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -415,7 +414,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.first
|
<< left_member
|
||||||
<< " "
|
<< " "
|
||||||
<< left_content_type
|
<< left_content_type
|
||||||
<< " "
|
<< " "
|
||||||
|
@ -425,7 +424,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.first << std::endl;
|
std::cout << left_member << std::endl;
|
||||||
match = false;
|
match = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
92
third-party/CMakeLists.txt
vendored
92
third-party/CMakeLists.txt
vendored
|
@ -14,30 +14,47 @@ set(LIBSTUDXML
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/libstudxml/xml/qname.cxx
|
${CMAKE_CURRENT_SOURCE_DIR}/libstudxml/xml/qname.cxx
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/libstudxml/xml/serializer.cxx
|
${CMAKE_CURRENT_SOURCE_DIR}/libstudxml/xml/serializer.cxx
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/libstudxml/xml/value-traits.cxx
|
${CMAKE_CURRENT_SOURCE_DIR}/libstudxml/xml/value-traits.cxx
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/libstudxml/xml/content
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/libstudxml/xml/exception
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/libstudxml/xml/forward
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/libstudxml/xml/parser
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/libstudxml/xml/qname
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/libstudxml/xml/serializer
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/libstudxml/xml/value-traits)
|
||||||
|
|
||||||
|
set(EXPAT
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/libstudxml/xml/details/expat/xmlparse.c
|
${CMAKE_CURRENT_SOURCE_DIR}/libstudxml/xml/details/expat/xmlparse.c
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/libstudxml/xml/details/expat/xmlrole.c
|
${CMAKE_CURRENT_SOURCE_DIR}/libstudxml/xml/details/expat/xmlrole.c
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/libstudxml/xml/details/expat/xmltok_impl.c
|
${CMAKE_CURRENT_SOURCE_DIR}/libstudxml/xml/details/expat/xmltok_impl.c
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/libstudxml/xml/details/expat/xmltok_ns.c
|
${CMAKE_CURRENT_SOURCE_DIR}/libstudxml/xml/details/expat/xmltok_ns.c
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/libstudxml/xml/details/expat/xmltok.c
|
${CMAKE_CURRENT_SOURCE_DIR}/libstudxml/xml/details/expat/xmltok.c
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/libstudxml/xml/details/expat/ascii.h
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/libstudxml/xml/details/expat/asciitab.h
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/libstudxml/xml/details/expat/config.h
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/libstudxml/xml/details/expat/expat_external.h
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/libstudxml/xml/details/expat/expat.h
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/libstudxml/xml/details/expat/iasciitab.h
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/libstudxml/xml/details/expat/internal.h
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/libstudxml/xml/details/expat/latin1tab.h
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/libstudxml/xml/details/expat/nametab.h
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/libstudxml/xml/details/expat/utf8tab.h
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/libstudxml/xml/details/expat/xmlrole.h
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/libstudxml/xml/details/expat/xmltok_impl.h
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/libstudxml/xml/details/expat/xmltok.h)
|
||||||
|
|
||||||
|
set(GENX
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/libstudxml/xml/details/genx/char-props.c
|
${CMAKE_CURRENT_SOURCE_DIR}/libstudxml/xml/details/genx/char-props.c
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/libstudxml/xml/details/genx/genx.c)
|
${CMAKE_CURRENT_SOURCE_DIR}/libstudxml/xml/details/genx/genx.c
|
||||||
set(POLE pole/pole.cpp)
|
${CMAKE_CURRENT_SOURCE_DIR}/libstudxml/xml/details/genx/genx.h)
|
||||||
set(BOTAN ${CMAKE_CURRENT_SOURCE_DIR}/botan/botan_all.cpp)
|
|
||||||
set(ZLIB ${CMAKE_CURRENT_SOURCE_DIR}/zlib/adler32.c
|
set(POLE
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/zlib/compress.c
|
${CMAKE_CURRENT_SOURCE_DIR}/pole/pole.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/zlib/crc32.c
|
${CMAKE_CURRENT_SOURCE_DIR}/pole/pole.h)
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/zlib/deflate.c
|
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/zlib/gzclose.c
|
set(BOTAN
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/zlib/gzlib.c
|
${CMAKE_CURRENT_SOURCE_DIR}/botan/botan_all.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/zlib/gzread.c
|
${CMAKE_CURRENT_SOURCE_DIR}/botan/botan_all_internal.h
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/zlib/gzwrite.c
|
${CMAKE_CURRENT_SOURCE_DIR}/botan/botan_all.h)
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/zlib/infback.c
|
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/zlib/inffast.c
|
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/zlib/inflate.c
|
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/zlib/inftrees.c
|
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/zlib/trees.c
|
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/zlib/uncompr.c
|
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/zlib/zutil.c)
|
|
||||||
|
|
||||||
if(MSVC)
|
if(MSVC)
|
||||||
set_source_files_properties(${BOTAN} PROPERTIES COMPILE_FLAGS "/wd\"4244\"")
|
set_source_files_properties(${BOTAN} PROPERTIES COMPILE_FLAGS "/wd\"4244\"")
|
||||||
|
@ -52,9 +69,40 @@ endif()
|
||||||
add_custom_command(OUTPUT ${BOTAN}
|
add_custom_command(OUTPUT ${BOTAN}
|
||||||
COMMAND python configure.py --minimized-build --enable-modules=sha1,aes,filters,codec_filt,cbc,ecb,sha2_32,sha2_64 --without-sphinx --disable-shared --amalgamation --cpu=${CPU}
|
COMMAND python configure.py --minimized-build --enable-modules=sha1,aes,filters,codec_filt,cbc,ecb,sha2_32,sha2_64 --without-sphinx --disable-shared --amalgamation --cpu=${CPU}
|
||||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/botan
|
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/botan
|
||||||
COMMENT "Generating botan amalgamation ${BOTAN}")
|
COMMENT "Generating botan amalgamation")
|
||||||
|
|
||||||
add_library(xlnt.third-party OBJECT ${LIBSTUDXML} ${POLE} ${BOTAN} ${ZLIB})
|
set(ZLIB ${CMAKE_CURRENT_SOURCE_DIR}/zlib/adler32.c
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/zlib/compress.c
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/zlib/crc32.c
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/zlib/deflate.c
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/zlib/gzclose.c
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/zlib/gzlib.c
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/zlib/gzread.c
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/zlib/gzwrite.c
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/zlib/infback.c
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/zlib/inffast.c
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/zlib/inflate.c
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/zlib/inftrees.c
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/zlib/trees.c
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/zlib/uncompr.c
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/zlib/zutil.c
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/zlib/crc32.h
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/zlib/deflate.h
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/zlib/gzguts.h
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/zlib/inffast.h
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/zlib/inffixed.h
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/zlib/inflate.h
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/zlib/inftrees.h
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/zlib/trees.h
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/zlib/zconf.h
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/zlib/zlib.h
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/zlib/zutil.h)
|
||||||
|
|
||||||
|
if(NOT MSVC)
|
||||||
|
set_source_files_properties(${ZLIB} PROPERTIES COMPILE_FLAGS "-Wno-implicit-function-declaration")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
add_library(xlnt.third-party OBJECT ${LIBSTUDXML} ${GENX} ${EXPAT} ${POLE} ${BOTAN} ${ZLIB})
|
||||||
target_compile_definitions(xlnt.third-party PRIVATE LIBSTUDXML_STATIC_LIB=1)
|
target_compile_definitions(xlnt.third-party PRIVATE LIBSTUDXML_STATIC_LIB=1)
|
||||||
|
|
||||||
if(NOT STATIC)
|
if(NOT STATIC)
|
||||||
|
@ -69,5 +117,7 @@ endif()
|
||||||
|
|
||||||
source_group(botan FILES ${BOTAN})
|
source_group(botan FILES ${BOTAN})
|
||||||
source_group(libstudxml FILES ${LIBSTUDXML})
|
source_group(libstudxml FILES ${LIBSTUDXML})
|
||||||
source_group(pole FILES ${LIBSTUDXML})
|
source_group(libstudxml\\genx FILES ${GENX})
|
||||||
|
source_group(libstudxml\\expat FILES ${EXPAT})
|
||||||
|
source_group(pole FILES ${POLE})
|
||||||
source_group(zlib FILES ${ZLIB})
|
source_group(zlib FILES ${ZLIB})
|
||||||
|
|
2
third-party/botan
vendored
2
third-party/botan
vendored
|
@ -1 +1 @@
|
||||||
Subproject commit 36e0ea1e407027ac48e82b56016a6813ff6a1082
|
Subproject commit 73c2605f50e6192bf6cb560c51d32bc53b4c5597
|
2
third-party/libstudxml
vendored
2
third-party/libstudxml
vendored
|
@ -1 +1 @@
|
||||||
Subproject commit 54d64e7ca405e06d2328e6207bb4752e20577e50
|
Subproject commit 132522ca4c895e9b07d7e323d5529474806e5829
|
2
third-party/pugixml
vendored
2
third-party/pugixml
vendored
|
@ -1 +1 @@
|
||||||
Subproject commit dfe9360cdf038c0ecf53d45bfc75cf8fd34604b8
|
Subproject commit a832e8a5eff11f58a00ca41ec51ff3895b0da165
|
2
third-party/utfcpp
vendored
2
third-party/utfcpp
vendored
|
@ -1 +1 @@
|
||||||
Subproject commit f029fcc2fbc7cd979925f198f7e6ca8170d45000
|
Subproject commit a5ad5ec9d936d63e9c010d1054f8b11fed0fabbc
|
2
third-party/zlib
vendored
2
third-party/zlib
vendored
|
@ -1 +1 @@
|
||||||
Subproject commit 50893291621658f355bc5b4d450a8d06a563053d
|
Subproject commit 94575859cf7f657f0f31aff4c50761fe3f182699
|
Loading…
Reference in New Issue
Block a user