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:
Thomas Fussell 2016-10-31 20:48:43 -04:00
parent dce2367524
commit 0d97105122
88 changed files with 1864 additions and 1486 deletions

View File

@ -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
View File

@ -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

View File

@ -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

View File

@ -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:
++++++++++++ ++++++++++++

View File

@ -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>

View File

@ -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

View File

@ -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_;

View File

@ -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_;
@ -82,9 +91,16 @@ 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_;

View File

@ -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;

View File

@ -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();
@ -134,9 +141,16 @@ public:
gradient_fill &clear_stops(); gradient_fill &clear_stops();
std::unordered_map<double, color> stops() const; std::unordered_map<double, color> stops() const;
/// <summary>
/// Returns true if left is exactly equal to right.
/// </summary>
friend bool operator==(const gradient_fill &left, const gradient_fill &right);
protected: /// <summary>
std::string to_hash_string() const override; /// 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>
@ -203,9 +217,16 @@ public:
/// Throws an invalid_attribute exception if this is not a pattern fill. /// Throws an invalid_attribute exception if this is not a pattern fill.
/// </summary> /// </summary>
class pattern_fill pattern_fill() const; class pattern_fill pattern_fill() const;
/// <summary>
/// Returns true if left is exactly equal to right.
/// </summary>
friend bool operator==(const fill &left, const fill &right);
protected: /// <summary>
std::string to_hash_string() const override; /// 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;

View File

@ -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
@ -91,9 +91,16 @@ public:
font &scheme(const std::string &scheme); font &scheme(const std::string &scheme);
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;

View File

@ -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_;

View File

@ -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();
@ -49,9 +48,16 @@ public:
bool hidden() const; bool hidden() const;
protection &hidden(bool hidden); protection &hidden(bool hidden);
/// <summary>
/// Returns true if left is exactly equal to right.
/// </summary>
friend bool operator==(const protection &left, const protection &right);
protected: /// <summary>
std::string to_hash_string() const override; /// 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_;

View File

@ -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>

View File

@ -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

View File

@ -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>

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -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)

View File

@ -48,7 +48,15 @@ endforeach()
# Platform specific settings # Platform specific settings
if(COVERAGE) 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()
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() endif()
if(APPLE) if(APPLE)
@ -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}

View File

@ -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()

View File

@ -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

View File

@ -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); }

View File

@ -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

View File

@ -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();
} }

View File

@ -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.

View File

