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: []
install: []
before_build:
- git submodule update --init --recursive
- cmake -H. -Bbuild -G"Visual Studio 14 2015 Win64" -DSTATIC=%STATIC%
- git submodule update --init --recursive --remote
- cmake -H. -Bbuild -G"Visual Studio 14 2015 Win64" -DSTATIC=%STATIC% -DSAMPLES=ON
build:
project: build/xlnt_all.sln

2
.gitmodules vendored
View File

@ -22,6 +22,8 @@
path = third-party/botan
url = https://github.com/randombit/botan
branch = master
[submodule "third-party/zlib"]
path = third-party/zlib
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
env:
- COMPILER=g++-4.9
- COVERAGE=ON
- os: linux
compiler: gcc
@ -35,25 +36,12 @@ matrix:
- valgrind
env:
- COMPILER=g++-5
- COVERAGE=OFF
script:
- cmake --version
- mkdir build
- cd build
- cmake -D SHARED=1 -D STATIC=0 -D WITH_TESTS=1 -D WITH_SAMPLES=1 -D CMAKE_CXX_COMPILER=$COMPILER ..
- cmake --build . --target xlnt.test
- cmake -D STATIC=ON -D SAMPLES=ON -D COVERAGE=$COVERAGE -D CMAKE_CXX_COMPILER=$COMPILER -D CMAKE_BUILD_TYPE=Debug ..
- cmake --build .
- cd bin && ./xlnt.test
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
- find .

View File

@ -19,57 +19,107 @@ xlnt is a C++14 library for reading, writing, and modifying XLSX files as descri
Summary of Features
+++++++++++++++++++
+---------------------------------------------------------------------+------+------+-------+
| Feature | Read | Edit | Write |
|---------------------------------------------------------------------|------|------|-------|
+=====================================================================+======+======+=======+
| Excel-style Workbook | ✓ | ✓ | ✓ |
+---------------------------------------------------------------------+------+------+-------+
| LibreOffice-style Workbook | ✓ | ✓ | ✓ |
+---------------------------------------------------------------------+------+------+-------+
| Numbers-style Workbook | ✓ | ✓ | ✓ |
+---------------------------------------------------------------------+------+------+-------+
| Encrypted Workbook (Excel 2007-2010) | ✓ | ✓ | |
+---------------------------------------------------------------------+------+------+-------+
| Encrypted Workbook (Excel 2013-2016) | ✓ | ✓ | |
+---------------------------------------------------------------------+------+------+-------+
| Excel Binary Workbook (.xlsb) | | | |
+---------------------------------------------------------------------+------+------+-------+
| Excel Macro-Enabled Workbook (.xlsm) | | | |
+---------------------------------------------------------------------+------+------+-------+
| Excel Macro-Enabled Template (.xltm) | | | |
+---------------------------------------------------------------------+------+------+-------+
| Document Properties | ✓ | ✓ | ✓ |
+---------------------------------------------------------------------+------+------+-------+
| Numeric Cell Values | ✓ | ✓ | ✓ |
+---------------------------------------------------------------------+------+------+-------+
| Inline String Cell Values | ✓ | ✓ | ✓ |
+---------------------------------------------------------------------+------+------+-------+
| Shared String Cell Values | ✓ | ✓ | ✓ |
+---------------------------------------------------------------------+------+------+-------+
| Shared String Text Run Formatting (e.g. varied fonts within a cell) | ✓ | ✓ | ✓ |
+---------------------------------------------------------------------+------+------+-------+
| Hyperlink Cell Values | | | |
+---------------------------------------------------------------------+------+------+-------+
| Formula Cell Values | | | |
+---------------------------------------------------------------------+------+------+-------+
| Formula Evaluation | | | |
+---------------------------------------------------------------------+------+------+-------+
| Page Margins | ✓ | ✓ | ✓ |
+---------------------------------------------------------------------+------+------+-------+
| Page Setup | | | |
+---------------------------------------------------------------------+------+------+-------+
| Print Area | | | |
| Comments | | | |
+---------------------------------------------------------------------+------+------+-------+
| Comments | ✓ | ✓ | |
+---------------------------------------------------------------------+------+------+-------+
| Header and Footer | | | |
+---------------------------------------------------------------------+------+------+-------+
| Custom Views | | | |
+---------------------------------------------------------------------+------+------+-------+
| Charts | | | |
+---------------------------------------------------------------------+------+------+-------+
| Chartsheets | | | |
+---------------------------------------------------------------------+------+------+-------+
| Dialogsheets | | | |
+---------------------------------------------------------------------+------+------+-------+
| Themes | ✓ | | ✓ |
+---------------------------------------------------------------------+------+------+-------+
| Cell Styles | ✓ | ✓ | ✓ |
+---------------------------------------------------------------------+------+------+-------+
| Cell Formats | ✓ | ✓ | ✓ |
+---------------------------------------------------------------------+------+------+-------+
| Formatting->Alignment (e.g. right align) | ✓ | ✓ | ✓ |
+---------------------------------------------------------------------+------+------+-------+
| Formatting->Border (e.g. red cell outline) | ✓ | ✓ | ✓ |
+---------------------------------------------------------------------+------+------+-------+
| Formatting->Fill (e.g. green cell background) | ✓ | ✓ | ✓ |
+---------------------------------------------------------------------+------+------+-------+
| Formatting->Font (e.g. blue cell text) | ✓ | ✓ | ✓ |
+---------------------------------------------------------------------+------+------+-------+
| Formatting->Number Format (e.g. show 2 decimals) | ✓ | ✓ | ✓ |
+---------------------------------------------------------------------+------+------+-------+
| Formatting->Protection (e.g. hide formulas) | ✓ | ✓ | ✓ |
+---------------------------------------------------------------------+------+------+-------+
| Column Styles | | | |
+---------------------------------------------------------------------+------+------+-------+
| Row Styles | | | |
+---------------------------------------------------------------------+------+------+-------+
| Sheet Styles | | | |
+---------------------------------------------------------------------+------+------+-------+
| Conditional Formatting | | | |
+---------------------------------------------------------------------+------+------+-------+
| Tables | | | |
+---------------------------------------------------------------------+------+------+-------+
| Table Formatting | | | |
+---------------------------------------------------------------------+------+------+-------+
| Pivot Tables | | | |
+---------------------------------------------------------------------+------+------+-------+
| XLSX Thumbnail | ✓ | | ✓ |
+---------------------------------------------------------------------+------+------+-------+
| Custom OOXML Properties | | | |
+---------------------------------------------------------------------+------+------+-------+
| Custom OOXML Parts | | | |
+---------------------------------------------------------------------+------+------+-------+
| Drawing | | | |
+---------------------------------------------------------------------+------+------+-------+
| Text Box | | | |
+---------------------------------------------------------------------+------+------+-------+
| WordArt | | | |
+---------------------------------------------------------------------+------+------+-------+
| Embedded Content (e.g. images) | | | |
+---------------------------------------------------------------------+------+------+-------+
| Excel VBA | | | |
+---------------------------------------------------------------------+------+------+-------+
Sample code:
++++++++++++

View File

@ -86,12 +86,6 @@ public:
/// </summary>
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>
/// Constructs a cell_reference from a 1-indexed column index and row index.
/// </summary>

View File

@ -81,12 +81,12 @@ public:
/// <summary>
/// Construct a column from a string.
/// </summary>
explicit column_t(const std::string &column_string);
column_t(const std::string &column_string);
/// <summary>
/// Construct a column from a string.
/// </summary>
explicit column_t(const char *column_string);
column_t(const char *column_string);
/// <summary>
/// Copy constructor

View File

