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

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

@ -48,7 +48,15 @@ endforeach()
# Platform specific settings
if(COVERAGE)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage")
endif()
if(MSVC)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4")
elseif(CMAKE_CXX_COMPILER_ID MATCHES "GNU")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra")
elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Weverything -Wno-c++98-compat -Wno-padded")
endif()
if(APPLE)
@ -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,4 +25,4 @@
#include <xml/content>
#include <xml/parser>
#include <xml/qname>
#include <xml/serializer>
#include <xml/serializer>

View File

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

File diff suppressed because it is too large Load Diff

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())
@ -119,10 +128,6 @@ void xlsx_producer::populate_archive()
case relationship::type::office_document:
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;}}
// 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;}
// read and check for local/global magic
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
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

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

View File

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

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())
{
hash_string.append(std::to_string(static_cast<std::size_t>(side_type)));
if (side(side_type))
{
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(' ');
}
if (side_properties.color())
{
hash_string.append(std::to_string(std::hash<xlnt::hashable>()(*side_properties.color())));
}
else
{
hash_string.push_back(' ');
}
}
else
{
hash_string.push_back(' ');
}
hash_string.push_back(' ');
}
return hash_string;
for (auto side : border::all_sides())
{
if (left.side(side).is_set() != right.side(side).is_set())
{
return false;
}
if (left.side(side).is_set())
{
if (left.side(side).get() != right.side(side).get())
{
return false;
}
}
}
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";
if (left.background().is_set() != right.background().is_set())
{
return false;
}
if (left.background().is_set())
{
if (left.background().get() != right.background().get())
{
return false;
}
}
hash_string.append(background_ ? "1" : "0");
if (background_)
{
hash_string.append(std::to_string(background_->hash()));
}
hash_string.append(background_ ? "1" : "0");
if (background_)
{
hash_string.append(std::to_string(background_->hash()));
}
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";
if (left.type() != right.type())
{
return false;
}
if (left.type() == fill_type::gradient)
{
return left.gradient_fill() == right.gradient_fill();
}
hash_string.append(std::to_string(static_cast<std::size_t>(type_)));
switch (type_)
{
case fill_type::pattern:
hash_string.append(std::to_string(pattern_.hash()));
break;
case fill_type::gradient:
hash_string.append(std::to_string(gradient_.hash()));
break;
default:
break;
} // switch (type_)
return hash_string;
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;
}
if (left.color().is_set())
{
if (left.color().get() != right.color().get())
{
return false;
}
}
return hash_string;
if (left.family().is_set() != right.family().is_set())
{
return false;
}
if (left.family().is_set())
{
if (left.family().get() != right.family().get())
{
return false;
}
}
if (left.italic() != right.italic())
{
return false;
}
if (left.name() != right.name())
{
return false;
}
if (left.scheme().is_set() != right.scheme().is_set())
{
return false;
}
if (left.scheme().is_set())
{
if (left.scheme().get() != right.scheme().get())
{
return false;
}
}
if (left.size() != right.size())
{
return false;
}
if (left.strikethrough() != right.strikethrough())
{
return false;
}
if (left.superscript() != right.superscript())
{
return false;
}
if (left.underline() != right.underline())
{
return false;
}
return true;
}
} // namespace xlnt

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

@ -13,31 +13,48 @@ set(LIBSTUDXML
${CMAKE_CURRENT_SOURCE_DIR}/libstudxml/xml/parser.cxx
${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/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/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_ns.c
${CMAKE_CURRENT_SOURCE_DIR}/libstudxml/xml/details/expat/xmltok.c
${CMAKE_CURRENT_SOURCE_DIR}/libstudxml/xml/details/genx/char-props.c
${CMAKE_CURRENT_SOURCE_DIR}/libstudxml/xml/details/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/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
${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

View File

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

2
third-party/pugixml vendored

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

2
third-party/utfcpp vendored

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

2
third-party/zlib vendored

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