@ -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>{

View File

@ -25,4 +25,4 @@
#include <xml/content> #include <xml/content>
#include <xml/parser> #include <xml/parser>
#include <xml/qname> #include <xml/qname>
#include <xml/serializer> #include <xml/serializer>

View File

@ -25,125 +25,144 @@
#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()
{ {
const std::unordered_map<int, std::string> *all = const std::unordered_map<int, std::string> *all =
new std::unordered_map<int, std::string>( new std::unordered_map<int, std::string>(
{ {
{ 0x401, "Arabic - Saudi Arabia" }, { 0x401, "Arabic - Saudi Arabia" },
{ 0x402, "Bulgarian" }, { 0x402, "Bulgarian" },
{ 0x403, "Catalan" }, { 0x403, "Catalan" },
{ 0x404, "Chinese - Taiwan" }, { 0x404, "Chinese - Taiwan" },
{ 0x405, "Czech" }, { 0x405, "Czech" },
{ 0x406, "Danish" }, { 0x406, "Danish" },
{ 0x407, "German - Germany" }, { 0x407, "German - Germany" },
{ 0x408, "Greek" }, { 0x408, "Greek" },
{ 0x409, "English - United States" }, { 0x409, "English - United States" },
{ 0x410, "Italian - Italy" }, { 0x410, "Italian - Italy" },
{ 0x411, "Japanese" }, { 0x411, "Japanese" },
{ 0x412, "Korean" }, { 0x412, "Korean" },
{ 0x413, "Dutch - Netherlands" }, { 0x413, "Dutch - Netherlands" },
{ 0x414, "Norwegian - Bokml" }, { 0x414, "Norwegian - Bokml" },
{ 0x415, "Polish" }, { 0x415, "Polish" },
{ 0x416, "Portuguese - Brazil" }, { 0x416, "Portuguese - Brazil" },
{ 0x417, "Raeto-Romance" }, { 0x417, "Raeto-Romance" },
{ 0x418, "Romanian - Romania" }, { 0x418, "Romanian - Romania" },
{ 0x419, "Russian" }, { 0x419, "Russian" },
{ 0x420, "Urdu" }, { 0x420, "Urdu" },
{ 0x421, "Indonesian" }, { 0x421, "Indonesian" },
{ 0x422, "Ukrainian" }, { 0x422, "Ukrainian" },
{ 0x423, "Belarusian" }, { 0x423, "Belarusian" },
{ 0x424, "Slovenian" }, { 0x424, "Slovenian" },
{ 0x425, "Estonian" }, { 0x425, "Estonian" },
{ 0x426, "Latvian" }, { 0x426, "Latvian" },
{ 0x427, "Lithuanian" }, { 0x427, "Lithuanian" },
{ 0x428, "Tajik" }, { 0x428, "Tajik" },
{ 0x429, "Farsi - Persian" }, { 0x429, "Farsi - Persian" },
{ 0x430, "Sesotho (Sutu)" }, { 0x430, "Sesotho (Sutu)" },
{ 0x431, "Tsonga" }, { 0x431, "Tsonga" },
{ 0x432, "Setsuana" }, { 0x432, "Setsuana" },
{ 0x433, "Venda" }, { 0x433, "Venda" },
{ 0x434, "Xhosa" }, { 0x434, "Xhosa" },
{ 0x435, "Zulu" }, { 0x435, "Zulu" },
{ 0x436, "Afrikaans" }, { 0x436, "Afrikaans" },
{ 0x437, "Georgian" }, { 0x437, "Georgian" },
{ 0x438, "Faroese" }, { 0x438, "Faroese" },
{ 0x439, "Hindi" }, { 0x439, "Hindi" },
{ 0x440, "Kyrgyz - Cyrillic" }, { 0x440, "Kyrgyz - Cyrillic" },
{ 0x441, "Swahili" }, { 0x441, "Swahili" },
{ 0x442, "Turkmen" }, { 0x442, "Turkmen" },
{ 0x443, "Uzbek - Latin" }, { 0x443, "Uzbek - Latin" },
{ 0x444, "Tatar" }, { 0x444, "Tatar" },
{ 0x445, "Bengali - India" }, { 0x445, "Bengali - India" },
{ 0x446, "Punjabi" }, { 0x446, "Punjabi" },
{ 0x447, "Gujarati" }, { 0x447, "Gujarati" },
{ 0x448, "Oriya" }, { 0x448, "Oriya" },
{ 0x449, "Tamil" }, { 0x449, "Tamil" },
{ 0x450, "Mongolian" }, { 0x450, "Mongolian" },
{ 0x451, "Tibetan" }, { 0x451, "Tibetan" },
{ 0x452, "Welsh" }, { 0x452, "Welsh" },
{ 0x453, "Khmer" }, { 0x453, "Khmer" },
{ 0x454, "Lao" }, { 0x454, "Lao" },
{ 0x455, "Burmese" }, { 0x455, "Burmese" },
{ 0x456, "Galician" }, { 0x456, "Galician" },
{ 0x457, "Konkani" }, { 0x457, "Konkani" },
{ 0x458, "Manipuri" }, { 0x458, "Manipuri" },
{ 0x459, "Sindhi" }, { 0x459, "Sindhi" },
{ 0x460, "Kashmiri" }, { 0x460, "Kashmiri" },
{ 0x461, "Nepali" }, { 0x461, "Nepali" },
{ 0x462, "Frisian - Netherlands" }, { 0x462, "Frisian - Netherlands" },
{ 0x464, "Filipino" }, { 0x464, "Filipino" },
{ 0x465, "Divehi; Dhivehi; Maldivian" }, { 0x465, "Divehi; Dhivehi; Maldivian" },
{ 0x466, "Edo" }, { 0x466, "Edo" },
{ 0x470, "Igbo - Nigeria" }, { 0x470, "Igbo - Nigeria" },
{ 0x474, "Guarani - Paraguay" }, { 0x474, "Guarani - Paraguay" },
{ 0x476, "Latin" }, { 0x476, "Latin" },
{ 0x477, "Somali" }, { 0x477, "Somali" },
{ 0x481, "Maori" }, { 0x481, "Maori" },
{ 0x801, "Arabic - Iraq" }, { 0x801, "Arabic - Iraq" },
{ 0x804, "Chinese - China" }, { 0x804, "Chinese - China" },
{ 0x807, "German - Switzerland" }, { 0x807, "German - Switzerland" },
{ 0x809, "English - Great Britain" }, { 0x809, "English - Great Britain" },
{ 0x810, "Italian - Switzerland" }, { 0x810, "Italian - Switzerland" },
{ 0x813, "Dutch - Belgium" }, { 0x813, "Dutch - Belgium" },
{ 0x814, "Norwegian - Nynorsk" }, { 0x814, "Norwegian - Nynorsk" },
{ 0x816, "Portuguese - Portugal" }, { 0x816, "Portuguese - Portugal" },
{ 0x818, "Romanian - Moldova" }, { 0x818, "Romanian - Moldova" },
{ 0x819, "Russian - Moldova" }, { 0x819, "Russian - Moldova" },
{ 0x843, "Uzbek - Cyrillic" }, { 0x843, "Uzbek - Cyrillic" },
{ 0x845, "Bengali - Bangladesh" }, { 0x845, "Bengali - Bangladesh" },
{ 0x850, "Mongolian" }, { 0x850, "Mongolian" },
{ 0x1001, "Arabic - Libya" }, { 0x1001, "Arabic - Libya" },
{ 0x1004, "Chinese - Singapore" }, { 0x1004, "Chinese - Singapore" },
{ 0x1007, "German - Luxembourg" }, { 0x1007, "German - Luxembourg" },
{ 0x1009, "English - Canada" }, { 0x1009, "English - Canada" },
{ 0x1401, "Arabic - Algeria" }, { 0x1401, "Arabic - Algeria" },
{ 0x1404, "Chinese - Macau SAR" }, { 0x1404, "Chinese - Macau SAR" },
{ 0x1407, "German - Liechtenstein" }, { 0x1407, "German - Liechtenstein" },
{ 0x1409, "English - New Zealand" }, { 0x1409, "English - New Zealand" },
{ 0x1801, "Arabic - Morocco" }, { 0x1801, "Arabic - Morocco" },
{ 0x1809, "English - Ireland" }, { 0x1809, "English - Ireland" },
{ 0x2001, "Arabic - Oman" }, { 0x2001, "Arabic - Oman" },
{ 0x2009, "English - Jamaica" }, { 0x2009, "English - Jamaica" },
{ 0x2401, "Arabic - Yemen" }, { 0x2401, "Arabic - Yemen" },
{ 0x2409, "English - Caribbean" }, { 0x2409, "English - Caribbean" },
{ 0x2801, "Arabic - Syria" }, { 0x2801, "Arabic - Syria" },
{ 0x2809, "English - Belize" }, { 0x2809, "English - Belize" },
{ 0x3001, "Arabic - Lebanon" }, { 0x3001, "Arabic - Lebanon" },
{ 0x3009, "English - Zimbabwe" }, { 0x3009, "English - Zimbabwe" },
{ 0x3401, "Arabic - Kuwait" }, { 0x3401, "Arabic - Kuwait" },
{ 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))
{ {

View File

@ -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

View File

@ -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())

View File

@ -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.

File diff suppressed because it is too large Load Diff

View File

@ -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())
@ -119,10 +128,6 @@ void xlsx_producer::populate_archive()
case relationship::type::office_document: case relationship::type::office_document:
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()

View File

@ -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_;
}; };

View File

@ -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) // read and check for local/global magic
{unsigned int sig; if(global)
unsigned short version,flags; {
// read and check for local/global magic if(sig!=0x02014b50)
if(global){ {
Read_Primitive(istream,sig); std::cerr<<"Did not find global header signature"<<std::endl;
if(sig!=0x02014b50){std::cerr<<"Did not find global header signature"<<std::endl;return false;} return false;
Read_Primitive(istream,version);} }
else{
Read_Primitive(istream,sig); version = read_int<std::uint16_t>(istream);
if(sig!=0x04034b50){std::cerr<<"Did not find local header signature"<<std::endl;return false;}} }
// Read rest of header else if(sig!=0x04034b50)
Read_Primitive(istream,version); {
Read_Primitive(istream,flags); std::cerr<<"Did not find local header signature"<<std::endl;
Read_Primitive(istream,compression_type); return false;
Read_Primitive(istream,stamp_date); }
Read_Primitive(istream,stamp_time);
Read_Primitive(istream,crc); // Read rest of header
Read_Primitive(istream,compressed_size); version = read_int<std::uint16_t>(istream);
Read_Primitive(istream,uncompressed_size); flags = read_int<std::uint16_t>(istream);
unsigned short filename_length,extra_length; compression_type = read_int<std::uint16_t>(istream);
Read_Primitive(istream,filename_length); stamp_date = read_int<std::uint16_t>(istream);
Read_Primitive(istream,extra_length); stamp_time = read_int<std::uint16_t>(istream);
unsigned short comment_length=0; crc = read_int<std::uint32_t>(istream);
if(global){ compressed_size = read_int<std::uint32_t>(istream);
Read_Primitive(istream,comment_length); // filecomment uncompressed_size = read_int<std::uint32_t>(istream);
unsigned short disk_number_start,int_file_attrib;
unsigned int ext_file_attrib; auto filename_length = read_int<std::uint16_t>(istream);
Read_Primitive(istream,disk_number_start); // disk# start auto extra_length = read_int<std::uint16_t>(istream);
Read_Primitive(istream,int_file_attrib); // internal file
Read_Primitive(istream,ext_file_attrib); // ext final std::uint16_t comment_length = 0;
Read_Primitive(istream,header_offset);} // rel offset
char* buf=new char[std::max(comment_length,std::max(filename_length,extra_length))+1]; if(global)
istream.read(buf,filename_length); {
buf[filename_length]=0; comment_length = read_int<std::uint16_t>(istream);
filename=std::string(buf, buf + filename_length); /*std::uint16_t disk_number_start = */read_int<std::uint16_t>(istream);
istream.read(buf,extra_length); /*std::uint16_t int_file_attrib = */read_int<std::uint16_t>(istream);
if(global) istream.read(buf,comment_length); /*std::uint32_t ext_file_attrib = */read_int<std::uint32_t>(istream);
delete [] buf; header_offset = read_int<std::uint32_t>(istream);
return true;} }
filename.resize(filename_length, '\0');
istream.read(&filename[0], filename_length);
extra.resize(extra_length, 0);
istream.read(reinterpret_cast<char *>(extra.data()), extra_length);
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

View File

@ -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

View File

@ -25,4 +25,4 @@ bool operator==(const uri &left, const uri &right)
return left.to_string() == right.to_string(); return left.to_string() == right.to_string();
} }
} // namespace xlnt } // namespace xlnt