@ -27,7 +27,6 @@
#include <xlnt/utils/hash_combine.hpp>
#include <xlnt/styles/horizontal_alignment.hpp>
#include <xlnt/styles/vertical_alignment.hpp>
#include <xlnt/utils/hashable.hpp>
#include <xlnt/utils/optional.hpp>
namespace xlnt {
@ -35,7 +34,7 @@ namespace xlnt {
/// <summary>
/// Alignment options for use in cell formats.
/// </summary>
class XLNT_API alignment : public hashable
class XLNT_API alignment
{
public:
optional<bool> shrink() const;
@ -62,8 +61,15 @@ public:
alignment &vertical(vertical_alignment vertical);
protected:
std::string to_hash_string() const override;
/// <summary>
/// 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:
optional<bool> shrink_to_fit_;

View File

@ -33,7 +33,6 @@
#include <xlnt/styles/color.hpp>
#include <xlnt/styles/diagonal_direction.hpp>
#include <xlnt/styles/side.hpp>
#include <xlnt/utils/hashable.hpp>
#include <xlnt/utils/optional.hpp>
namespace xlnt {
@ -56,7 +55,7 @@ namespace xlnt {
/// <summary>
/// Describes the border style of a particular cell.
/// </summary>
class XLNT_API border : public hashable
class XLNT_API border
{
public:
class XLNT_API border_property
@ -68,6 +67,16 @@ public:
optional<border_style> style() const;
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:
optional<class color> color_;
optional<border_style> style_;
@ -83,8 +92,15 @@ public:
optional<diagonal_direction> diagonal() const;
border &diagonal(diagonal_direction dir);
protected:
std::string to_hash_string() const override;
/// <summary>
/// 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:
optional<border_property> start_;

View File

@ -87,7 +87,7 @@ private:
/// <summary>
/// Colors can be applied to many parts of a cell's style.
/// </summary>
class XLNT_API color : public hashable
class XLNT_API color
{
public:
/// <summary>
@ -136,9 +136,6 @@ public:
bool operator==(const color &other) const;
bool operator!=(const color &other) const { return !(*this == other); }
protected:
std::string to_hash_string() const override;
private:
void assert_type(type t) const;

View File

@ -54,7 +54,7 @@ enum class XLNT_API pattern_fill_type
gray0625
};
class XLNT_API pattern_fill : public hashable
class XLNT_API pattern_fill
{
public:
pattern_fill();
@ -71,8 +71,15 @@ public:
pattern_fill &background(const color &background);
protected:
std::string to_hash_string() const override;
/// <summary>
/// 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:
pattern_fill_type type_ = pattern_fill_type::none;
@ -87,7 +94,7 @@ enum class XLNT_API gradient_fill_type
path
};
class XLNT_API gradient_fill : public hashable
class XLNT_API gradient_fill
{
public:
gradient_fill();
@ -135,8 +142,15 @@ public:
std::unordered_map<double, color> stops() const;
protected:
std::string to_hash_string() const override;
/// <summary>
/// Returns true if left is exactly equal to right.
/// </summary>
friend bool operator==(const gradient_fill &left, const gradient_fill &right);
/// <summary>
/// Returns true if left is not exactly equal to right.
/// </summary>
friend bool operator!=(const gradient_fill &left, const gradient_fill &right) { return !(left == right); }
private:
gradient_fill_type type_ = gradient_fill_type::linear;
@ -160,7 +174,7 @@ enum class XLNT_API fill_type
/// <summary>
/// Describes the fill style of a particular cell.
/// </summary>
class XLNT_API fill : public hashable
class XLNT_API fill
{
public:
/// <summary>
@ -204,8 +218,15 @@ public:
/// </summary>
class pattern_fill pattern_fill() const;
protected:
std::string to_hash_string() const override;
/// <summary>
/// Returns true if left is exactly equal to right.
/// </summary>
friend bool operator==(const fill &left, const fill &right);
/// <summary>
/// Returns true if left is not exactly equal to right.
/// </summary>
friend bool operator!=(const fill &left, const fill &right) { return !(left == right); }
private:
fill_type type_ = fill_type::pattern;

View File

@ -36,7 +36,7 @@ class style;
/// <summary>
/// Describes the font style of a particular cell.
/// </summary>
class XLNT_API font : public hashable
class XLNT_API font
{
public:
enum class underline_style
@ -92,8 +92,15 @@ public:
optional<std::string> scheme() const;
protected:
std::string to_hash_string() const override;
/// <summary>
/// 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:
friend class style;

View File

@ -27,7 +27,6 @@
#include <string>
#include <xlnt/xlnt_config.hpp>
#include <xlnt/utils/hashable.hpp>
namespace xlnt {
@ -36,7 +35,7 @@ enum class calendar;
/// <summary>
/// Describes the number formatting applied to text and numbers within a certain cell.
/// </summary>
class XLNT_API number_format : public hashable
class XLNT_API number_format
{
public:
static const number_format general();
@ -88,8 +87,16 @@ public:
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:
bool id_set_;

View File

@ -26,7 +26,6 @@
#include <cstddef>
#include <xlnt/xlnt_config.hpp>
#include <xlnt/utils/hashable.hpp>
#include <xlnt/utils/optional.hpp>
namespace xlnt {
@ -34,7 +33,7 @@ namespace xlnt {
/// <summary>
/// Describes the protection style of a particular cell.
/// </summary>
class XLNT_API protection : public hashable
class XLNT_API protection
{
public:
static protection unlocked_and_visible();
@ -50,8 +49,15 @@ public:
bool hidden() const;
protection &hidden(bool hidden);
protected:
std::string to_hash_string() const override;
/// <summary>
/// Returns true if left is exactly equal to right.
/// </summary>
friend bool operator==(const protection &left, const protection &right);
/// <summary>
/// Returns true if left is not exactly equal to right.
/// </summary>
friend bool operator!=(const protection &left, const protection &right) { return !(left == right); }
private:
bool locked_;

View File

@ -38,6 +38,8 @@ class XLNT_API exception : public std::runtime_error
{
public:
exception(const std::string &message);
exception(const exception &) = default;
virtual ~exception();
void set_message(const std::string &message);
@ -107,6 +109,8 @@ class XLNT_API invalid_column_string_index : public exception
{
public:
invalid_column_string_index();
invalid_column_string_index(const invalid_column_string_index &) = default;
~invalid_column_string_index();
};
/// <summary>
@ -117,6 +121,8 @@ class XLNT_API invalid_cell_reference : public exception
public:
invalid_cell_reference(column_t column, row_t row);
invalid_cell_reference(const std::string &reference_string);
invalid_cell_reference(const invalid_cell_reference &) = default;
~invalid_cell_reference();
};
/// <summary>
@ -126,6 +132,8 @@ class XLNT_API invalid_attribute : public exception
{
public:
invalid_attribute();
invalid_attribute(const invalid_attribute &) = default;
virtual ~invalid_attribute();
};
/// <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 <vector>
#include <utf8.h>
#include <xlnt/xlnt_config.hpp> // for XLNT_API
#include <xlnt/xlnt_config.hpp>

View File

@ -24,6 +24,7 @@
#pragma once
#include <xlnt/xlnt_config.hpp>
#include <xlnt/cell/index_types.hpp>
#include <xlnt/cell/cell_reference.hpp>
namespace xlnt {
@ -57,8 +58,8 @@ public:
cell_reference top_left_cell;
pane_state state;
pane_corner active_pane;
int y_split;
int x_split;
row_t y_split;
column_t x_split;
};
} // namespace xlnt

View File

@ -223,10 +223,10 @@ public:
range iter_cells(bool skip_null);
void add_print_title(int i);
void add_print_title(int i, const std::string &rows_or_cols);
void set_print_title_rows(const std::string &rows);
void set_print_title_cols(const std::string &rows);
void set_print_title_rows(row_t first_row, row_t last_row);
void set_print_title_rows(row_t last_row);
void set_print_title_cols(column_t first_column, column_t last_column);
void set_print_title_cols(column_t last_column);
std::string get_print_titles() const;
void set_print_area(const std::string &print_area);

View File

@ -26,28 +26,6 @@
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
#if !defined(XLNT_STATIC) && defined(_MSC_VER)
#ifdef XLNT_EXPORT

View File

@ -1,3 +1,4 @@
cmake_minimum_required(VERSION 3.1)
include(${CMAKE_CURRENT_SOURCE_DIR}/../cmake/common.cmake)
project(${LIBRARY_NAME}.samples VERSION ${LIBRARY_VERSION} LANGUAGES CXX C)
@ -7,18 +8,22 @@ endif()
include_directories(${LIBRARY_INCLUDE_DIR})
add_executable(sample-basic ${CMAKE_CURRENT_SOURCE_DIR}/sample.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})
file(GLOB SAMPLE_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp)
if(NOT MSVC)
set(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(Threads REQUIRED)
target_link_libraries(sample-basic Threads::Threads)
target_link_libraries(sample-decrypt Threads::Threads)
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
DESTINATION ${CMAKE_BINARY_DIR}/bin)

View File

@ -51,6 +51,14 @@ if(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()
if(APPLE)
# Prevent a warning about deployment target not being set
execute_process(COMMAND "sw_vers -productVersion | awk -F'.' '{print $1\".\"$2}'"
@ -68,7 +76,6 @@ include_directories(${XLNT_INCLUDE_DIR}
${THIRD_PARTY_DIR}/utfcpp/source
${THIRD_PARTY_DIR}/pole
${THIRD_PARTY_DIR}/botan
${THIRD_PARTY_DIR}/partio
${THIRD_PARTY_DIR}/zlib)
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 WORKSHEET_HEADERS ${XLNT_INCLUDE_DIR}/xlnt/worksheet/*.hpp)
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)
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)
{
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()

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)
: 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
{
//TODO: check for overflow/underflow
return cell_reference(static_cast<column_t>(static_cast<int>(column_.index) + column_offset),
static_cast<row_t>(static_cast<int>(row_) + row_offset));
auto relative_column = static_cast<column_t::index_t>(static_cast<int>(column_.index) + column_offset);
auto relative_row = static_cast<row_t>(static_cast<int>(row_) + row_offset);
return cell_reference(relative_column, relative_row);
}
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==(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); }

View File

@ -51,7 +51,7 @@ bool text_run::has_formatting() const
bool text_run::has_size() const
{
return (bool)size_;
return size_.is_set();
}
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
{
return (bool)color_;
return color_.is_set();
}
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
{
return (bool)font_;
return font_.is_set();
}
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
{
return (bool)family_;
return family_.is_set();
}
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
{
return (bool)scheme_;
return scheme_.is_set();
}
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
{
return (bool)bold_;
return bold_.is_set();
}
bool text_run::is_bold() const

View File

@ -27,12 +27,12 @@
namespace xlnt {
const row_t constants::min_row()
row_t constants::min_row()
{
return 1;
}
const row_t constants::max_row()
row_t constants::max_row()
{
return std::numeric_limits<row_t>::max();
}

View File

@ -35,12 +35,12 @@ struct XLNT_API constants
/// <summary>
/// Returns the lowest allowable row index in a worksheet.
/// </summary>
static const row_t min_row();
static row_t min_row();
/// <summary>
/// Returns the largest allowable row index in a worksheet.
/// </summary>
static const row_t max_row();
static row_t max_row();
/// <summary>
/// Returns the lowest allowable column index in a worksheet.

View File

@ -5,6 +5,8 @@
namespace xlnt {
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>{

View File

@ -25,9 +25,9 @@
#include <cmath>
#include <detail/number_formatter.hpp>
#include <xlnt/utils/exceptions.hpp>
namespace xlnt {
namespace detail {
namespace {
const std::unordered_map<int, std::string> known_locales()
{
@ -139,11 +139,30 @@ const std::unordered_map<int, std::string> known_locales()
{ 0x3409, "English - Phillippines" },
{ 0x3801, "Arabic - United Arab Emirates" },
{ 0x4001, "Arabic - Qatar" }
});
}
);
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
{
switch (type)
@ -157,10 +176,9 @@ bool format_condition::satisfied_by(long double number) const
case condition_type::less_than:
return number < value;
case condition_type::not_equal:
return number != value;
return std::fabs(number - value) >= std::numeric_limits<long double>::min();
case condition_type::equal:
default:
return number == value;
return std::fabs(number - value) < std::numeric_limits<long double>::min();
}
}
@ -336,6 +354,10 @@ void number_format_parser::parse()
part.type = template_part::template_type::elapsed_seconds;
break;
}
unhandled_case(true);
break;
case 'm':
if (token.string == "m")
{
@ -362,6 +384,10 @@ void number_format_parser::parse()
part.type = template_part::template_type::month_letter;
break;
}
unhandled_case(true);
break;
case 'd':
if (token.string == "d")
{
@ -383,6 +409,10 @@ void number_format_parser::parse()
part.type = template_part::template_type::day_name;
break;
}
unhandled_case(true);
break;
case 'y':
if (token.string == "yy")
{
@ -394,6 +424,10 @@ void number_format_parser::parse()
part.type = template_part::template_type::year_long;
break;
}
unhandled_case(true);
break;
case 'h':
if (token.string == "h")
{
@ -405,6 +439,10 @@ void number_format_parser::parse()
part.type = template_part::template_type::hour_leading_zero;
break;
}
unhandled_case(true);
break;
case 's':
if (token.string == "s")
{
@ -416,6 +454,10 @@ void number_format_parser::parse()
part.type = template_part::template_type::second_leading_zero;
break;
}
unhandled_case(true);
break;
case 'A':
section.twelve_hour = true;
@ -429,6 +471,13 @@ void number_format_parser::parse()
part.type = template_part::template_type::a_p;
break;
}
unhandled_case(true);
break;
default:
unhandled_case(true);
break;
}
section.parts.push_back(part);
@ -445,8 +494,6 @@ void number_format_parser::parse()
token = parse_next_token();
}
throw std::runtime_error("bad format");
}
void number_format_parser::finalize()
@ -805,11 +852,41 @@ number_format_token number_format_parser::parse_next_token()
break;
case '(':
token.type = number_format_token::token_type::text;
token.string.push_back(current_char);
break;
case ')':
token.type = number_format_token::token_type::text;
token.string.push_back(current_char);
break;
case '-':
token.type = number_format_token::token_type::text;
token.string.push_back(current_char);
break;
case '+':
token.type = number_format_token::token_type::text;
token.string.push_back(current_char);
break;
case ':':
token.type = number_format_token::token_type::text;
token.string.push_back(current_char);
break;
case ' ':
token.type = number_format_token::token_type::text;
token.string.push_back(current_char);
break;
case '/':
token.type = number_format_token::token_type::text;
token.string.push_back(current_char);
@ -832,6 +909,8 @@ number_format_token number_format_parser::parse_next_token()
break;
}
break;
default:
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);
}
}
unhandled_case(true);
break;
case 'B':
if (color == "Black")
{
@ -960,34 +1043,60 @@ format_color number_format_parser::color_from_string(const std::string &color)
{
return format_color::blue;
}
unhandled_case(true);
break;
case 'G':
if (color == "Green")
{
return format_color::green;
}
unhandled_case(true);
break;
case 'W':
if (color == "White")
{
return format_color::white;
}
unhandled_case(true);
break;
case 'M':
if (color == "Magenta")
{
return format_color::magenta;
}
unhandled_case(true);
break;
case 'Y':
if (color == "Yellow")
{
return format_color::yellow;
}
unhandled_case(true);
break;
case 'R':
if (color == "Red")
{
return format_color::red;
}
unhandled_case(true);
break;
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)
@ -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)
{
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))
{

View File

@ -48,39 +48,32 @@ public:
private:
int_type underflow()
{
return (position_ == static_cast<std::streampos>(data_.size()))
? traits_type::eof() : traits_type::to_int_type(data_[position_]);
if (position_ == data_.size())
{
return traits_type::eof();
}
return traits_type::to_int_type(static_cast<char>(data_[position_]));
}
int_type uflow()
{
if (position_ == static_cast<std::streampos>(data_.size()))
if (position_ == data_.size())
{
return traits_type::eof();
}
auto previous = 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_]);
return traits_type::to_int_type(static_cast<char>(data_[position_++]));
}
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,
@ -96,23 +89,56 @@ private:
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;
if (position_ > data_.size()) return -1;
return position_;
return static_cast<std::ptrdiff_t>(position_);
}
std::streampos seekpos(std::streampos sp,
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:
const std::vector<std::uint8_t> &data_;
std::streampos position_;
std::size_t position_;
};
/// <summary>
@ -141,59 +167,91 @@ private:
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)
{
if (data_.empty())
{
data_.resize(n);
data_.resize(static_cast<std::size_t>(n));
}
else
{
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));
}
std::copy(s, s + n, data_.begin() + position_);
position_ += n;
std::copy(s, s + n, data_.begin() + static_cast<std::ptrdiff_t>(position_));
position_ += static_cast<std::size_t>(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)
{
if (way == std::ios_base::beg)
{
position_ = off;
}
else if (way == std::ios_base::cur)
{
position_ += off;
position_ = 0;
}
else if (way == std::ios_base::end)
{
position_ = data_.size();
}
return (position_ < 0 || position_ > data_.size())
? std::streampos(-1) : position_;
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);
}
}
return static_cast<std::ptrdiff_t>(position_);
}
std::streampos seekpos(std::streampos sp,
std::ios_base::openmode which = std::ios_base::in | std::ios_base::out)
{
position_ = sp;
return (position_ < 0 || position_ > data_.size())
? std::streampos(-1) : position_;
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:
std::vector<std::uint8_t> &data_;
std::streampos position_;
std::size_t position_;
};
} // namespace detail

View File

@ -99,13 +99,13 @@ xlnt::color read_color(xml::parser &parser)
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;
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));
xml::parser parser(*rels_stream, part.string());
auto &rels_stream = archive.open(part.string());
xml::parser parser(rels_stream, part.string());
xlnt::uri source(part.string());
@ -152,7 +152,7 @@ xlsx_consumer::xlsx_consumer(workbook &target)
void xlsx_consumer::read(std::istream &source)
{
archive_.reset(new Partio::ZipFileReader(source));
archive_.reset(new ZipFileReader(source));
populate_workbook();
}
@ -170,8 +170,8 @@ void xlsx_consumer::populate_workbook()
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(*parser_stream, rel.get_target().get_path().string());
xml::parser parser(archive_->open(rel.get_target().get_path().string()),
rel.get_target().get_path().string());
parser_ = &parser;
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()))
{
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 receive = xml::parser::receive_default
| (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;
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()))
{
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;
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;
switch (rel.get_type())
@ -306,21 +304,17 @@ void xlsx_consumer::read_manifest()
{
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");
}
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();
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.content(xml::content::complex);
@ -355,10 +349,7 @@ void xlsx_consumer::read_manifest()
package_rel.get_id());
}
std::vector<std::string> file_list;
archive_->Get_File_List(file_list);
for (const auto &relationship_source_string : file_list)
for (const auto &relationship_source_string : archive_->files())
{
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(""),
[](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;
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;
switch (rel.get_type())

View File

@ -30,10 +30,7 @@
#include <vector>
#include <detail/include_libstudxml.hpp>
namespace Partio {
class ZipFileReader;
}
#include <detail/zip.hpp>
namespace xlnt {
@ -44,6 +41,8 @@ class worksheet;
namespace detail {
class ZipFileReader;
/// <summary>
/// Handles writing a workbook into an XLSX file.
/// </summary>
@ -218,7 +217,7 @@ private:
/// <summary>
/// The ZIP file containing the files that make up the OOXML package.
/// </summary>
std::unique_ptr<Partio::ZipFileReader> archive_;
std::unique_ptr<ZipFileReader> archive_;
/// <summary>
/// Map of sheet titles to relationship IDs.

View File

@ -33,10 +33,12 @@
namespace xlnt {
namespace detail {
static const std::size_t segment_length = 4096;
enum class cipher_algorithm
struct crypto_helper
{
static const std::size_t segment_length = 4096;
enum class cipher_algorithm
{
aes,
rc2,
rc4,
@ -44,23 +46,23 @@ enum class cipher_algorithm
desx,
triple_des,
triple_des_112
};
};
enum class cipher_chaining
{
enum class cipher_chaining
{
ecb, // electronic code book
cbc, // cipher block chaining
cfb // cipher feedback chaining
};
};
enum class cipher_direction
{
enum class cipher_direction
{
encryption,
decryption
};
};
enum class hash_algorithm
{
enum class hash_algorithm
{
sha1,
sha256,
sha384,
@ -71,13 +73,13 @@ enum class hash_algorithm
ripemd128,
ripemd160,
whirlpool
};
};
std::vector<std::uint8_t> aes(const std::vector<std::uint8_t> &key,
static std::vector<std::uint8_t> aes(const std::vector<std::uint8_t> &key,
const std::vector<std::uint8_t> &iv,
const std::vector<std::uint8_t> &encrypted,
cipher_chaining chaining, cipher_direction direction)
{
{
std::string cipher_name("AES-");
cipher_name.append(std::to_string(key.size() * 8));
cipher_name.append(chaining == cipher_chaining::ecb
@ -90,48 +92,48 @@ std::vector<std::uint8_t> aes(const std::vector<std::uint8_t> &key,
auto decrypted = pipe.read_all();
return std::vector<std::uint8_t>(decrypted.begin(), decrypted.end());
}
}
std::vector<std::uint8_t> decode_base64(const std::string &encoded)
{
static std::vector<std::uint8_t> decode_base64(const std::string &encoded)
{
Botan::Pipe pipe(new Botan::Base64_Decoder);
pipe.process_msg(encoded);
auto decoded = pipe.read_all();
return std::vector<std::uint8_t>(decoded.begin(), decoded.end());
};
};
std::vector<std::uint8_t> hash(hash_algorithm algorithm,
static std::vector<std::uint8_t> hash(hash_algorithm algorithm,
const std::vector<std::uint8_t> &input)
{
{
Botan::Pipe pipe(new Botan::Hash_Filter(
algorithm == hash_algorithm::sha512 ? "SHA-512" : "SHA-1"));
pipe.process_msg(input);
auto hash = pipe.read_all();
return std::vector<std::uint8_t>(hash.begin(), hash.end());
};
};
std::vector<std::uint8_t> get_file(POLE::Storage &storage, const std::string &name)
{
static std::vector<std::uint8_t> get_file(POLE::Storage &storage, const std::string &name)
{
POLE::Stream stream(&storage, name.c_str());
if (stream.fail()) return {};
std::vector<std::uint8_t> bytes(stream.size(), 0);
stream.read(bytes.data(), static_cast<unsigned long>(bytes.size()));
return bytes;
}
}
template<typename T>
auto read_int(std::size_t &index, const std::vector<std::uint8_t> &raw_data)
{
template<typename T>
static auto read_int(std::size_t &index, const std::vector<std::uint8_t> &raw_data)
{
auto result = *reinterpret_cast<const T *>(&raw_data[index]);
index += sizeof(T);
return result;
};
};
struct standard_encryption_info
{
struct standard_encryption_info
{
const std::size_t spin_count = 50000;
std::size_t block_size;
std::size_t key_bits;
@ -144,11 +146,11 @@ struct standard_encryption_info
std::vector<std::uint8_t> verifier_hash_input;
std::vector<std::uint8_t> verifier_hash_value;
std::vector<std::uint8_t> encrypted_key_value;
};
};
std::vector<std::uint8_t> decrypt_xlsx_standard(const std::vector<std::uint8_t> &encryption_info,
static std::vector<std::uint8_t> decrypt_xlsx_standard(const std::vector<std::uint8_t> &encryption_info,
const std::string &password, const std::vector<std::uint8_t> &encrypted_package)
{
{
std::size_t offset = 0;
standard_encryption_info info;
@ -191,8 +193,8 @@ std::vector<std::uint8_t> decrypt_xlsx_standard(const std::vector<std::uint8_t>
const auto csp_name_length = header_length - (offset - index_at_start);
std::vector<std::uint16_t> csp_name_wide(
reinterpret_cast<const std::uint16_t *>(&*(encryption_info.begin() + offset)),
reinterpret_cast<const std::uint16_t *>(&*(encryption_info.begin() + offset + csp_name_length)));
reinterpret_cast<const std::uint16_t *>(&*(encryption_info.begin() + static_cast<std::ptrdiff_t>(offset))),
reinterpret_cast<const std::uint16_t *>(&*(encryption_info.begin() + static_cast<std::ptrdiff_t>(offset + csp_name_length))));
std::string csp_name(csp_name_wide.begin(), csp_name_wide.end() - 1); // without trailing null
if (csp_name != "Microsoft Enhanced RSA and AES Cryptographic Provider (Prototype)"
&& csp_name != "Microsoft Enhanced RSA and AES Cryptographic Provider")
@ -202,18 +204,18 @@ std::vector<std::uint8_t> decrypt_xlsx_standard(const std::vector<std::uint8_t>
offset += csp_name_length;
const auto salt_size = read_int<std::uint32_t>(offset, encryption_info);
std::vector<std::uint8_t> salt(encryption_info.begin() + offset,
encryption_info.begin() + offset + salt_size);
std::vector<std::uint8_t> salt(encryption_info.begin() + static_cast<std::ptrdiff_t>(offset),
encryption_info.begin() + static_cast<std::ptrdiff_t>(offset + salt_size));
offset += salt_size;
static const auto verifier_size = std::size_t(16);
std::vector<std::uint8_t> verifier_hash_input(encryption_info.begin() + offset,
encryption_info.begin() + offset + verifier_size);
std::vector<std::uint8_t> verifier_hash_input(encryption_info.begin() + static_cast<std::ptrdiff_t>(offset),
encryption_info.begin() + static_cast<std::ptrdiff_t>(offset + verifier_size));
offset += verifier_size;
const auto verifier_hash_size = read_int<std::uint32_t>(offset, encryption_info);
std::vector<std::uint8_t> verifier_hash_value(encryption_info.begin() + offset,
encryption_info.begin() + offset + 32);
std::vector<std::uint8_t> verifier_hash_value(encryption_info.begin() + static_cast<std::ptrdiff_t>(offset),
encryption_info.begin() + static_cast<std::ptrdiff_t>(offset + verifier_hash_size));
offset += verifier_hash_size;
// begin key generation algorithm
@ -268,7 +270,7 @@ std::vector<std::uint8_t> decrypt_xlsx_standard(const std::vector<std::uint8_t>
auto X3 = X1;
X3.insert(X3.end(), X2.begin(), X2.end());
auto key_derived = std::vector<std::uint8_t>(X3.begin(), X3.begin() + info.key_bytes);
auto key_derived = std::vector<std::uint8_t>(X3.begin(), X3.begin() + static_cast<std::ptrdiff_t>(info.key_bytes));
//todo: verify here
@ -280,11 +282,10 @@ std::vector<std::uint8_t> decrypt_xlsx_standard(const std::vector<std::uint8_t>
decrypted.resize(decrypted_size);
return decrypted;
}
}
struct agile_encryption_info
{
struct agile_encryption_info
{
// key data
struct
{
@ -319,11 +320,11 @@ struct agile_encryption_info
std::vector<std::uint8_t> verifier_hash_value;
std::vector<std::uint8_t> encrypted_key_value;
} key_encryptor;
};
};
std::vector<std::uint8_t> decrypt_xlsx_agile(const std::vector<std::uint8_t> &encryption_info,
static std::vector<std::uint8_t> decrypt_xlsx_agile(const std::vector<std::uint8_t> &encryption_info,
const std::string &password, const std::vector<std::uint8_t> &encrypted_package)
{
{
static const auto xmlns = std::string("http://schemas.microsoft.com/office/2006/encryption");
static const auto xmlns_p = std::string("http://schemas.microsoft.com/office/2006/keyEncryptor/password");
static const auto xmlns_c = std::string("http://schemas.microsoft.com/office/2006/keyEncryptor/certificate");
@ -496,8 +497,10 @@ std::vector<std::uint8_t> decrypt_xlsx_agile(const std::vector<std::uint8_t> &en
iv.resize(16);
auto decrypted_segment = aes(key, iv, std::vector<std::uint8_t>(
encrypted_package.begin() + i, encrypted_package.begin() + i + segment_length),
encrypted_package.begin() + static_cast<std::ptrdiff_t>(i),
encrypted_package.begin() + static_cast<std::ptrdiff_t>(i) + segment_length),
cipher_chaining::cbc, cipher_direction::decryption);
decrypted_package.insert(decrypted_package.end(),
decrypted_segment.begin(), decrypted_segment.end());
@ -507,10 +510,10 @@ std::vector<std::uint8_t> decrypt_xlsx_agile(const std::vector<std::uint8_t> &en
decrypted_package.resize(total_size);
return decrypted_package;
}
}
std::vector<std::uint8_t> decrypt_xlsx(const std::vector<std::uint8_t> &bytes, const std::string &password)
{
static std::vector<std::uint8_t> decrypt_xlsx(const std::vector<std::uint8_t> &bytes, const std::string &password)
{
if (bytes.empty())
{
throw xlnt::exception("empty file");
@ -534,7 +537,8 @@ std::vector<std::uint8_t> decrypt_xlsx(const std::vector<std::uint8_t> &bytes, c
auto encryption_flags = read_int<std::uint32_t>(index, encryption_info);
// get rid of header
encryption_info.erase(encryption_info.begin(), encryption_info.begin() + index);
encryption_info.erase(encryption_info.begin(),
encryption_info.begin() + static_cast<std::ptrdiff_t>(index));
// version 4.4 is agile
if (version_major == 4 && version_minor == 4)
@ -571,13 +575,14 @@ std::vector<std::uint8_t> decrypt_xlsx(const std::vector<std::uint8_t> &bytes, c
}
return decrypt_xlsx_standard(encryption_info, password, encrypted_package);
}
}
};
void xlsx_consumer::read(std::istream &source, const std::string &password)
{
std::vector<std::uint8_t> data((std::istreambuf_iterator<char>(source)),
(std::istreambuf_iterator<char>()));
const auto decrypted = decrypt_xlsx(data, password);
const auto decrypted = crypto_helper::decrypt_xlsx(data, password);
vector_istreambuf decrypted_buffer(decrypted);
std::istream decrypted_stream(&decrypted_buffer);
read(decrypted_stream);

View File

@ -24,10 +24,12 @@
#include <numeric> // for std::accumulate
#include <string>
#include <detail/custom_value_traits.hpp>
#include <detail/xlsx_producer.hpp>
#include <detail/constants.hpp>
#include <detail/custom_value_traits.hpp>
#include <detail/vector_streambuf.hpp>
#include <detail/workbook_impl.hpp>
#include <detail/xlsx_producer.hpp>
#include <detail/zip.hpp>
#include <xlnt/cell/cell.hpp>
#include <xlnt/utils/path.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)
{
Partio::ZipFileWriter archive(destination);
ZipFileWriter archive(destination);
archive_ = &archive;
populate_archive();
}
@ -100,6 +102,13 @@ void xlsx_producer::populate_archive()
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());
switch (rel.get_type())
@ -120,10 +129,6 @@ void xlsx_producer::populate_archive()
write_workbook(rel);
break;
case relationship::type::thumbnail:
write_thumbnail(rel);
break;
default:
break;
}
@ -154,7 +159,7 @@ void xlsx_producer::begin_part(const path &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()));
}
@ -2498,11 +2503,12 @@ void xlsx_producer::write_unknown_relationships()
void xlsx_producer::write_thumbnail(const relationship &rel)
{
end_part();
const auto &thumbnail = source_.get_thumbnail();
std::unique_ptr<std::ostream> thumbnail_stream(
archive_->Add_File(rel.get_target().get_path().string(), true));
std::for_each(thumbnail.begin(), thumbnail.end(),
[&thumbnail_stream](std::uint8_t b) { *thumbnail_stream << b; });
current_part_stream_.reset(archive_->open(rel.get_target().get_path().string()));
vector_istreambuf thumbnail_buffer(thumbnail);
*current_part_stream_ << &thumbnail_buffer;
}
xml::serializer &xlsx_producer::serializer()

View File

@ -28,11 +28,6 @@
#include <vector>
#include <detail/include_libstudxml.hpp>
#include <detail/zip.hpp>
namespace Partio {
class ZipFileWriter;
}
namespace xml {
class serializer;
@ -49,6 +44,8 @@ class worksheet;
namespace detail {
class ZipFileWriter;
/// <summary>
/// Handles writing a workbook into an XLSX file.
/// </summary>
@ -138,7 +135,7 @@ private:
/// </summary>
const workbook &source_;
Partio::ZipFileWriter *archive_;
ZipFileWriter *archive_;
std::unique_ptr<std::ostream> current_part_stream_;
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.
*/
extern "C"{
#include <zlib.h>
}
#include <algorithm>
#include <cassert>
#include <fstream>
@ -46,123 +42,129 @@ extern "C"{
#include <cstring>
#include <string>
#include <zlib.h>
#include <detail/zip.hpp>
namespace Partio{
namespace xlnt {
namespace detail {
template<class T>
inline void Swap_Endianity(T& x)
inline T read_int(std::istream &stream)
{
assert(sizeof(T)<=8);
if(sizeof(T)>1) {
T old=x;
for(unsigned int k=1;k<=sizeof(T);k++) ((char*)&x)[k-1]=((char*)&old)[sizeof(T)-k];
}
T value;
stream.read(reinterpret_cast<char *>(&value), sizeof(T));
return value;
}
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>
inline void Write_Primitive(std::ostream& stream,const T& x)
struct zip_file_header
{
stream.write(&(char&)x,sizeof(T));
}
//#####################################################################
// class ZipFileHeader
//#####################################################################
struct ZipFileHeader
{
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::uint16_t version = 20;
std::uint16_t flags = 0;
std::uint16_t compression_type = 8;
std::uint16_t stamp_date,stamp_time = 0;
std::uint32_t crc = 0;
std::uint32_t compressed_size = 0;
std::uint32_t uncompressed_size = 0;
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)
: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)
{}
bool read(std::istream& istream,const bool global)
{
auto sig = read_int<std::uint32_t>(istream);
bool Read(std::istream& istream,const bool global)
{unsigned int sig;
unsigned short version,flags;
// read and check for local/global magic
if(global){
Read_Primitive(istream,sig);
if(sig!=0x02014b50){std::cerr<<"Did not find global header signature"<<std::endl;return false;}
Read_Primitive(istream,version);}
else{
Read_Primitive(istream,sig);
if(sig!=0x04034b50){std::cerr<<"Did not find local header signature"<<std::endl;return false;}}
if(global)
{
if(sig!=0x02014b50)
{
std::cerr<<"Did not find global header signature"<<std::endl;
return false;
}
version = read_int<std::uint16_t>(istream);
}
else if(sig!=0x04034b50)
{
std::cerr<<"Did not find local header signature"<<std::endl;
return false;
}
// Read rest of header
Read_Primitive(istream,version);
Read_Primitive(istream,flags);
Read_Primitive(istream,compression_type);
Read_Primitive(istream,stamp_date);
Read_Primitive(istream,stamp_time);
Read_Primitive(istream,crc);
Read_Primitive(istream,compressed_size);
Read_Primitive(istream,uncompressed_size);
unsigned short filename_length,extra_length;
Read_Primitive(istream,filename_length);
Read_Primitive(istream,extra_length);
unsigned short comment_length=0;
if(global){
Read_Primitive(istream,comment_length); // filecomment
unsigned short disk_number_start,int_file_attrib;
unsigned int ext_file_attrib;
Read_Primitive(istream,disk_number_start); // disk# start
Read_Primitive(istream,int_file_attrib); // internal file
Read_Primitive(istream,ext_file_attrib); // ext final
Read_Primitive(istream,header_offset);} // rel offset
char* buf=new char[std::max(comment_length,std::max(filename_length,extra_length))+1];
istream.read(buf,filename_length);
buf[filename_length]=0;
filename=std::string(buf, buf + filename_length);
istream.read(buf,extra_length);
if(global) istream.read(buf,comment_length);
delete [] buf;
return true;}
version = read_int<std::uint16_t>(istream);
flags = read_int<std::uint16_t>(istream);
compression_type = read_int<std::uint16_t>(istream);
stamp_date = read_int<std::uint16_t>(istream);
stamp_time = read_int<std::uint16_t>(istream);
crc = read_int<std::uint32_t>(istream);
compressed_size = read_int<std::uint32_t>(istream);
uncompressed_size = read_int<std::uint32_t>(istream);
auto filename_length = read_int<std::uint16_t>(istream);
auto extra_length = read_int<std::uint16_t>(istream);
std::uint16_t comment_length = 0;
if(global)
{
comment_length = read_int<std::uint16_t>(istream);
/*std::uint16_t disk_number_start = */read_int<std::uint16_t>(istream);
/*std::uint16_t int_file_attrib = */read_int<std::uint16_t>(istream);
/*std::uint32_t ext_file_attrib = */read_int<std::uint32_t>(istream);
header_offset = read_int<std::uint32_t>(istream);
}
filename.resize(filename_length, '\0');
istream.read(&filename[0], filename_length);
extra.resize(extra_length, 0);
istream.read(reinterpret_cast<char *>(extra.data()), extra_length);
if (global)
{
comment.resize(comment_length, '\0');
istream.read(&comment[0], comment_length);
}
return true;
}
void Write(std::ostream& ostream,const bool global) const
{if(global){
Write_Primitive(ostream,(unsigned int)0x02014b50); // header sig
Write_Primitive(ostream,(unsigned short)00);} // version made by
else Write_Primitive(ostream,(unsigned int)0x04034b50);
Write_Primitive(ostream,version);
Write_Primitive(ostream,flags);
Write_Primitive(ostream,compression_type);
Write_Primitive(ostream,stamp_date);
Write_Primitive(ostream,stamp_time);
Write_Primitive(ostream,crc);
Write_Primitive(ostream,compressed_size);
Write_Primitive(ostream,uncompressed_size);
Write_Primitive(ostream,(unsigned short)filename.length());
Write_Primitive(ostream,(unsigned short)0); // extra lengthx
write_int(ostream,(unsigned int)0x02014b50); // header sig
write_int(ostream,(unsigned short)00);} // version made by
else write_int(ostream,(unsigned int)0x04034b50);
write_int(ostream,version);
write_int(ostream,flags);
write_int(ostream,compression_type);
write_int(ostream,stamp_date);
write_int(ostream,stamp_time);
write_int(ostream,crc);
write_int(ostream,compressed_size);
write_int(ostream,uncompressed_size);
write_int(ostream,(unsigned short)filename.length());
write_int(ostream,(unsigned short)0); // extra lengthx
if(global){
Write_Primitive(ostream,(unsigned short)0); // filecomment
Write_Primitive(ostream,(unsigned short)0); // disk# start
Write_Primitive(ostream,(unsigned short)0); // internal file
Write_Primitive(ostream,(unsigned int)0); // ext final
Write_Primitive(ostream,(unsigned int)header_offset);} // rel offset
for(unsigned int i=0;i<filename.length();i++) Write_Primitive(ostream,filename.c_str()[i]);}
//#####################################################################
write_int(ostream,(unsigned short)0); // filecomment
write_int(ostream,(unsigned short)0); // disk# start
write_int(ostream,(unsigned short)0); // internal file
write_int(ostream,(unsigned int)0); // ext final
write_int(ostream,(unsigned int)header_offset);} // rel offset
for(unsigned int i=0;i<filename.length();i++) write_int(ostream,filename.c_str()[i]);}
};
//#####################################################################
// class ZipStreambufDecompress
//#####################################################################
class ZipStreambufDecompress:public std::streambuf
{
static const unsigned int buffer_size=512;
@ -170,23 +172,23 @@ class ZipStreambufDecompress:public std::streambuf
z_stream strm;
unsigned char in[buffer_size],out[buffer_size];
ZipFileHeader header;
zip_file_header header;
int total_read,total_uncompressed;
bool own_istream;
//bool own_istream;
bool valid;
bool compressed_data;
static const unsigned short DEFLATE=8;
static const unsigned short UNCOMPRESSED=0;
public:
ZipStreambufDecompress(std::istream& stream,ZipFileHeader central_header)
:istream(stream),total_read(0),total_uncompressed(0),valid(true),header(central_header)
ZipStreambufDecompress(std::istream& stream,zip_file_header central_header)
:istream(stream),header(central_header),total_read(0),total_uncompressed(0),valid(true)
{
strm.zalloc=Z_NULL;strm.zfree=Z_NULL;strm.opaque=Z_NULL;strm.avail_in=0;strm.next_in=Z_NULL;
setg((char*)in,(char*)in,(char*)in);
setp(0,0);
// skip the header
valid=header.Read(istream,false);
valid=header.read(istream,false);
if(header.compression_type==DEFLATE) compressed_data=true;
else if(header.compression_type==UNCOMPRESSED) compressed_data=false;
else{
@ -246,13 +248,8 @@ public:
virtual int overflow(int c=EOF)
{assert(false);return EOF;}
//#####################################################################
};
//#####################################################################
// class ZipStreambufCompress
//#####################################################################
class ZipStreambufCompress:public std::streambuf
{
static const int buffer_size=512;
@ -261,16 +258,15 @@ class ZipStreambufCompress:public std::streambuf
z_stream strm;
unsigned char in[buffer_size],out[buffer_size];
ZipFileHeader* header;
unsigned int header_offset;
zip_file_header* header;
unsigned int uncompressed_size;
unsigned int crc;
bool valid;
public:
ZipStreambufCompress(ZipFileHeader* header,std::ostream& stream)
:ostream(stream),header(header),valid(true)
ZipStreambufCompress(zip_file_header* central_header,std::ostream& stream)
:ostream(stream),header(central_header),valid(true)
{
strm.zalloc=Z_NULL;strm.zfree=Z_NULL;strm.opaque=Z_NULL;
int ret=deflateInit2(&strm,Z_DEFAULT_COMPRESSION,Z_DEFLATED,-MAX_WBITS,8,Z_DEFAULT_STRATEGY);
@ -293,7 +289,7 @@ public:
ostream.seekp(header->header_offset);
header->Write(ostream,false);
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;}
protected:
@ -329,174 +325,189 @@ protected:
{if(c!=EOF){*pptr()=c;pbump(1);}
if(process(false)==EOF) return EOF;
return c;}
//#####################################################################
};
//#####################################################################
// Class ZIP_FILE_ISTREAM
//#####################################################################
// Class needed because istream cannot own its streambuf
class ZIP_FILE_ISTREAM:public std::istream
{
ZipStreambufDecompress buf;
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)
{}
{
}
virtual ~ZIP_FILE_ISTREAM()
{}
//#####################################################################
{
}
};
//#####################################################################
// Class ZIP_FILE_OSTREAM
//#####################################################################
// Class needed because ostream cannot own its streambuf
class ZIP_FILE_OSTREAM:public std::ostream
{
ZipStreambufCompress buf;
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)
{}
{
}
virtual ~ZIP_FILE_OSTREAM()
{}
//#####################################################################
{
}
};
//#####################################################################
// Function ZipFileWriter
//#####################################################################
ZipFileWriter::
ZipFileWriter(std::ostream& stream) : ostream(stream)
ZipFileWriter::ZipFileWriter(std::ostream& stream) : target_stream_(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
std::ios::streampos final_position=ostream.tellp();
for(unsigned int i=0;i<files.size();i++){files[i]->Write(ostream,true);delete files[i];}
std::ios::streampos central_end=ostream.tellp();
std::ios::streampos final_position=target_stream_.tellp();
for(unsigned int i=0;i<file_headers_.size();i++)
{
file_headers_[i].Write(target_stream_,true);
}
std::ios::streampos central_end=target_stream_.tellp();
// Write end of central
Write_Primitive(ostream,(unsigned int)0x06054b50); // end of central
Write_Primitive(ostream,(unsigned short)0); // this disk number
Write_Primitive(ostream,(unsigned short)0); // this disk number
Write_Primitive(ostream,(unsigned short)files.size()); // one entry in center in this disk
Write_Primitive(ostream,(unsigned short)files.size()); // one entry in center
Write_Primitive(ostream,(unsigned int)(central_end-final_position)); // size of header
Write_Primitive(ostream,(unsigned int)final_position); // offset to header
Write_Primitive(ostream,(unsigned short)0); // zip comment
write_int(target_stream_,(unsigned int)0x06054b50); // end of central
write_int(target_stream_,(unsigned short)0); // this disk number
write_int(target_stream_,(unsigned short)0); // this disk number
write_int(target_stream_,(unsigned short)file_headers_.size()); // one entry in center in this disk
write_int(target_stream_,(unsigned short)file_headers_.size()); // one entry in center
write_int(target_stream_,(unsigned int)(central_end - final_position)); // size of header
write_int(target_stream_,(unsigned int)final_position); // offset to header
write_int(target_stream_,(unsigned short)0); // zip comment
}
//#####################################################################
// Function ZipFileWriter
//#####################################################################
std::ostream* ZipFileWriter::
Add_File(const std::string& filename,const bool binary)
std::ostream* ZipFileWriter::open(const std::string& filename)
{
files.push_back(new ZipFileHeader(filename));
return new ZIP_FILE_OSTREAM(files.back(),ostream);
zip_file_header header;
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) : istream(stream)
ZipFileReader::ZipFileReader(std::istream &stream) : source_stream_(stream)
{
if(!istream) throw std::runtime_error("ZIP: Invalid file handle");
Find_And_Read_Central_Header();
if(!stream)
{
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::
Find_And_Read_Central_Header()
bool ZipFileReader::read_central_header()
{
// Find the header
// NOTE: this assumes the zip file header is the last thing written to file...
istream.seekg(0,std::ios_base::end);
std::ios::streampos end_position=istream.tellg();
unsigned int max_comment_size=0xffff; // max size of header
unsigned int read_size_before_comment=22;
source_stream_.seekg(0,std::ios_base::end);
std::ios::streampos end_position=source_stream_.tellg();
auto max_comment_size = std::uint32_t(0xffff); // max size of header
auto read_size_before_comment = std::uint32_t(22);
std::ios::streamoff read_start=max_comment_size+read_size_before_comment;
if(read_start>end_position) read_start=end_position;
istream.seekg(end_position-read_start);
char *buf=new char[read_start];
source_stream_.seekg(end_position-read_start);
std::vector<char> buf(static_cast<std::size_t>(read_start), '\0');
if(read_start<=0){std::cerr<<"ZIP: Invalid read buffer size"<<std::endl;return false;}
istream.read(buf,read_start);
int found=-1;
for(unsigned int i=0;i<read_start-3;i++){
if(buf[i]==0x50 && buf[i+1]==0x4b && buf[i+2]==0x05 && buf[i+3]==0x06){found=i;break;}}
delete [] buf;
if(found==-1){std::cerr<<"ZIP: Failed to find zip header"<<std::endl;return false;}
source_stream_.read(buf.data(), read_start);
auto found_header = false;
std::size_t header_index = 0;
for(std::size_t i = 0; i < read_start - 3; ++i)
{
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
istream.seekg(end_position-(read_start-found));
unsigned int word;
unsigned short disk_number1,disk_number2,num_files,num_files_this_disk;
Read_Primitive(istream,word); // end of central
Read_Primitive(istream,disk_number1); // this disk number
Read_Primitive(istream,disk_number2); // this disk number
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
Read_Primitive(istream,num_files_this_disk); // one entry in center
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;
Read_Primitive(istream,size_of_header); // size of header
Read_Primitive(istream,header_offset); // offset to header
source_stream_.seekg(end_position - (read_start - static_cast<std::ptrdiff_t>(header_index)));
/*auto word = */read_int<std::uint32_t>(source_stream_);
auto disk_number1 = read_int<std::uint16_t>(source_stream_);
auto disk_number2 = read_int<std::uint16_t>(source_stream_);
if(disk_number1 != disk_number2 || disk_number1 != 0)
{
std::cerr<<"ZIP: multiple disk zip files are not supported"<<std::endl;
return false;
}
auto num_files = read_int<std::uint16_t>(source_stream_); // one entry in center in this disk
auto num_files_this_disk = read_int<std::uint16_t>(source_stream_); // one entry in center
if(num_files != num_files_this_disk)
{
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
istream.seekg(header_offset);
for(int i=0;i<num_files;i++){
ZipFileHeader* header=new ZipFileHeader;
bool valid=header->Read(istream,true);
if(valid) filename_to_header[header->filename]=header;}
source_stream_.seekg(header_offset);
for (std::uint16_t i = 0; i < num_files; ++i)
{
zip_file_header header;
if (header.read(source_stream_, true))
{
file_headers_[header.filename] = header;
}
}
return true;
}
//#####################################################################
// Function Get_File
//#####################################################################
std::istream* ZipFileReader::Get_File(const std::string& filename,const bool binary)
std::istream &ZipFileReader::open(const std::string &filename)
{
std::map<std::string,ZipFileHeader*>::iterator i=filename_to_header.find(filename);
if(i!=filename_to_header.end()){
ZipFileHeader* header=i->second;
istream.seekg((*header).header_offset);return new ZIP_FILE_ISTREAM(istream,*header);
if (!has_file(filename))
{
throw "not found";
}
return 0;
}
//#####################################################################
// Function Get_File_List
//#####################################################################
void ZipFileReader::Get_File_List(std::vector<std::string>& filenames) const
{
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();
auto header = file_headers_.at(filename);
source_stream_.seekg(header.header_offset);
read_stream_.reset(new ZIP_FILE_ISTREAM(source_stream_, header));
return *read_stream_;
}
} // 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.
*/
#ifndef __ZIP__
#define __ZIP__
#pragma once
#include <fstream>
#include <iostream>
#include <map>
#include <stdexcept>
#include <memory>
#include <unordered_map>
#include <vector>
namespace Partio{
struct ZipFileHeader;
//#####################################################################
// Functions Gzip_Out/Gzip_In - Create streams that read/write .gz
//#####################################################################
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
//#####################################################################
namespace xlnt {
namespace detail {
struct zip_file_header;
class ZipFileWriter
{
std::ostream &ostream;
std::vector<ZipFileHeader*> files;
public:
//#####################################################################
ZipFileWriter(std::ostream &filename);
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
{
std::istream &istream;
public:
std::map<std::string,ZipFileHeader*> filename_to_header;
//#####################################################################
ZipFileReader(std::istream &stream);
virtual ~ZipFileReader();
std::istream* Get_File(const std::string& filename,const bool binary=true);
void Get_File_List(std::vector<std::string>& filenames) const;
bool Has_File(const std::string &filename) const;
std::istream &open(const std::string &filename);
std::vector<std::string> files() const;
bool has_file(const std::string &filename) const;
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

@ -92,18 +92,87 @@ optional<int> alignment::rotation() const
return text_rotation_;
}
std::string alignment::to_hash_string() const
bool operator==(const alignment &left, const alignment &right)
{
std::string hash_string;
if (left.horizontal().is_set() != right.horizontal().is_set())
{
return false;
}
hash_string.append(wrap_text_ ? "1" : "0");
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_));
if (left.horizontal().is_set())
{
if (left.horizontal().get() != right.horizontal().get())
{
return false;
}
}
return hash_string;
if (left.indent().is_set() != right.indent().is_set())
{
return false;
}
if (left.indent().is_set())
{
if (left.indent().get() != right.indent().get())
{
return false;
}
}
if (left.rotation().is_set() != right.rotation().is_set())
{
return false;
}
if (left.rotation().is_set())
{
if (left.rotation().get() != right.rotation().get())
{
return false;
}
}
if (left.shrink().is_set() != right.shrink().is_set())
{
return false;
}
if (left.shrink().is_set())
{
if (left.shrink().get() != right.shrink().get())
{
return false;
}
}
if (left.vertical().is_set() != right.vertical().is_set())
{
return false;
}
if (left.vertical().is_set())
{
if (left.vertical().get() != right.vertical().get())
{
return false;
}
}
if (left.wrap().is_set() != right.wrap().is_set())
{
return false;
}
if (left.wrap().is_set())
{
if (left.wrap().get() != right.wrap().get())
{
return false;
}
}
return true;
}
} // namespace xlnt

View File

@ -49,6 +49,38 @@ border::border_property &border::border_property::style(border_style s)
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()
{
}
@ -112,45 +144,25 @@ optional<diagonal_direction> border::diagonal() const
return diagonal_direction_;
}
std::string border::to_hash_string() const
bool operator==(const border &left, const border &right)
{
std::string hash_string;
for (const auto &side_type : all_sides())
for (auto side : border::all_sides())
{
hash_string.append(std::to_string(static_cast<std::size_t>(side_type)));
if (side(side_type))
if (left.side(side).is_set() != right.side(side).is_set())
{
const auto side_properties = *side(side_type);
if (side_properties.style())
{
hash_string.append(std::to_string(static_cast<std::size_t>(*side_properties.style())));
}
else
{
hash_string.push_back(' ');
return false;
}
if (side_properties.color())
if (left.side(side).is_set())
{
hash_string.append(std::to_string(std::hash<xlnt::hashable>()(*side_properties.color())));
}
else
if (left.side(side).get() != right.side(side).get())
{
hash_string.push_back(' ');
return false;
}
}
else
{
hash_string.push_back(' ');
}
hash_string.push_back(' ');
}
return hash_string;
return true;
}
} // namespace xlnt

View File

@ -206,32 +206,6 @@ void color::set_tint(double 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
{
if (t != type_)

View File

@ -72,25 +72,40 @@ pattern_fill &pattern_fill::background(const color &new_background)
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";
hash_string.append(background_ ? "1" : "0");
if (background_)
if (left.background().is_set() != right.background().is_set())
{
hash_string.append(std::to_string(background_->hash()));
return false;
}
hash_string.append(background_ ? "1" : "0");
if (background_)
if (left.background().is_set())
{
hash_string.append(std::to_string(background_->hash()));
if (left.background().get() != right.background().get())
{
return false;
}
}
return hash_string;
if (left.foreground().is_set() != right.foreground().is_set())
{
return false;
}
if (left.foreground().is_set())
{
if (left.foreground().get() != right.foreground().get())
{
return false;
}
}
if (left.type() != right.type())
{
return false;
}
return true;
}
// gradient_fill
@ -166,21 +181,6 @@ gradient_fill &gradient_fill::bottom(double value)
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)
{
stops_[position] = stop_color;
@ -198,6 +198,46 @@ std::unordered_map<double, color> gradient_fill::stops() const
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::solid(const color &fill_color)
@ -249,27 +289,19 @@ pattern_fill fill::pattern_fill() const
return pattern_;
}
std::string fill::to_hash_string() const
bool operator==(const fill &left, const fill &right)
{
std::string hash_string = "fill";
hash_string.append(std::to_string(static_cast<std::size_t>(type_)));
switch (type_)
if (left.type() != right.type())
{
case fill_type::pattern:
hash_string.append(std::to_string(pattern_.hash()));
break;
return false;
}
case fill_type::gradient:
hash_string.append(std::to_string(gradient_.hash()));
break;
if (left.type() == fill_type::gradient)
{
return left.gradient_fill() == right.gradient_fill();
}
default:
break;
} // switch (type_)
return hash_string;
return left.pattern_fill() == right.pattern_fill();
}
} // namespace xlnt

View File

@ -153,22 +153,83 @@ optional<std::string> font::scheme() const
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_));
hash_string.append(std::to_string(italic_));
hash_string.append(std::to_string(superscript_));
hash_string.append(std::to_string(subscript_));
hash_string.append(std::to_string(strikethrough_));
hash_string.append(name_);
hash_string.append(std::to_string(size_));
hash_string.append(std::to_string(static_cast<std::size_t>(underline_)));
hash_string.append(family_ ? std::to_string(*family_) : "");
hash_string.append(scheme_ ? *scheme_ : "");
if (left.color().is_set() != right.color().is_set())
{
return false;
}
return hash_string;
if (left.color().is_set())
{
if (left.color().get() != right.color().get())
{
return false;
}
}
if (left.family().is_set() != right.family().is_set())
{
return false;
}
if (left.family().is_set())
{
if (left.family().get() != right.family().get())
{
return false;
}
}
if (left.italic() != right.italic())
{
return false;
}
if (left.name() != right.name())
{
return false;
}
if (left.scheme().is_set() != right.scheme().is_set())
{
return false;
}
if (left.scheme().is_set())
{
if (left.scheme().get() != right.scheme().get())
{
return false;
}
}
if (left.size() != right.size())
{
return false;
}
if (left.strikethrough() != right.strikethrough())
{
return false;
}
if (left.superscript() != right.superscript())
{
return false;
}
if (left.underline() != right.underline())
{
return false;
}
return true;
}
} // namespace xlnt

View File

@ -273,17 +273,6 @@ std::string number_format::get_format_string() const
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)
{
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);
}
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

View File

@ -52,14 +52,9 @@ protection &protection::hidden(bool hidden)
return *this;
}
std::string protection::to_hash_string() const
bool operator==(const protection &left, const protection &right)
{
std::string hash_string = "protection";
hash_string.append(locked_ ? "1" : "0");
hash_string.append(hidden_ ? "1" : "0");
return hash_string;
return left.locked_ == right.locked_ && left.hidden_ == right.hidden_;
}
} // namespace xlnt

View File

@ -43,14 +43,14 @@ public:
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 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);
TS_ASSERT_DIFFERS(pattern_fill.hash(), gradient_fill_linear.hash());
TS_ASSERT_DIFFERS(gradient_fill_linear.hash(), gradient_fill_path.hash());
TS_ASSERT_DIFFERS(gradient_fill_path.hash(), pattern_fill.hash());
TS_ASSERT_DIFFERS(pattern_fill, gradient_fill_linear);
TS_ASSERT_DIFFERS(gradient_fill_linear, gradient_fill_path);
TS_ASSERT_DIFFERS(gradient_fill_path, pattern_fill);
}
};

View File

@ -32,6 +32,10 @@ exception::exception(const std::string &message)
set_message(message);
}
exception::~exception()
{
}
void exception::set_message(const std::string &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()
: 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)
: 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()
: 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
// @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>
namespace xlnt {

View File

@ -70,6 +70,10 @@ public:
#ifdef WIN32
xlnt::workbook wb;
wb.load(L"data\\19_unicode_Λ.xlsx");
#else
xlnt::workbook wb;
wb.load("data/19_unicode_Λ.xlsx");
#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();
}
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)

View File

@ -521,11 +521,11 @@ public:
xlnt::workbook wb;
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");
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");
}
@ -534,17 +534,17 @@ public:
xlnt::workbook wb;
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");
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");
auto ws3 = wb.create_sheet();
ws3.set_print_title_rows("1:2");
ws3.set_print_title_cols("C:D");
TS_ASSERT_EQUALS(ws3.get_print_titles(), "Sheet3!1:2,Sheet3!C:D");
ws3.set_print_title_rows(2, 3);
ws3.set_print_title_cols("C", "D");
TS_ASSERT_EQUALS(ws3.get_print_titles(), "Sheet3!2:3,Sheet3!C:D");
}
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)
{
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);
}
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")
{
set_print_title_cols("A:" + column_t::column_string_from_index(i));
}
else
{
set_print_title_rows("1:" + std::to_string(i));
}
d_->print_title_rows_ = std::to_string(first_row) + ":" + std::to_string(last_row);
}
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

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 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}
${FORMULA_TESTS} ${PACKAGING_TESTS} ${STYLES_TESTS} ${UTILS_TESTS}
${WORKBOOK_TESTS} ${WORKSHEET_TESTS})
set(PUGIXML ${THIRD_PARTY_DIR}/pugixml/src/pugixml.cpp)
file(GLOB TEST_HELPERS_HEADERS ${XLNT_TESTS_DIR}/helpers/*.hpp)
file(GLOB TEST_HELPERS_SOURCES ${XLNT_TESTS_DIR}/helpers/*.cpp)
set(PUGIXML
${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})
@ -42,9 +48,11 @@ file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/tests")
set(RUNNER "${CMAKE_CURRENT_BINARY_DIR}/runner-autogen.cpp")
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(xlnt\\detail FILES ${XLNT_ZIP})
source_group(third-party\\pugixml FILES ${PUGIXML})
source_group(tests\\cell FILES ${CELL_TESTS})
source_group(tests\\charts FILES ${CHARTS_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;
wb.save(bytes);
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);
}
@ -287,33 +287,32 @@ public:
std::vector<std::uint8_t> bytes;
wb.save(bytes);
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);
}
static bool string_matches_archive_member(const std::string &expected,
Partio::ZipFileReader &archive,
xlnt::detail::ZipFileReader &archive,
const xlnt::path &member,
const std::string &content_type)
{
auto stream = archive.Get_File(member.string(), true);
std::string contents((std::istreambuf_iterator<char>(*stream)), (std::istreambuf_iterator<char>()));
delete stream;
auto &stream = archive.open(member.string());
std::string contents((std::istreambuf_iterator<char>(stream)), (std::istreambuf_iterator<char>()));
return compare_files(expected, contents, content_type);
}
static bool file_matches_archive_member(const xlnt::path &file,
Partio::ZipFileReader &archive,
xlnt::detail::ZipFileReader &archive,
const xlnt::path &member,
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;
xlnt::detail::vector_ostreambuf member_data_buffer(member_data);
std::ostream member_data_stream(&member_data_buffer);
std::unique_ptr<std::istream> member_stream(archive.Get_File(member.string(), true));
member_data_stream << member_stream->rdbuf();
auto &member_stream = archive.open(member.string());
member_data_stream << member_stream.rdbuf();
std::string contents(member_data.begin(), member_data.end());
return compare_files(file.read_contents(), contents, content_type);
}
@ -337,15 +336,15 @@ public:
{
xlnt::detail::vector_istreambuf left_buffer(left);
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);
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())
{
@ -354,14 +353,14 @@ public:
std::cout << "left has: ";
for (auto &info : left_info)
{
std::cout << info.first << ", ";
std::cout << info << ", ";
}
std::cout << std::endl;
std::cout << "right has: ";
for (auto &info : right_info)
{
std::cout << info.first << ", ";
std::cout << info << ", ";
}
std::cout << std::endl;
}
@ -379,33 +378,33 @@ public:
for (auto left_member : left_info)
{
if (!right_archive.Has_File(left_member.first))
if (!right_archive.has_file(left_member))
{
match = false;
std::cout << "right is missing file: " << left_member.first << std::endl;
std::cout << "right is missing file: " << left_member << std::endl;
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;
xlnt::detail::vector_ostreambuf left_contents_buffer(left_contents_raw);
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::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;
xlnt::detail::vector_ostreambuf right_contents_buffer(right_contents_raw);
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 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));
right_content_type = right_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));
}
else
{
@ -415,7 +414,7 @@ public:
if (left_content_type != right_content_type)
{
std::cout << "content types differ: "
<< left_member.first
<< left_member
<< " "
<< left_content_type
<< " "
@ -425,7 +424,7 @@ public:
}
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;
}
}

View File

@ -14,30 +14,47 @@ set(LIBSTUDXML
${CMAKE_CURRENT_SOURCE_DIR}/libstudxml/xml/qname.cxx
${CMAKE_CURRENT_SOURCE_DIR}/libstudxml/xml/serializer.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/xmlrole.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.c
${CMAKE_CURRENT_SOURCE_DIR}/libstudxml/xml/details/expat/ascii.h
${CMAKE_CURRENT_SOURCE_DIR}/libstudxml/xml/details/expat/asciitab.h
${CMAKE_CURRENT_SOURCE_DIR}/libstudxml/xml/details/expat/config.h
${CMAKE_CURRENT_SOURCE_DIR}/libstudxml/xml/details/expat/expat_external.h
${CMAKE_CURRENT_SOURCE_DIR}/libstudxml/xml/details/expat/expat.h
${CMAKE_CURRENT_SOURCE_DIR}/libstudxml/xml/details/expat/iasciitab.h
${CMAKE_CURRENT_SOURCE_DIR}/libstudxml/xml/details/expat/internal.h
${CMAKE_CURRENT_SOURCE_DIR}/libstudxml/xml/details/expat/latin1tab.h
${CMAKE_CURRENT_SOURCE_DIR}/libstudxml/xml/details/expat/nametab.h
${CMAKE_CURRENT_SOURCE_DIR}/libstudxml/xml/details/expat/utf8tab.h
${CMAKE_CURRENT_SOURCE_DIR}/libstudxml/xml/details/expat/xmlrole.h
${CMAKE_CURRENT_SOURCE_DIR}/libstudxml/xml/details/expat/xmltok_impl.h
${CMAKE_CURRENT_SOURCE_DIR}/libstudxml/xml/details/expat/xmltok.h)
set(GENX
${CMAKE_CURRENT_SOURCE_DIR}/libstudxml/xml/details/genx/char-props.c
${CMAKE_CURRENT_SOURCE_DIR}/libstudxml/xml/details/genx/genx.c)
set(POLE pole/pole.cpp)
set(BOTAN ${CMAKE_CURRENT_SOURCE_DIR}/botan/botan_all.cpp)
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}/libstudxml/xml/details/genx/genx.c
${CMAKE_CURRENT_SOURCE_DIR}/libstudxml/xml/details/genx/genx.h)
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)
set_source_files_properties(${BOTAN} PROPERTIES COMPILE_FLAGS "/wd\"4244\"")
@ -52,9 +69,40 @@ endif()
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}
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)
if(NOT STATIC)
@ -69,5 +117,7 @@ endif()
source_group(botan FILES ${BOTAN})
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})

2
third-party/botan vendored

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

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

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