View File

@ -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())
{
hash_string.append(wrap_text_ ? "1" : "0"); return false;
hash_string.append(shrink_to_fit_ ? "1" : "0"); }
hash_string.append(std::to_string(static_cast<std::size_t>(horizontal_)));
hash_string.append(std::to_string(static_cast<std::size_t>(vertical_)));
hash_string.append(std::to_string(text_rotation_));
hash_string.append(std::to_string(indent_));
return hash_string; if (left.horizontal().is_set())
{
if (left.horizontal().get() != right.horizontal().get())
{
return false;
}
}
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

View File

@ -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()) if (left.side(side).is_set() != right.side(side).is_set())
{ {
hash_string.append(std::to_string(static_cast<std::size_t>(side_type))); return false;
}
if (side(side_type))
{ if (left.side(side).is_set())
const auto side_properties = *side(side_type); {
if (left.side(side).get() != right.side(side).get())
if (side_properties.style()) {
{ return false;
hash_string.append(std::to_string(static_cast<std::size_t>(*side_properties.style()))); }
} }
else }
{
hash_string.push_back(' '); return true;
}
if (side_properties.color())
{
hash_string.append(std::to_string(std::hash<xlnt::hashable>()(*side_properties.color())));
}
else
{
hash_string.push_back(' ');
}
}
else
{
hash_string.push_back(' ');
}
hash_string.push_back(' ');
}
return hash_string;
} }
} // namespace xlnt } // namespace xlnt

View File

@ -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_)

View File

@ -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())
{
return false;
}
if (left.background().is_set())
{
if (left.background().get() != right.background().get())
{
return false;
}
}
hash_string.append(background_ ? "1" : "0"); if (left.foreground().is_set() != right.foreground().is_set())
{
if (background_) return false;
{ }
hash_string.append(std::to_string(background_->hash()));
} if (left.foreground().is_set())
{
hash_string.append(background_ ? "1" : "0"); if (left.foreground().get() != right.foreground().get())
{
if (background_) return false;
{ }
hash_string.append(std::to_string(background_->hash())); }
}
if (left.type() != right.type())
return hash_string; {
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())
{
return false;
}
if (left.type() == fill_type::gradient)
{
return left.gradient_fill() == right.gradient_fill();
}
hash_string.append(std::to_string(static_cast<std::size_t>(type_))); return left.pattern_fill() == right.pattern_fill();
switch (type_)
{
case fill_type::pattern:
hash_string.append(std::to_string(pattern_.hash()));
break;
case fill_type::gradient:
hash_string.append(std::to_string(gradient_.hash()));
break;
default:
break;
} // switch (type_)
return hash_string;
} }
} // namespace xlnt } // namespace xlnt

View File

@ -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_); if (left.color().is_set())
hash_string.append(std::to_string(size_)); {
hash_string.append(std::to_string(static_cast<std::size_t>(underline_))); if (left.color().get() != right.color().get())
hash_string.append(family_ ? std::to_string(*family_) : ""); {
hash_string.append(scheme_ ? *scheme_ : ""); return false;
}
}
return hash_string; 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

View File

@ -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

View File

@ -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

View File

@ -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);
} }
}; };

View File

@ -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")
{ {

View File

@ -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

View File

@ -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 {

View File

@ -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!");
} }
}; };

View File

@ -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)

View File

@ -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()

View File

@ -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

View File

@ -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.

View File

@ -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;
} }
} }

View File

@ -13,31 +13,48 @@ set(LIBSTUDXML
${CMAKE_CURRENT_SOURCE_DIR}/libstudxml/xml/parser.cxx ${CMAKE_CURRENT_SOURCE_DIR}/libstudxml/xml/parser.cxx
${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/genx/char-props.c ${CMAKE_CURRENT_SOURCE_DIR}/libstudxml/xml/details/expat/ascii.h
${CMAKE_CURRENT_SOURCE_DIR}/libstudxml/xml/details/genx/genx.c) ${CMAKE_CURRENT_SOURCE_DIR}/libstudxml/xml/details/expat/asciitab.h
set(POLE pole/pole.cpp) ${CMAKE_CURRENT_SOURCE_DIR}/libstudxml/xml/details/expat/config.h
set(BOTAN ${CMAKE_CURRENT_SOURCE_DIR}/botan/botan_all.cpp) ${CMAKE_CURRENT_SOURCE_DIR}/libstudxml/xml/details/expat/expat_external.h
set(ZLIB ${CMAKE_CURRENT_SOURCE_DIR}/zlib/adler32.c ${CMAKE_CURRENT_SOURCE_DIR}/libstudxml/xml/details/expat/expat.h
${CMAKE_CURRENT_SOURCE_DIR}/zlib/compress.c ${CMAKE_CURRENT_SOURCE_DIR}/libstudxml/xml/details/expat/iasciitab.h
${CMAKE_CURRENT_SOURCE_DIR}/zlib/crc32.c ${CMAKE_CURRENT_SOURCE_DIR}/libstudxml/xml/details/expat/internal.h
${CMAKE_CURRENT_SOURCE_DIR}/zlib/deflate.c ${CMAKE_CURRENT_SOURCE_DIR}/libstudxml/xml/details/expat/latin1tab.h
${CMAKE_CURRENT_SOURCE_DIR}/zlib/gzclose.c ${CMAKE_CURRENT_SOURCE_DIR}/libstudxml/xml/details/expat/nametab.h
${CMAKE_CURRENT_SOURCE_DIR}/zlib/gzlib.c ${CMAKE_CURRENT_SOURCE_DIR}/libstudxml/xml/details/expat/utf8tab.h
${CMAKE_CURRENT_SOURCE_DIR}/zlib/gzread.c ${CMAKE_CURRENT_SOURCE_DIR}/libstudxml/xml/details/expat/xmlrole.h
${CMAKE_CURRENT_SOURCE_DIR}/zlib/gzwrite.c ${CMAKE_CURRENT_SOURCE_DIR}/libstudxml/xml/details/expat/xmltok_impl.h
${CMAKE_CURRENT_SOURCE_DIR}/zlib/infback.c ${CMAKE_CURRENT_SOURCE_DIR}/libstudxml/xml/details/expat/xmltok.h)
${CMAKE_CURRENT_SOURCE_DIR}/zlib/inffast.c
${CMAKE_CURRENT_SOURCE_DIR}/zlib/inflate.c set(GENX
${CMAKE_CURRENT_SOURCE_DIR}/zlib/inftrees.c ${CMAKE_CURRENT_SOURCE_DIR}/libstudxml/xml/details/genx/char-props.c
${CMAKE_CURRENT_SOURCE_DIR}/zlib/trees.c ${CMAKE_CURRENT_SOURCE_DIR}/libstudxml/xml/details/genx/genx.c
${CMAKE_CURRENT_SOURCE_DIR}/zlib/uncompr.c ${CMAKE_CURRENT_SOURCE_DIR}/libstudxml/xml/details/genx/genx.h)
${CMAKE_CURRENT_SOURCE_DIR}/zlib/zutil.c)
set(POLE
${CMAKE_CURRENT_SOURCE_DIR}/pole/pole.cpp
${CMAKE_CURRENT_SOURCE_DIR}/pole/pole.h)
set(BOTAN
${CMAKE_CURRENT_SOURCE_DIR}/botan/botan_all.cpp
${CMAKE_CURRENT_SOURCE_DIR}/botan/botan_all_internal.h
${CMAKE_CURRENT_SOURCE_DIR}/botan/botan_all.h)
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

@ -1 +1 @@
Subproject commit 36e0ea1e407027ac48e82b56016a6813ff6a1082 Subproject commit 73c2605f50e6192bf6cb560c51d32bc53b4c5597

@ -1 +1 @@
Subproject commit 54d64e7ca405e06d2328e6207bb4752e20577e50 Subproject commit 132522ca4c895e9b07d7e323d5529474806e5829

View File

@ -355,4 +355,4 @@ namespace POLE
} // namespace POLE } // namespace POLE
#endif // POLE_H #endif // POLE_H

2
third-party/pugixml vendored

@ -1 +1 @@
Subproject commit dfe9360cdf038c0ecf53d45bfc75cf8fd34604b8 Subproject commit a832e8a5eff11f58a00ca41ec51ff3895b0da165

2
third-party/utfcpp vendored

@ -1 +1 @@
Subproject commit f029fcc2fbc7cd979925f198f7e6ca8170d45000 Subproject commit a5ad5ec9d936d63e9c010d1054f8b11fed0fabbc

2
third-party/zlib vendored

@ -1 +1 @@
Subproject commit 50893291621658f355bc5b4d450a8d06a563053d Subproject commit 94575859cf7f657f0f31aff4c50761fe3f182699