mirror of
https://github.com/tfussell/xlnt.git
synced 2024-03-22 13:11:17 +08:00
start correctly implementing opc
This commit is contained in:
parent
f21d4c922c
commit
ccc3995709
|
@ -75,28 +75,6 @@ public:
|
|||
/// </summary>
|
||||
static const std::unordered_map<std::string, int> &error_codes();
|
||||
|
||||
// TODO: Should it be possible to construct and use a cell without a parent worksheet?
|
||||
//(cont'd) If so, it would need to be responsible for allocating and deleting its PIMPL.
|
||||
|
||||
/// <summary>
|
||||
/// Construct a null cell without a parent.
|
||||
/// Most methods will throw an exception if this cell is not further initialized.
|
||||
/// </summary>
|
||||
cell();
|
||||
|
||||
/// <summary>
|
||||
/// Construct a cell in worksheet, sheet, at the given reference location (e.g. A1).
|
||||
/// </summary>
|
||||
cell(worksheet sheet, const cell_reference &reference);
|
||||
|
||||
/// <summary>
|
||||
/// This constructor, provided for convenience, is equivalent to calling:
|
||||
/// cell c(sheet, reference);
|
||||
/// c.set_value(initial_value);
|
||||
/// </summary>
|
||||
template <typename T>
|
||||
cell(worksheet sheet, const cell_reference &reference, const T &initial_value);
|
||||
|
||||
// value
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -35,14 +35,7 @@ namespace xlnt {
|
|||
class XLNT_CLASS app_properties
|
||||
{
|
||||
public:
|
||||
std::string application = "libxlnt";
|
||||
int doc_security = 0;
|
||||
bool scale_crop = false;
|
||||
std::string company = "";
|
||||
bool links_up_to_date = false;
|
||||
bool shared_doc = false;
|
||||
bool hyperlinks_changed = false;
|
||||
std::string app_version = "0.9";
|
||||
|
||||
};
|
||||
|
||||
} // namespace xlnt
|
||||
|
|
|
@ -38,17 +38,7 @@ class XLNT_CLASS document_properties
|
|||
public:
|
||||
document_properties();
|
||||
|
||||
std::string creator;
|
||||
std::string last_modified_by;
|
||||
datetime created;
|
||||
datetime modified;
|
||||
std::string title = "Untitled";
|
||||
std::string subject;
|
||||
std::string description;
|
||||
std::string keywords;
|
||||
std::string category;
|
||||
std::string company;
|
||||
calendar excel_base_date;
|
||||
|
||||
};
|
||||
|
||||
} // namespace xlnt
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include <xlnt/xlnt_config.hpp>
|
||||
#include <xlnt/packaging/default_type.hpp>
|
||||
#include <xlnt/packaging/override_type.hpp>
|
||||
#include <xlnt/utils/path.hpp>
|
||||
|
||||
namespace xlnt {
|
||||
|
||||
|
@ -39,21 +40,24 @@ namespace xlnt {
|
|||
class XLNT_CLASS manifest
|
||||
{
|
||||
public:
|
||||
using default_types_container = std::unordered_map<std::string, default_type>;
|
||||
using override_types_container = std::unordered_map<path, override_type, std::hash<hashable>>;
|
||||
|
||||
void clear();
|
||||
|
||||
bool has_default_type(const std::string &extension) const;
|
||||
std::string get_default_type(const std::string &extension) const;
|
||||
const std::unordered_map<std::string, default_type> &get_default_types() const;
|
||||
const default_types_container &get_default_types() const;
|
||||
void add_default_type(const std::string &extension, const std::string &content_type);
|
||||
|
||||
bool has_override_type(const std::string &part_name) const;
|
||||
std::string get_override_type(const std::string &part_name) const;
|
||||
const std::unordered_map<std::string, override_type> &get_override_types() const;
|
||||
void add_override_type(const std::string &part_name, const std::string &content_type);
|
||||
bool has_override_type(const path &part) const;
|
||||
std::string get_override_type(const path &part) const;
|
||||
const override_types_container &get_override_types() const;
|
||||
void add_override_type(const path &part, const std::string &content_type);
|
||||
|
||||
private:
|
||||
std::unordered_map<std::string, default_type> default_types_;
|
||||
std::unordered_map<std::string, override_type> override_types_;
|
||||
default_types_container default_types_;
|
||||
override_types_container override_types_;
|
||||
};
|
||||
|
||||
} // namespace xlnt
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include <string>
|
||||
|
||||
#include <xlnt/xlnt_config.hpp>
|
||||
#include <xlnt/utils/path.hpp>
|
||||
|
||||
namespace xlnt {
|
||||
|
||||
|
@ -37,15 +38,15 @@ class XLNT_CLASS override_type
|
|||
{
|
||||
public:
|
||||
override_type();
|
||||
override_type(const std::string &extension, const std::string &content_type);
|
||||
override_type(const path &part, const std::string &content_type);
|
||||
override_type(const override_type &other);
|
||||
override_type &operator=(const override_type &other);
|
||||
|
||||
std::string get_part_name() const;
|
||||
path get_part() const;
|
||||
std::string get_content_type() const;
|
||||
|
||||
private:
|
||||
std::string part_name_;
|
||||
path part_;
|
||||
std::string content_type_;
|
||||
};
|
||||
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include <vector>
|
||||
|
||||
#include <xlnt/xlnt_config.hpp>
|
||||
#include <xlnt/utils/path.hpp>
|
||||
|
||||
// Note: this comes from https://github.com/tfussell/miniz-cpp
|
||||
|
||||
|
@ -61,7 +62,7 @@ struct XLNT_CLASS zip_info
|
|||
zip_info();
|
||||
|
||||
date_time_t date_time;
|
||||
std::string filename;
|
||||
path filename;
|
||||
std::string comment;
|
||||
std::string extra;
|
||||
uint16_t create_system;
|
||||
|
@ -85,18 +86,18 @@ class XLNT_CLASS zip_file
|
|||
{
|
||||
public:
|
||||
zip_file();
|
||||
zip_file(const std::string &filename);
|
||||
zip_file(const std::vector<unsigned char> &bytes);
|
||||
zip_file(const path &filename);
|
||||
zip_file(const std::vector<uint8_t> &bytes);
|
||||
zip_file(std::istream &stream);
|
||||
~zip_file();
|
||||
|
||||
// to/from file
|
||||
void load(const std::string &filename);
|
||||
void save(const std::string &filename);
|
||||
void load(const path &filename);
|
||||
void save(const path &filename);
|
||||
|
||||
// to/from byte vector
|
||||
void load(const std::vector<unsigned char> &bytes);
|
||||
void save(std::vector<unsigned char> &bytes);
|
||||
void load(const std::vector<std::uint8_t> &bytes);
|
||||
void save(std::vector<std::uint8_t> &bytes);
|
||||
|
||||
// to/from iostream
|
||||
void load(std::istream &stream);
|
||||
|
@ -104,42 +105,29 @@ public:
|
|||
|
||||
void reset();
|
||||
|
||||
bool has_file(const std::string &name);
|
||||
bool has_file(const path &name);
|
||||
bool has_file(const zip_info &name);
|
||||
|
||||
zip_info getinfo(const std::string &name);
|
||||
zip_info getinfo(const path &name);
|
||||
|
||||
std::vector<zip_info> infolist();
|
||||
std::vector<std::string> namelist();
|
||||
std::vector<path> namelist();
|
||||
|
||||
std::ostream &open(const std::string &name);
|
||||
std::ostream &open(const path &name);
|
||||
std::ostream &open(const zip_info &name);
|
||||
|
||||
void extract(const std::string &name);
|
||||
void extract(const std::string &name, const std::string &path);
|
||||
void extract(const zip_info &name);
|
||||
void extract(const zip_info &name, const std::string &path);
|
||||
|
||||
void extractall();
|
||||
void extractall(const std::string &path);
|
||||
void extractall(const std::string &path, const std::vector<std::string> &members);
|
||||
void extractall(const std::string &path, const std::vector<zip_info> &members);
|
||||
|
||||
void printdir();
|
||||
void printdir(std::ostream &stream);
|
||||
|
||||
std::string read(const std::string &name);
|
||||
std::string read(const path &name);
|
||||
std::string read(const zip_info &name);
|
||||
|
||||
std::pair<bool, std::string> testzip();
|
||||
bool check_crc();
|
||||
|
||||
void write(const std::string &filename);
|
||||
void write(const std::string &filename, const std::string &arcname);
|
||||
void write_file(const path &source_file);
|
||||
void write_file(const path &source_file, const path &archive_path);
|
||||
|
||||
void writestr(const std::string &arcname, const std::string &bytes);
|
||||
void writestr(const zip_info &arcname, const std::string &bytes);
|
||||
void write_string(const std::string &string, const path &archive_path);
|
||||
void write_string(const std::string &string, const zip_info &archive_path);
|
||||
|
||||
std::string get_filename() const;
|
||||
path get_filename() const;
|
||||
|
||||
std::string comment;
|
||||
|
||||
|
@ -155,7 +143,7 @@ private:
|
|||
std::unique_ptr<mz_zip_archive_tag> archive_;
|
||||
std::vector<char> buffer_;
|
||||
std::stringstream open_stream_;
|
||||
std::string filename_;
|
||||
path filename_;
|
||||
};
|
||||
|
||||
} // namespace xlnt
|
||||
|
|
247
include/xlnt/utils/path.hpp
Normal file
247
include/xlnt/utils/path.hpp
Normal file
|
@ -0,0 +1,247 @@
|
|||
// 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 <string>
|
||||
#include <vector>
|
||||
|
||||
#include <xlnt/xlnt_config.hpp>
|
||||
#include <xlnt/utils/hashable.hpp>
|
||||
|
||||
namespace xlnt {
|
||||
|
||||
/// <summary>
|
||||
/// Encapsulates a path that points to location in a filesystem.
|
||||
/// </summary>
|
||||
class XLNT_CLASS path : public hashable
|
||||
{
|
||||
public:
|
||||
/// <summary>
|
||||
/// The parts of this path are held in a container of this type.
|
||||
/// </summary>
|
||||
using container = std::vector<std::string>;
|
||||
|
||||
/// <summary>
|
||||
/// Expose the container's iterator as the iterator for this class.
|
||||
/// </summary>
|
||||
using iterator = container::iterator;
|
||||
/// <summary>
|
||||
/// Expose the container's const_iterator as the const_iterator for this class.
|
||||
/// </summary>
|
||||
using const_iterator = container::const_iterator;
|
||||
|
||||
/// <summary>
|
||||
/// Expose the container's reverse_iterator as the reverse_iterator for this class.
|
||||
/// </summary>
|
||||
using reverse_iterator = container::reverse_iterator;
|
||||
|
||||
/// <summary>
|
||||
/// Expose the container's const_reverse_iterator as the const_reverse_iterator for this class.
|
||||
/// </summary>
|
||||
using const_reverse_iterator = container::const_reverse_iterator;
|
||||
|
||||
/// <summary>
|
||||
/// The system-specific path separator character (e.g. '/' or '\').
|
||||
/// </summary>
|
||||
static char separator();
|
||||
|
||||
/// <summary>
|
||||
/// Construct an empty path.
|
||||
/// </summary>
|
||||
path();
|
||||
|
||||
/// <summary>
|
||||
/// Counstruct a path from a string representing the path.
|
||||
/// </summary>
|
||||
explicit path(const std::string &path_string);
|
||||
|
||||
/// <summary>
|
||||
/// Construct a path from a string with an explicit directory seprator.
|
||||
/// </summary>
|
||||
path(const std::string &path_string, char sep);
|
||||
|
||||
// general attributes
|
||||
|
||||
/// <summary>
|
||||
/// Return true iff this path doesn't begin with / (or a drive letter on Windows).
|
||||
/// </summary>
|
||||
bool is_relative() const;
|
||||
|
||||
/// <summary>
|
||||
/// Return true iff path::is_relative() is false.
|
||||
/// </summary>
|
||||
bool is_absolute() const;
|
||||
|
||||
/// <summary>
|
||||
/// Return true iff this path is the root of the host's filesystem.
|
||||
/// </summary>
|
||||
bool is_root() const;
|
||||
|
||||
/// <summary>
|
||||
/// Return a new path that points to the directory containing the current path
|
||||
/// Return the path unchanged if this path is the absolute or relative root.
|
||||
/// </summary>
|
||||
path parent() const;
|
||||
|
||||
/// <summary>
|
||||
/// Return the last component of this path.
|
||||
/// </summary>
|
||||
std::string basename();
|
||||
|
||||
// conversion
|
||||
|
||||
/// <summary>
|
||||
/// Create a string representing this path separated by the provided
|
||||
/// separator or the system-default separator if not provided.
|
||||
/// </summary>
|
||||
std::string to_string(char sep = separator()) const;
|
||||
|
||||
/// <summary>
|
||||
/// If this path is relative, append each component of this path
|
||||
/// to base_path and return the resulting absolute path. Otherwise,
|
||||
/// the the current path will be returned and base_path will be ignored.
|
||||
/// </summary>
|
||||
path make_absolute(const path &base_path) const;
|
||||
|
||||
// filesystem attributes
|
||||
|
||||
/// <summary>
|
||||
/// Return true iff the file or directory pointed to by this path
|
||||
/// exists on the filesystem.
|
||||
/// </summary>
|
||||
bool exists() const;
|
||||
|
||||
/// <summary>
|
||||
/// Return true if the file or directory pointed to by this path
|
||||
/// is a directory.
|
||||
/// </summary>
|
||||
bool is_directory() const;
|
||||
|
||||
/// <summary>
|
||||
/// Return true if the file or directory pointed to by this path
|
||||
/// is a regular file.
|
||||
/// </summary>
|
||||
bool is_file() const;
|
||||
|
||||
// filesystem
|
||||
|
||||
/// <summary>
|
||||
/// Open the file pointed to by this path and return a string containing
|
||||
/// the files contents.
|
||||
/// </summary>
|
||||
std::string read_contents() const;
|
||||
|
||||
// mutators
|
||||
|
||||
/// <summary>
|
||||
/// Append the provided part to this path and return a reference to this same path
|
||||
/// so calls can be chained.
|
||||
/// </summary>
|
||||
path &append(const std::string &to_append);
|
||||
|
||||
/// <summary>
|
||||
/// Append the provided part to this path and return the result.
|
||||
/// </summary>
|
||||
path append(const std::string &to_append) const;
|
||||
|
||||
/// <summary>
|
||||
/// Append the provided part to this path and return a reference to this same path
|
||||
/// so calls can be chained.
|
||||
/// </summary>
|
||||
path &append(const path &to_append);
|
||||
|
||||
/// <summary>
|
||||
/// Append the provided part to this path and return the result.
|
||||
/// </summary>
|
||||
path append(const path &to_append) const;
|
||||
|
||||
// iterators
|
||||
|
||||
/// <summary>
|
||||
/// An iterator to the first element in this path.
|
||||
/// </summary>
|
||||
iterator begin();
|
||||
|
||||
/// <summary>
|
||||
/// An iterator to one past the last element in this path.
|
||||
/// </summary>
|
||||
iterator end();
|
||||
|
||||
/// <summary>
|
||||
/// An iterator to the first element in this path.
|
||||
/// </summary>
|
||||
const_iterator begin() const;
|
||||
|
||||
/// <summary>
|
||||
/// A const iterator to one past the last element in this path.
|
||||
/// </summary>
|
||||
const_iterator end() const;
|
||||
|
||||
/// <summary>
|
||||
/// An iterator to the first element in this path.
|
||||
/// </summary>
|
||||
const_iterator cbegin() const;
|
||||
|
||||
/// <summary>
|
||||
/// A const iterator to one past the last element in this path.
|
||||
/// </summary>
|
||||
const_iterator cend() const;
|
||||
|
||||
/// <summary>
|
||||
/// A reverse iterator to the last element in this path.
|
||||
/// </summary>
|
||||
reverse_iterator rbegin();
|
||||
|
||||
/// <summary>
|
||||
/// A reverse iterator to one before the first element in this path.
|
||||
/// </summary>
|
||||
reverse_iterator rend();
|
||||
|
||||
/// <summary>
|
||||
/// A const reverse iterator to the last element in this path.
|
||||
/// </summary>
|
||||
const_reverse_iterator rbegin() const;
|
||||
|
||||
/// <summary>
|
||||
/// A const reverse iterator to one before the first element in this path.
|
||||
/// </summary>
|
||||
const_reverse_iterator rend() const;
|
||||
|
||||
/// <summary>
|
||||
/// A const reverse iterator to the last element in this path.
|
||||
/// </summary>
|
||||
const_reverse_iterator crbegin() const;
|
||||
|
||||
/// <summary>
|
||||
/// A const reverse iterator to one before the first element in this path.
|
||||
/// </summary>
|
||||
const_reverse_iterator crend() const;
|
||||
|
||||
protected:
|
||||
std::string to_hash_string() const override;
|
||||
|
||||
private:
|
||||
container parts_;
|
||||
};
|
||||
|
||||
} // namespace xlnt
|
|
@ -36,13 +36,11 @@
|
|||
namespace xlnt {
|
||||
|
||||
class alignment;
|
||||
class app_properties;
|
||||
class border;
|
||||
class cell;
|
||||
class cell_style;
|
||||
class color;
|
||||
class const_worksheet_iterator;
|
||||
class document_properties;
|
||||
class drawing;
|
||||
class fill;
|
||||
class font;
|
||||
|
@ -50,6 +48,7 @@ class format;
|
|||
class manifest;
|
||||
class named_range;
|
||||
class number_format;
|
||||
class path;
|
||||
class pattern_fill;
|
||||
class protection;
|
||||
class range;
|
||||
|
@ -63,6 +62,9 @@ class worksheet;
|
|||
class worksheet_iterator;
|
||||
class zip_file;
|
||||
|
||||
struct datetime;
|
||||
|
||||
enum class calendar;
|
||||
enum class relationship_type;
|
||||
|
||||
namespace detail {
|
||||
|
@ -85,6 +87,14 @@ public:
|
|||
/// </summary>
|
||||
friend void swap(workbook &left, workbook &right);
|
||||
|
||||
static workbook minimal();
|
||||
|
||||
static workbook empty_excel();
|
||||
|
||||
static workbook empty_libre_office();
|
||||
|
||||
static workbook empty_numbers();
|
||||
|
||||
// constructors
|
||||
|
||||
/// <summary>
|
||||
|
@ -297,11 +307,47 @@ public:
|
|||
/// </summary>
|
||||
std::vector<std::string> get_sheet_titles() const;
|
||||
|
||||
document_properties &get_properties();
|
||||
const document_properties &get_properties() const;
|
||||
std::string get_application() const;
|
||||
void set_application(const std::string &application);
|
||||
|
||||
app_properties &get_app_properties();
|
||||
const app_properties &get_app_properties() const;
|
||||
calendar get_base_date() const;
|
||||
void set_base_date(calendar base_date);
|
||||
|
||||
std::string get_creator() const;
|
||||
void set_creator(const std::string &creator);
|
||||
|
||||
std::string get_last_modified_by() const;
|
||||
void set_last_modified_by(const std::string &last_modified_by);
|
||||
|
||||
datetime get_created() const;
|
||||
void set_created(const datetime &when);
|
||||
|
||||
datetime get_modified() const;
|
||||
void set_modified(const datetime &when);
|
||||
|
||||
int get_doc_security() const;
|
||||
void set_doc_security(int doc_security);
|
||||
|
||||
bool get_scale_crop() const;
|
||||
void set_scale_crop(bool scale_crop);
|
||||
|
||||
std::string get_company() const;
|
||||
void set_company(const std::string &company);
|
||||
|
||||
bool links_up_to_date() const;
|
||||
void set_links_up_to_date(bool links_up_to_date);
|
||||
|
||||
bool is_shared_doc() const;
|
||||
void set_shared_doc(bool shared_doc);
|
||||
|
||||
bool hyperlinks_changed() const;
|
||||
void set_hyperlinks_changed(bool hyperlinks_changed);
|
||||
|
||||
std::string get_app_version() const;
|
||||
void set_app_version(const std::string &version);
|
||||
|
||||
std::string get_title() const;
|
||||
void set_title(const std::string &title);
|
||||
|
||||
// named ranges
|
||||
|
||||
|
@ -314,19 +360,23 @@ public:
|
|||
|
||||
// serialization
|
||||
|
||||
bool save(std::vector<unsigned char> &data);
|
||||
bool save(std::vector<std::uint8_t> &data);
|
||||
bool save(const std::string &filename);
|
||||
bool load(const std::vector<unsigned char> &data);
|
||||
bool save(const xlnt::path &filename);
|
||||
bool save(std::ostream &stream);
|
||||
|
||||
bool load(const std::vector<std::uint8_t> &data);
|
||||
bool load(const std::string &filename);
|
||||
bool load(const xlnt::path &filename);
|
||||
bool load(std::istream &stream);
|
||||
bool load(zip_file &archive);
|
||||
|
||||
void set_code_name(const std::string &code_name);
|
||||
|
||||
// theme
|
||||
|
||||
bool has_loaded_theme() const;
|
||||
const theme &get_loaded_theme() const;
|
||||
bool has_theme() const;
|
||||
const theme &get_theme() const;
|
||||
void set_theme(const theme &value);
|
||||
|
||||
// formats
|
||||
|
||||
|
@ -407,6 +457,8 @@ private:
|
|||
friend class excel_serializer;
|
||||
friend class worksheet;
|
||||
|
||||
workbook(detail::workbook_impl *impl);
|
||||
|
||||
/// <summary>
|
||||
/// Get the name of the next unused relationship.
|
||||
/// </summary>
|
||||
|
|
|
@ -65,6 +65,7 @@
|
|||
#include <xlnt/utils/date.hpp>
|
||||
#include <xlnt/utils/datetime.hpp>
|
||||
#include <xlnt/utils/exceptions.hpp>
|
||||
#include <xlnt/utils/path.hpp>
|
||||
#include <xlnt/utils/time.hpp>
|
||||
#include <xlnt/utils/timedelta.hpp>
|
||||
|
||||
|
|
|
@ -155,26 +155,10 @@ std::string cell::check_string(const std::string &to_check)
|
|||
return s;
|
||||
}
|
||||
|
||||
cell::cell() : d_(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
cell::cell(detail::cell_impl *d) : d_(d)
|
||||
{
|
||||
}
|
||||
|
||||
cell::cell(worksheet worksheet, const cell_reference &reference) : d_(nullptr)
|
||||
{
|
||||
cell self = worksheet.get_cell(reference);
|
||||
d_ = self.d_;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
cell::cell(worksheet worksheet, const cell_reference &reference, const T &initial_value) : cell(worksheet, reference)
|
||||
{
|
||||
set_value(initial_value);
|
||||
}
|
||||
|
||||
bool cell::garbage_collectible() const
|
||||
{
|
||||
return !(get_data_type() != type::null || is_merged() || has_comment() || has_formula() || has_format());
|
||||
|
@ -953,7 +937,7 @@ void cell::set_format(const format &new_format)
|
|||
|
||||
calendar cell::get_base_date() const
|
||||
{
|
||||
return get_workbook().get_properties().excel_base_date;
|
||||
return get_workbook().get_base_date();
|
||||
}
|
||||
|
||||
std::ostream &operator<<(std::ostream &stream, const xlnt::cell &cell)
|
||||
|
|
|
@ -604,12 +604,6 @@ public:
|
|||
TS_ASSERT_EQUALS(cell.get_value<std::string>(), std::string(32'767, 'a'));
|
||||
}
|
||||
|
||||
void test_operators()
|
||||
{
|
||||
xlnt::cell cell;
|
||||
TS_ASSERT_EQUALS(cell, nullptr);
|
||||
}
|
||||
|
||||
void test_comment()
|
||||
{
|
||||
xlnt::workbook wb;
|
||||
|
@ -646,7 +640,7 @@ public:
|
|||
void test_anchor()
|
||||
{
|
||||
xlnt::workbook wb;
|
||||
xlnt::cell cell(wb.get_active_sheet(), "A1");
|
||||
auto cell = wb.get_active_sheet().get_cell("A1");
|
||||
auto anchor = cell.get_anchor();
|
||||
TS_ASSERT_EQUALS(anchor.first, 0);
|
||||
TS_ASSERT_EQUALS(anchor.second, 0);
|
||||
|
@ -655,7 +649,7 @@ public:
|
|||
void test_hyperlink()
|
||||
{
|
||||
xlnt::workbook wb;
|
||||
xlnt::cell cell(wb.get_active_sheet(), "A1");
|
||||
auto cell = wb.get_active_sheet().get_cell("A1");
|
||||
TS_ASSERT(!cell.has_hyperlink());
|
||||
TS_ASSERT_THROWS(cell.get_hyperlink(), std::runtime_error);
|
||||
TS_ASSERT_THROWS(cell.set_hyperlink("notaurl"), std::runtime_error);
|
||||
|
|
|
@ -23,8 +23,7 @@
|
|||
#include <limits>
|
||||
|
||||
#include <detail/constants.hpp>
|
||||
|
||||
#include "xlnt_config.hpp"
|
||||
#include <xlnt/xlnt_config.hpp>
|
||||
|
||||
namespace xlnt {
|
||||
|
||||
|
@ -49,20 +48,20 @@ const column_t constants::max_column()
|
|||
}
|
||||
|
||||
// constants
|
||||
const std::string constants::package_properties() { return "docProps"; }
|
||||
const std::string constants::package_xl() { return "xl"; }
|
||||
const std::string constants::package_root_rels() { return "_rels"; }
|
||||
const std::string constants::package_theme() { return package_xl() + "/" + "theme"; }
|
||||
const std::string constants::package_worksheets() { return package_xl() + "/" + "worksheets"; }
|
||||
const path constants::package_properties() { return path("docProps"); }
|
||||
const path constants::package_xl() { return path("xl"); }
|
||||
const path constants::package_root_rels() { return path(std::string("_rels")); }
|
||||
const path constants::package_theme() { return package_xl().append("theme"); }
|
||||
const path constants::package_worksheets() { return package_xl().append("worksheets"); }
|
||||
|
||||
const std::string constants::part_content_types() { return "[Content_Types].xml"; }
|
||||
const std::string constants::part_root_relationships() { return package_root_rels() + "/.rels"; }
|
||||
const std::string constants::part_core() { return package_properties() + "/core.xml"; }
|
||||
const std::string constants::part_app() { return package_properties() + "/app.xml"; }
|
||||
const std::string constants::part_workbook() { return package_xl() + "/workbook.xml"; }
|
||||
const std::string constants::part_styles() { return package_xl() + "/styles.xml"; }
|
||||
const std::string constants::part_theme() { return package_theme() + "/theme1.xml"; }
|
||||
const std::string constants::part_shared_strings() { return package_xl() + "/sharedStrings.xml"; }
|
||||
const path constants::part_content_types() { return path("[Content_Types].xml"); }
|
||||
const path constants::part_root_relationships() { return package_root_rels().append(".rels"); }
|
||||
const path constants::part_core() { return package_properties().append("core.xml"); }
|
||||
const path constants::part_app() { return package_properties().append("app.xml"); }
|
||||
const path constants::part_workbook() { return package_xl().append("workbook.xml"); }
|
||||
const path constants::part_styles() { return package_xl().append("styles.xml"); }
|
||||
const path constants::part_theme() { return package_theme().append("theme1.xml"); }
|
||||
const path constants::part_shared_strings() { return package_xl().append("sharedStrings.xml"); }
|
||||
|
||||
const std::unordered_map<std::string, std::string> &constants::get_namespaces()
|
||||
{
|
||||
|
|
|
@ -26,10 +26,11 @@
|
|||
#include <unordered_map>
|
||||
|
||||
#include <xlnt/cell/index_types.hpp>
|
||||
#include <xlnt/utils/path.hpp>
|
||||
|
||||
namespace xlnt {
|
||||
|
||||
struct constants
|
||||
struct XLNT_CLASS constants
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns the lowest allowable row index in a worksheet.
|
||||
|
@ -54,67 +55,67 @@ struct constants
|
|||
/// <summary>
|
||||
/// Returns the URI of the directory containing package properties.
|
||||
/// </summary>
|
||||
static const std::string package_properties();
|
||||
static const path package_properties();
|
||||
|
||||
/// <summary>
|
||||
/// Returns the URI of the directory containing SpreatsheetML package parts.
|
||||
/// </summary>
|
||||
static const std::string package_xl();
|
||||
static const path package_xl();
|
||||
|
||||
/// <summary>
|
||||
/// Returns the URI of the directory containing root relationships package part.
|
||||
/// </summary>
|
||||
static const std::string package_root_rels();
|
||||
static const path package_root_rels();
|
||||
|
||||
/// <summary>
|
||||
/// Returns the URI of the directory containing package themes.
|
||||
/// </summary>
|
||||
static const std::string package_theme();
|
||||
static const path package_theme();
|
||||
|
||||
/// <summary>
|
||||
/// Returns the URI of the directory containing package worksheets.
|
||||
/// </summary>
|
||||
static const std::string package_worksheets();
|
||||
static const path package_worksheets();
|
||||
|
||||
/// <summary>
|
||||
/// Returns the URI of the content types package part.
|
||||
/// </summary>
|
||||
static const std::string part_content_types();
|
||||
static const path part_content_types();
|
||||
|
||||
/// <summary>
|
||||
/// Returns the URI of the core properties package part.
|
||||
/// </summary>
|
||||
static const std::string part_core();
|
||||
static const path part_core();
|
||||
|
||||
/// <summary>
|
||||
/// Returns the URI of the app properties package part.
|
||||
/// </summary>
|
||||
static const std::string part_app();
|
||||
static const path part_app();
|
||||
|
||||
/// <summary>
|
||||
/// Returns the URI of the workbook package part.
|
||||
/// </summary>
|
||||
static const std::string part_workbook();
|
||||
static const path part_workbook();
|
||||
|
||||
/// <summary>
|
||||
/// Returns the URI of the root relationships package part.
|
||||
/// </summary>
|
||||
static const std::string part_root_relationships();
|
||||
static const path part_root_relationships();
|
||||
|
||||
/// <summary>
|
||||
/// Returns the URI of the styles package part.
|
||||
/// </summary>
|
||||
static const std::string part_styles();
|
||||
static const path part_styles();
|
||||
|
||||
/// <summary>
|
||||
/// Returns the URI of the theme package part.
|
||||
/// </summary>
|
||||
static const std::string part_theme();
|
||||
static const path part_theme();
|
||||
|
||||
/// <summary>
|
||||
/// Returns the URI of the shared strings package part.
|
||||
/// </summary>
|
||||
static const std::string part_shared_strings();
|
||||
static const path part_shared_strings();
|
||||
|
||||
/// <summary>
|
||||
/// Returns an unordered_map mapping namespace names to namespaces.
|
||||
|
|
|
@ -70,9 +70,6 @@ bool load_workbook(xlnt::zip_file &archive, bool guess_types, bool data_only, xl
|
|||
{
|
||||
wb.clear();
|
||||
|
||||
wb.set_guess_types(guess_types);
|
||||
wb.set_data_only(data_only);
|
||||
|
||||
if(!archive.has_file(xlnt::constants::part_content_types()))
|
||||
{
|
||||
throw xlnt::invalid_file("missing [Content Types].xml");
|
||||
|
@ -112,7 +109,7 @@ bool load_workbook(xlnt::zip_file &archive, bool guess_types, bool data_only, xl
|
|||
wb.create_root_relationship(relationship.get_id(), relationship.get_target_uri(), relationship.get_type());
|
||||
}
|
||||
|
||||
auto workbook_relationships = relationship_serializer_.read_relationships(xlnt::constants::part_workbook());
|
||||
auto workbook_relationships = relationship_serializer_.read_relationships(xlnt::constants::part_workbook().to_string('/'));
|
||||
|
||||
for (const auto &relationship : workbook_relationships)
|
||||
{
|
||||
|
@ -123,12 +120,17 @@ bool load_workbook(xlnt::zip_file &archive, bool guess_types, bool data_only, xl
|
|||
xml.load(archive.read(xlnt::constants::part_workbook()).c_str());
|
||||
|
||||
auto root_node = xml.child("workbook");
|
||||
|
||||
auto workbook_pr_node = root_node.child("workbookPr");
|
||||
wb.get_properties().excel_base_date =
|
||||
(workbook_pr_node.attribute("date1904") && workbook_pr_node.attribute("date1904").value() != std::string("0"))
|
||||
? xlnt::calendar::mac_1904
|
||||
: xlnt::calendar::windows_1900;
|
||||
|
||||
if (workbook_pr_node.attribute("date1904"))
|
||||
{
|
||||
std::string value = workbook_pr_node.attribute("date1904").value();
|
||||
|
||||
if (value == "1" || value == "true")
|
||||
{
|
||||
wb.set_base_date(xlnt::calendar::mac_1904);
|
||||
}
|
||||
}
|
||||
|
||||
if(archive.has_file(xlnt::constants::part_shared_strings()))
|
||||
{
|
||||
|
@ -162,14 +164,15 @@ bool load_workbook(xlnt::zip_file &archive, bool guess_types, bool data_only, xl
|
|||
ws.set_id(static_cast<std::size_t>(sheet_node.attribute("sheetId").as_ullong()));
|
||||
xlnt::worksheet_serializer worksheet_serializer(ws);
|
||||
pugi::xml_document worksheet_xml;
|
||||
worksheet_xml.load(archive.read("xl/" + rel.get_target_uri()).c_str());
|
||||
auto target_uri = xlnt::constants::package_xl().append(rel.get_target_uri());
|
||||
worksheet_xml.load(archive.read(target_uri).c_str());
|
||||
|
||||
worksheet_serializer.read_worksheet(worksheet_xml, stylesheet);
|
||||
}
|
||||
|
||||
if (archive.has_file("docProps/thumbnail.jpeg"))
|
||||
if (archive.has_file(xlnt::path("docProps/thumbnail.jpeg")))
|
||||
{
|
||||
auto thumbnail_data = archive.read("docProps/thumbnail.jpeg");
|
||||
auto thumbnail_data = archive.read(xlnt::path("docProps/thumbnail.jpeg"));
|
||||
wb.set_thumbnail(std::vector<std::uint8_t>(thumbnail_data.begin(), thumbnail_data.end()));
|
||||
}
|
||||
|
||||
|
@ -210,7 +213,7 @@ bool excel_serializer::load_stream_workbook(std::istream &stream, bool guess_typ
|
|||
return load_virtual_workbook(bytes, guess_types, data_only);
|
||||
}
|
||||
|
||||
bool excel_serializer::load_workbook(const std::string &filename, bool guess_types, bool data_only)
|
||||
bool excel_serializer::load_workbook(const path &filename, bool guess_types, bool data_only)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
@ -218,7 +221,7 @@ bool excel_serializer::load_workbook(const std::string &filename, bool guess_typ
|
|||
}
|
||||
catch (std::runtime_error)
|
||||
{
|
||||
throw invalid_file(filename);
|
||||
throw invalid_file(filename.to_string());
|
||||
}
|
||||
|
||||
return ::load_workbook(archive_, guess_types, data_only, workbook_, get_stylesheet());
|
||||
|
@ -239,7 +242,7 @@ void excel_serializer::write_data(bool /*as_template*/)
|
|||
{
|
||||
relationship_serializer relationship_serializer_(archive_);
|
||||
relationship_serializer_.write_relationships(workbook_.get_root_relationships(), "");
|
||||
relationship_serializer_.write_relationships(workbook_.get_relationships(), constants::part_workbook());
|
||||
relationship_serializer_.write_relationships(workbook_.get_relationships(), constants::part_workbook().to_string('/'));
|
||||
|
||||
pugi::xml_document properties_app_xml;
|
||||
workbook_serializer workbook_serializer_(workbook_);
|
||||
|
@ -248,7 +251,7 @@ void excel_serializer::write_data(bool /*as_template*/)
|
|||
{
|
||||
std::ostringstream ss;
|
||||
properties_app_xml.save(ss);
|
||||
archive_.writestr(constants::part_app(), ss.str());
|
||||
archive_.write_string(ss.str(), constants::part_app());
|
||||
}
|
||||
|
||||
pugi::xml_document properties_core_xml;
|
||||
|
@ -257,17 +260,17 @@ void excel_serializer::write_data(bool /*as_template*/)
|
|||
{
|
||||
std::ostringstream ss;
|
||||
properties_core_xml.save(ss);
|
||||
archive_.writestr(constants::part_core(), ss.str());
|
||||
archive_.write_string(ss.str(), constants::part_core());
|
||||
}
|
||||
|
||||
pugi::xml_document theme_xml;
|
||||
theme_serializer theme_serializer_;
|
||||
theme_serializer_.write_theme(workbook_.get_loaded_theme(), theme_xml);
|
||||
theme_serializer_.write_theme(workbook_.get_theme(), theme_xml);
|
||||
|
||||
{
|
||||
std::ostringstream ss;
|
||||
theme_xml.save(ss);
|
||||
archive_.writestr(constants::part_theme(), ss.str());
|
||||
archive_.write_string(ss.str(), constants::part_theme());
|
||||
}
|
||||
|
||||
if (!workbook_.get_shared_strings().empty())
|
||||
|
@ -278,7 +281,7 @@ void excel_serializer::write_data(bool /*as_template*/)
|
|||
|
||||
std::ostringstream ss;
|
||||
shared_strings_xml.save(ss);
|
||||
archive_.writestr(constants::part_shared_strings(), ss.str());
|
||||
archive_.write_string(ss.str(), constants::part_shared_strings());
|
||||
}
|
||||
|
||||
pugi::xml_document workbook_xml;
|
||||
|
@ -287,7 +290,7 @@ void excel_serializer::write_data(bool /*as_template*/)
|
|||
{
|
||||
std::ostringstream ss;
|
||||
workbook_xml.save(ss);
|
||||
archive_.writestr(constants::part_workbook(), ss.str());
|
||||
archive_.write_string(ss.str(), constants::part_workbook());
|
||||
}
|
||||
|
||||
style_serializer style_serializer(workbook_.d_->stylesheet_);
|
||||
|
@ -297,7 +300,7 @@ void excel_serializer::write_data(bool /*as_template*/)
|
|||
{
|
||||
std::ostringstream ss;
|
||||
style_xml.save(ss);
|
||||
archive_.writestr(constants::part_styles(), ss.str());
|
||||
archive_.write_string(ss.str(), constants::part_styles());
|
||||
}
|
||||
|
||||
manifest_serializer manifest_serializer_(workbook_.get_manifest());
|
||||
|
@ -307,7 +310,7 @@ void excel_serializer::write_data(bool /*as_template*/)
|
|||
{
|
||||
std::ostringstream ss;
|
||||
manifest_xml.save(ss);
|
||||
archive_.writestr(constants::part_content_types(), ss.str());
|
||||
archive_.write_string(ss.str(), constants::part_content_types());
|
||||
}
|
||||
|
||||
write_worksheets();
|
||||
|
@ -315,7 +318,7 @@ void excel_serializer::write_data(bool /*as_template*/)
|
|||
if(!workbook_.get_thumbnail().empty())
|
||||
{
|
||||
const auto &thumbnail = workbook_.get_thumbnail();
|
||||
archive_.writestr("docProps/thumbnail.jpeg", std::string(thumbnail.begin(), thumbnail.end()));
|
||||
archive_.write_string(std::string(thumbnail.begin(), thumbnail.end()), path("docProps/thumbnail.jpeg"));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -332,12 +335,13 @@ void excel_serializer::write_worksheets()
|
|||
if (rel.get_target_uri() != target) continue;
|
||||
|
||||
worksheet_serializer serializer_(ws);
|
||||
std::string ws_filename = (rel.get_target_uri().substr(0, 3) != "xl/" ? "xl/" : "") + rel.get_target_uri();
|
||||
path ws_path(rel.get_target_uri().substr(0, 3) != "xl/" ? "xl/" : "", '/');
|
||||
ws_path.append(rel.get_target_uri());
|
||||
std::ostringstream ss;
|
||||
pugi::xml_document worksheet_xml;
|
||||
serializer_.write_worksheet(worksheet_xml);
|
||||
worksheet_xml.save(ss);
|
||||
archive_.writestr(ws_filename, ss.str());
|
||||
archive_.write_string(ss.str(), ws_path);
|
||||
|
||||
break;
|
||||
}
|
||||
|
@ -356,7 +360,7 @@ bool excel_serializer::save_stream_workbook(std::ostream &stream, bool as_templa
|
|||
return true;
|
||||
}
|
||||
|
||||
bool excel_serializer::save_workbook(const std::string &filename, bool as_template)
|
||||
bool excel_serializer::save_workbook(const path &filename, bool as_template)
|
||||
{
|
||||
write_data(as_template);
|
||||
archive_.save(filename);
|
||||
|
|
|
@ -62,7 +62,7 @@ public:
|
|||
/// Create a ZIP file in memory, load archive from filename, then populate workbook
|
||||
/// with data from archive.
|
||||
/// </summary>
|
||||
bool load_workbook(const std::string &filename, bool guess_types = false, bool data_only = false);
|
||||
bool load_workbook(const path &filename, bool guess_types = false, bool data_only = false);
|
||||
|
||||
/// <summary>
|
||||
/// Create a ZIP file in memory, load archive from stream, then populate workbook
|
||||
|
@ -81,7 +81,7 @@ public:
|
|||
/// Create a ZIP file in memory, save workbook to this archive, then save archive
|
||||
/// to filename.
|
||||
/// </summary>
|
||||
bool save_workbook(const std::string &filename, bool as_template = false);
|
||||
bool save_workbook(const path &filename, bool as_template = false);
|
||||
|
||||
/// <summary>
|
||||
/// Create a ZIP file in memory, save workbook to this archive, then assign ZIP file
|
||||
|
|
|
@ -46,7 +46,7 @@ void manifest_serializer::read_manifest(const pugi::xml_document &xml)
|
|||
}
|
||||
else if (child.name() == std::string("Override"))
|
||||
{
|
||||
manifest_.add_override_type(child.attribute("PartName").value(), child.attribute("ContentType").value());
|
||||
manifest_.add_override_type(path(child.attribute("PartName").value()), child.attribute("ContentType").value());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -66,7 +66,7 @@ void manifest_serializer::write_manifest(pugi::xml_document &xml) const
|
|||
for (const auto override_type : manifest_.get_override_types())
|
||||
{
|
||||
auto type_node = root_node.append_child("Override");
|
||||
type_node.append_attribute("PartName").set_value(override_type.second.get_part_name().c_str());
|
||||
type_node.append_attribute("PartName").set_value(override_type.second.get_part().to_string('/').c_str());
|
||||
type_node.append_attribute("ContentType").set_value(override_type.second.get_content_type().c_str());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,7 +38,7 @@ std::string make_rels_name(const std::string &target)
|
|||
|
||||
if (target.empty())
|
||||
{
|
||||
return xlnt::constants::part_root_relationships();
|
||||
return xlnt::constants::part_root_relationships().to_string();
|
||||
}
|
||||
|
||||
auto sep_pos = target.find_last_of(sep);
|
||||
|
@ -58,7 +58,7 @@ relationship_serializer::relationship_serializer(zip_file &archive) : archive_(a
|
|||
std::vector<relationship> relationship_serializer::read_relationships(const std::string &target)
|
||||
{
|
||||
pugi::xml_document xml;
|
||||
xml.load(archive_.read(make_rels_name(target)).c_str());
|
||||
xml.load(archive_.read(path(make_rels_name(target))).c_str());
|
||||
|
||||
auto root_node = xml.child("Relationships");
|
||||
|
||||
|
@ -101,7 +101,7 @@ bool relationship_serializer::write_relationships(const std::vector<relationship
|
|||
|
||||
std::ostringstream ss;
|
||||
xml.save(ss);
|
||||
archive_.writestr(make_rels_name(target), ss.str());
|
||||
archive_.write_string(ss.str(), path(make_rels_name(target)));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -23,13 +23,13 @@
|
|||
#pragma once
|
||||
|
||||
#include <iterator>
|
||||
#include <list>
|
||||
#include <vector>
|
||||
|
||||
#include <detail/stylesheet.hpp>
|
||||
#include <detail/worksheet_impl.hpp>
|
||||
#include <xlnt/packaging/app_properties.hpp>
|
||||
#include <xlnt/packaging/document_properties.hpp>
|
||||
#include <xlnt/packaging/manifest.hpp>
|
||||
#include <xlnt/utils/datetime.hpp>
|
||||
#include <xlnt/workbook/theme.hpp>
|
||||
#include <xlnt/worksheet/range.hpp>
|
||||
#include <xlnt/worksheet/range_reference.hpp>
|
||||
|
@ -42,7 +42,26 @@ struct worksheet_impl;
|
|||
|
||||
struct workbook_impl
|
||||
{
|
||||
workbook_impl();
|
||||
workbook_impl()
|
||||
: active_sheet_index_(0),
|
||||
guess_types_(false),
|
||||
data_only_(false),
|
||||
has_theme_(false),
|
||||
write_core_properties_(false),
|
||||
created_(xlnt::datetime::now()),
|
||||
modified_(xlnt::datetime::now()),
|
||||
title_("Untitled"),
|
||||
base_date_(calendar::windows_1900),
|
||||
write_app_properties_(false),
|
||||
application_("libxlnt"),
|
||||
doc_security_(0),
|
||||
scale_crop_(false),
|
||||
links_up_to_date_(false),
|
||||
shared_doc_(false),
|
||||
hyperlinks_changed_(false),
|
||||
app_version_("0.9")
|
||||
{
|
||||
}
|
||||
|
||||
workbook_impl(const workbook_impl &other)
|
||||
: active_sheet_index_(other.active_sheet_index_),
|
||||
|
@ -50,12 +69,32 @@ struct workbook_impl
|
|||
relationships_(other.relationships_),
|
||||
root_relationships_(other.root_relationships_),
|
||||
shared_strings_(other.shared_strings_),
|
||||
properties_(other.properties_),
|
||||
app_properties_(other.app_properties_),
|
||||
guess_types_(other.guess_types_),
|
||||
data_only_(other.data_only_),
|
||||
stylesheet_(other.stylesheet_),
|
||||
manifest_(other.manifest_)
|
||||
has_theme_(other.has_theme_),
|
||||
theme_(other.theme_),
|
||||
manifest_(other.manifest_),
|
||||
write_core_properties_(other.write_core_properties_),
|
||||
creator_(other.creator_),
|
||||
last_modified_by_(other.last_modified_by_),
|
||||
created_(other.created_),
|
||||
modified_(other.modified_),
|
||||
title_(other.title_),
|
||||
subject_(other.subject_),
|
||||
description_(other.description_),
|
||||
keywords_(other.keywords_),
|
||||
category_(other.category_),
|
||||
company_(other.company_),
|
||||
base_date_(other.base_date_),
|
||||
write_app_properties_(other.write_app_properties_),
|
||||
application_(other.application_),
|
||||
doc_security_(other.doc_security_),
|
||||
scale_crop_(other.scale_crop_),
|
||||
links_up_to_date_(other.links_up_to_date_),
|
||||
shared_doc_(other.shared_doc_),
|
||||
hyperlinks_changed_(other.hyperlinks_changed_),
|
||||
app_version_(other.app_version_)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -71,32 +110,78 @@ struct workbook_impl
|
|||
std::back_inserter(root_relationships_));
|
||||
shared_strings_.clear();
|
||||
std::copy(other.shared_strings_.begin(), other.shared_strings_.end(), std::back_inserter(shared_strings_));
|
||||
properties_ = other.properties_;
|
||||
app_properties_ = other.app_properties_;
|
||||
guess_types_ = other.guess_types_;
|
||||
data_only_ = other.data_only_;
|
||||
has_theme_ = other.has_theme_;
|
||||
theme_ = other.theme_;
|
||||
manifest_ = other.manifest_;
|
||||
|
||||
write_core_properties_ = other.write_core_properties_;
|
||||
creator_ = other.creator_;
|
||||
last_modified_by_ = other.last_modified_by_;
|
||||
created_ = other.created_;
|
||||
modified_ = other.modified_;
|
||||
title_ = other.title_;
|
||||
subject_ = other.subject_;
|
||||
description_ = other.description_;
|
||||
keywords_ = other.keywords_;
|
||||
category_ = other.category_;
|
||||
company_ = other.company_;
|
||||
base_date_ = other.base_date_;
|
||||
|
||||
write_app_properties_ = other.write_app_properties_;
|
||||
application_ = other.application_;
|
||||
doc_security_ = other.doc_security_;
|
||||
scale_crop_ = other.scale_crop_;
|
||||
links_up_to_date_ = other.links_up_to_date_;
|
||||
shared_doc_ = other.shared_doc_;
|
||||
hyperlinks_changed_ = other.hyperlinks_changed_;
|
||||
app_version_ = other.app_version_;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::size_t active_sheet_index_;
|
||||
std::vector<worksheet_impl> worksheets_;
|
||||
std::list<worksheet_impl> worksheets_;
|
||||
std::vector<relationship> relationships_;
|
||||
std::vector<relationship> root_relationships_;
|
||||
std::vector<text> shared_strings_;
|
||||
|
||||
document_properties properties_;
|
||||
app_properties app_properties_;
|
||||
|
||||
bool guess_types_;
|
||||
bool data_only_;
|
||||
|
||||
stylesheet stylesheet_;
|
||||
|
||||
manifest manifest_;
|
||||
bool has_theme_;
|
||||
theme theme_;
|
||||
std::vector<std::uint8_t> thumbnail_;
|
||||
|
||||
// core properties
|
||||
|
||||
bool write_core_properties_;
|
||||
std::string creator_;
|
||||
std::string last_modified_by_;
|
||||
datetime created_;
|
||||
datetime modified_;
|
||||
std::string title_;
|
||||
std::string subject_;
|
||||
std::string description_;
|
||||
std::string keywords_;
|
||||
std::string category_;
|
||||
std::string company_;
|
||||
calendar base_date_;
|
||||
|
||||
// application properties
|
||||
|
||||
bool write_app_properties_;
|
||||
std::string application_;
|
||||
int doc_security_;
|
||||
bool scale_crop_;
|
||||
bool links_up_to_date_;
|
||||
bool shared_doc_;
|
||||
bool hyperlinks_changed_;
|
||||
std::string app_version_;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
|
|
@ -85,83 +85,78 @@ workbook_serializer::workbook_serializer(workbook &wb) : workbook_(wb)
|
|||
|
||||
void workbook_serializer::read_properties_core(const pugi::xml_document &xml)
|
||||
{
|
||||
auto &props = workbook_.get_properties();
|
||||
auto root_node = xml.child("cp:coreProperties");
|
||||
|
||||
props.excel_base_date = calendar::windows_1900;
|
||||
|
||||
if (root_node.child("dc:creator"))
|
||||
{
|
||||
props.creator = root_node.child("dc:creator").text().get();
|
||||
workbook_.set_creator(root_node.child("dc:creator").text().get());
|
||||
}
|
||||
|
||||
if (root_node.child("cp:lastModifiedBy"))
|
||||
{
|
||||
props.last_modified_by = root_node.child("cp:lastModifiedBy").text().get();
|
||||
workbook_.set_last_modified_by(root_node.child("cp:lastModifiedBy").text().get());
|
||||
}
|
||||
|
||||
if (root_node.child("dcterms:created"))
|
||||
{
|
||||
std::string created_string = root_node.child("dcterms:created").text().get();
|
||||
props.created = w3cdtf_to_datetime(created_string);
|
||||
workbook_.set_created(w3cdtf_to_datetime(created_string));
|
||||
}
|
||||
|
||||
if (root_node.child("dcterms:modified"))
|
||||
{
|
||||
std::string modified_string = root_node.child("dcterms:modified").text().get();
|
||||
props.modified = w3cdtf_to_datetime(modified_string);
|
||||
workbook_.set_modified(w3cdtf_to_datetime(modified_string));
|
||||
}
|
||||
}
|
||||
|
||||
void workbook_serializer::read_properties_app(const pugi::xml_document &xml)
|
||||
{
|
||||
auto &props = workbook_.get_app_properties();
|
||||
auto root_node = xml.child("Properties");
|
||||
|
||||
if(root_node.child("Application"))
|
||||
{
|
||||
props.application = root_node.child("Application").text().get();
|
||||
workbook_.set_application(root_node.child("Application").text().get());
|
||||
}
|
||||
|
||||
if(root_node.child("DocSecurity"))
|
||||
{
|
||||
props.doc_security = std::stoi(root_node.child("DocSecurity").text().get());
|
||||
workbook_.set_doc_security(std::stoi(root_node.child("DocSecurity").text().get()));
|
||||
}
|
||||
|
||||
if(root_node.child("ScaleCrop"))
|
||||
{
|
||||
props.scale_crop = root_node.child("ScaleCrop").text().get() == std::string("true");
|
||||
workbook_.set_scale_crop(root_node.child("ScaleCrop").text().get() == std::string("true"));
|
||||
}
|
||||
|
||||
if(root_node.child("Company"))
|
||||
{
|
||||
props.company = root_node.child("Company").text().get();
|
||||
workbook_.set_company(root_node.child("Company").text().get());
|
||||
}
|
||||
|
||||
if(root_node.child("ScaleCrop"))
|
||||
{
|
||||
props.links_up_to_date = root_node.child("ScaleCrop").text().get() == std::string("true");
|
||||
workbook_.set_links_up_to_date(root_node.child("ScaleCrop").text().get() == std::string("true"));
|
||||
}
|
||||
|
||||
if(root_node.child("SharedDoc"))
|
||||
{
|
||||
props.shared_doc = root_node.child("SharedDoc").text().get() == std::string("true");
|
||||
workbook_.set_shared_doc(root_node.child("SharedDoc").text().get() == std::string("true"));
|
||||
}
|
||||
|
||||
if(root_node.child("HyperlinksChanged"))
|
||||
{
|
||||
props.hyperlinks_changed = root_node.child("HyperlinksChanged").text().get() == std::string("true");
|
||||
workbook_.set_hyperlinks_changed(root_node.child("HyperlinksChanged").text().get() == std::string("true"));
|
||||
}
|
||||
|
||||
if(root_node.child("AppVersion"))
|
||||
{
|
||||
props.app_version = root_node.child("AppVersion").text().get();
|
||||
workbook_.set_app_version(root_node.child("AppVersion").text().get());
|
||||
}
|
||||
}
|
||||
|
||||
void workbook_serializer::write_properties_core(pugi::xml_document &xml) const
|
||||
{
|
||||
auto &props = workbook_.get_properties();
|
||||
auto root_node = xml.append_child("cp:coreProperties");
|
||||
|
||||
root_node.append_attribute("xmlns:cp").set_value("http://schemas.openxmlformats.org/package/2006/metadata/core-properties");
|
||||
|
@ -170,13 +165,13 @@ void workbook_serializer::write_properties_core(pugi::xml_document &xml) const
|
|||
root_node.append_attribute("xmlns:dcterms").set_value("http://purl.org/dc/terms/");
|
||||
root_node.append_attribute("xmlns:xsi").set_value("http://www.w3.org/2001/XMLSchema-instance");
|
||||
|
||||
root_node.append_child("dc:creator").text().set(props.creator.c_str());
|
||||
root_node.append_child("cp:lastModifiedBy").text().set(props.last_modified_by.c_str());
|
||||
root_node.append_child("dcterms:created").text().set(datetime_to_w3cdtf(props.created).c_str());
|
||||
root_node.append_child("dc:creator").text().set(workbook_.get_creator().c_str());
|
||||
root_node.append_child("cp:lastModifiedBy").text().set(workbook_.get_last_modified_by().c_str());
|
||||
root_node.append_child("dcterms:created").text().set(datetime_to_w3cdtf(workbook_.get_created()).c_str());
|
||||
root_node.child("dcterms:created").append_attribute("xsi:type").set_value("dcterms:W3CDTF");
|
||||
root_node.append_child("dcterms:modified").text().set(datetime_to_w3cdtf(props.modified).c_str());
|
||||
root_node.append_child("dcterms:modified").text().set(datetime_to_w3cdtf(workbook_.get_modified()).c_str());
|
||||
root_node.child("dcterms:modified").append_attribute("xsi:type").set_value("dcterms:W3CDTF");
|
||||
root_node.append_child("dc:title").text().set(props.title.c_str());
|
||||
root_node.append_child("dc:title").text().set(workbook_.get_title().c_str());
|
||||
root_node.append_child("dc:description");
|
||||
root_node.append_child("dc:subject");
|
||||
root_node.append_child("cp:keywords");
|
||||
|
@ -190,23 +185,21 @@ void workbook_serializer::write_properties_app(pugi::xml_document &xml) const
|
|||
root_node.append_attribute("xmlns").set_value("http://schemas.openxmlformats.org/officeDocument/2006/extended-properties");
|
||||
root_node.append_attribute("xmlns:vt").set_value("http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes");
|
||||
|
||||
const auto &properties = workbook_.get_app_properties();
|
||||
|
||||
root_node.append_child("Application").text().set(properties.application.c_str());
|
||||
root_node.append_child("DocSecurity").text().set(std::to_string(properties.doc_security).c_str());
|
||||
root_node.append_child("ScaleCrop").text().set(properties.scale_crop ? "true" : "false");
|
||||
root_node.append_child("Application").text().set(workbook_.get_application().c_str());
|
||||
root_node.append_child("DocSecurity").text().set(std::to_string(workbook_.get_doc_security()).c_str());
|
||||
root_node.append_child("ScaleCrop").text().set(workbook_.get_scale_crop() ? "true" : "false");
|
||||
|
||||
auto company_node = root_node.append_child("Company");
|
||||
|
||||
if (!properties.company.empty())
|
||||
if (!workbook_.get_company().empty())
|
||||
{
|
||||
company_node.text().set(properties.company.c_str());
|
||||
company_node.text().set(workbook_.get_company().c_str());
|
||||
}
|
||||
|
||||
root_node.append_child("LinksUpToDate").text().set(properties.links_up_to_date ? "true" : "false");
|
||||
root_node.append_child("SharedDoc").text().set(properties.shared_doc ? "true" : "false");
|
||||
root_node.append_child("HyperlinksChanged").text().set(properties.hyperlinks_changed ? "true" : "false");
|
||||
root_node.append_child("AppVersion").text().set(properties.app_version.c_str());
|
||||
root_node.append_child("LinksUpToDate").text().set(workbook_.links_up_to_date() ? "true" : "false");
|
||||
root_node.append_child("SharedDoc").text().set(workbook_.is_shared_doc() ? "true" : "false");
|
||||
root_node.append_child("HyperlinksChanged").text().set(workbook_.hyperlinks_changed() ? "true" : "false");
|
||||
root_node.append_child("AppVersion").text().set(workbook_.get_app_version().c_str());
|
||||
|
||||
// TODO what is this stuff?
|
||||
|
||||
|
@ -261,7 +254,7 @@ void workbook_serializer::write_workbook(pugi::xml_document &xml) const
|
|||
auto workbook_pr_node = root_node.append_child("workbookPr");
|
||||
workbook_pr_node.append_attribute("codeName").set_value("ThisWorkbook");
|
||||
workbook_pr_node.append_attribute("defaultThemeVersion").set_value("124226");
|
||||
workbook_pr_node.append_attribute("date1904").set_value(workbook_.get_properties().excel_base_date == calendar::mac_1904 ? "1" : "0");
|
||||
workbook_pr_node.append_attribute("date1904").set_value(workbook_.get_base_date() == calendar::mac_1904 ? "1" : "0");
|
||||
|
||||
auto book_views_node = root_node.append_child("bookViews");
|
||||
auto workbook_view_node = book_views_node.append_child("workbookView");
|
||||
|
|
322
source/detail/xlsx_writer.cpp
Normal file
322
source/detail/xlsx_writer.cpp
Normal file
|
@ -0,0 +1,322 @@
|
|||
#include <detail/xlsx_writer.hpp>
|
||||
|
||||
#include <detail/constants.hpp>
|
||||
#include <detail/include_pugixml.hpp>
|
||||
#include <xlnt/utils/path.hpp>
|
||||
#include <xlnt/packaging/zip_file.hpp>
|
||||
#include <xlnt/workbook/const_worksheet_iterator.hpp>
|
||||
#include <xlnt/workbook/workbook.hpp>
|
||||
#include <xlnt/worksheet/worksheet.hpp>
|
||||
|
||||
namespace {
|
||||
|
||||
void write_document_to_archive(const pugi::xml_document &document,
|
||||
const xlnt::path &archive_path, xlnt::zip_file &archive)
|
||||
{
|
||||
std::ostringstream out_stream;
|
||||
document.save(out_stream);
|
||||
archive.write_string(out_stream.str(), archive_path);
|
||||
}
|
||||
|
||||
// Package Parts
|
||||
|
||||
void write_package_relationships(const xlnt::workbook &target, xlnt::zip_file &archive)
|
||||
{
|
||||
pugi::xml_document document;
|
||||
|
||||
auto relationships_node = document.append_child("Relationships");
|
||||
relationships_node.append_attribute("xmlns").set_value("http://schemas.openxmlformats.org/package/2006/relationships");
|
||||
|
||||
for (const auto &relationship : target.get_root_relationships())
|
||||
{
|
||||
auto relationship_node = relationships_node.append_child("Relationship");
|
||||
|
||||
relationship_node.append_attribute("Id").set_value(relationship.get_id().c_str());
|
||||
relationship_node.append_attribute("Type").set_value(relationship.get_type_string().c_str());
|
||||
relationship_node.append_attribute("Target").set_value(relationship.get_target_uri().c_str());
|
||||
}
|
||||
|
||||
write_document_to_archive(document, xlnt::constants::part_root_relationships(), archive);
|
||||
}
|
||||
|
||||
void write_content_types(const xlnt::workbook &target, xlnt::zip_file &archive)
|
||||
{
|
||||
pugi::xml_document document;
|
||||
|
||||
auto types_node = document.append_child("Types");
|
||||
types_node.append_attribute("xmlns").set_value("http://schemas.openxmlformats.org/package/2006/content-types");
|
||||
|
||||
auto default_node = types_node.append_child("Default");
|
||||
default_node.append_attribute("Extension").set_value("rels");
|
||||
default_node.append_attribute("ContentType").set_value("application/vnd.openxmlformats-package.relationships+xml");
|
||||
|
||||
auto workbook_override_node = types_node.append_child("Override");
|
||||
workbook_override_node.append_attribute("PartName").set_value("/workbook.xml");
|
||||
workbook_override_node.append_attribute("ContentType").set_value("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml");
|
||||
|
||||
auto sheet_override_node = types_node.append_child("Default");
|
||||
sheet_override_node.append_attribute("PartName").set_value("/sheet1.xml");
|
||||
sheet_override_node.append_attribute("ContentType").set_value("application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml");
|
||||
|
||||
write_document_to_archive(document, xlnt::constants::part_content_types(), archive);
|
||||
}
|
||||
|
||||
void write_app_properties(const xlnt::workbook &target, xlnt::zip_file &archive)
|
||||
{
|
||||
pugi::xml_document document;
|
||||
auto root_node = document.append_child("appProperties");
|
||||
write_document_to_archive(document, xlnt::constants::part_app(), archive);
|
||||
}
|
||||
|
||||
void write_core_properties(const xlnt::workbook &target, xlnt::zip_file &archive)
|
||||
{
|
||||
pugi::xml_document document;
|
||||
auto root_node = document.append_child("coreProperties");
|
||||
write_document_to_archive(document, xlnt::constants::part_core(), archive);
|
||||
}
|
||||
|
||||
void write_custom_file_properties(const xlnt::workbook &target, xlnt::zip_file &archive)
|
||||
{
|
||||
pugi::xml_document document;
|
||||
auto root_node = document.append_child("customFileProperties");
|
||||
write_document_to_archive(document, xlnt::constants::part_core(), archive);
|
||||
}
|
||||
|
||||
// SpreadsheetML Package Parts
|
||||
|
||||
void write_workbook(const xlnt::workbook &target, xlnt::zip_file &archive)
|
||||
{
|
||||
pugi::xml_document document;
|
||||
|
||||
auto workbook_node = document.append_child("workbook");
|
||||
workbook_node.append_attribute("xmlns").set_value("http://schemas.openxmlformats.org/spreadsheetml/2006/main");
|
||||
workbook_node.append_attribute("xmlns:r").set_value("http://schemas.openxmlformats.org/officeDocument/2006/relationships");
|
||||
|
||||
auto sheets_node = workbook_node.append_child("sheets");
|
||||
auto sheet_node = sheets_node.append_child("sheet");
|
||||
sheet_node.append_attribute("name").set_value(1);
|
||||
sheet_node.append_attribute("sheetId").set_value(1);
|
||||
sheet_node.append_attribute("r:id").set_value("rId1");
|
||||
|
||||
write_document_to_archive(document, xlnt::path("workbook.xml"), archive);
|
||||
}
|
||||
|
||||
void write_workbook_relationships(const xlnt::workbook &target, xlnt::zip_file &archive)
|
||||
{
|
||||
pugi::xml_document document;
|
||||
|
||||
auto relationships_node = document.append_child("Relationships");
|
||||
relationships_node.append_attribute("xmlns").set_value("http://schemas.openxmlformats.org/package/2006/relationships");
|
||||
|
||||
auto relationship_node = relationships_node.append_child("Relationship");
|
||||
relationship_node.append_attribute("Id").set_value("rId1");
|
||||
relationship_node.append_attribute("Type").set_value("http://purl.oclc.org/ooxml/officeDocument/relationships/worksheet");
|
||||
relationship_node.append_attribute("Target").set_value("sheet1.xml");
|
||||
|
||||
write_document_to_archive(document, xlnt::path("_rels/workbook.xml.rels"), archive);
|
||||
}
|
||||
|
||||
// Workbook Relationship Target Parts
|
||||
|
||||
void write_calculation_chain(const xlnt::workbook &target, xlnt::zip_file &archive)
|
||||
{
|
||||
pugi::xml_document document;
|
||||
auto root_node = document.append_child("calcChain");
|
||||
write_document_to_archive(document, xlnt::constants::part_core(), archive);
|
||||
}
|
||||
|
||||
void write_chartsheet(const xlnt::worksheet &target, xlnt::zip_file &archive)
|
||||
{
|
||||
pugi::xml_document document;
|
||||
auto root_node = document.append_child("chartsheet");
|
||||
write_document_to_archive(document, xlnt::constants::part_core(), archive);
|
||||
}
|
||||
|
||||
void write_connections(const xlnt::workbook &target, xlnt::zip_file &archive)
|
||||
{
|
||||
pugi::xml_document document;
|
||||
auto root_node = document.append_child("connections");
|
||||
write_document_to_archive(document, xlnt::constants::part_core(), archive);
|
||||
}
|
||||
|
||||
void write_custom_property(const xlnt::workbook &target, xlnt::zip_file &archive)
|
||||
{
|
||||
pugi::xml_document document;
|
||||
auto root_node = document.append_child("customProperty");
|
||||
write_document_to_archive(document, xlnt::constants::part_core(), archive);
|
||||
}
|
||||
|
||||
void write_custom_xml_mappings(const xlnt::workbook &target, xlnt::zip_file &archive)
|
||||
{
|
||||
pugi::xml_document document;
|
||||
auto root_node = document.append_child("connections");
|
||||
write_document_to_archive(document, xlnt::constants::part_core(), archive);
|
||||
}
|
||||
|
||||
void write_dialogsheet(const xlnt::worksheet &target, xlnt::zip_file &archive)
|
||||
{
|
||||
pugi::xml_document document;
|
||||
auto root_node = document.append_child("dialogsheet");
|
||||
write_document_to_archive(document, xlnt::constants::part_core(), archive);
|
||||
}
|
||||
|
||||
void write_external_workbook_references(const xlnt::workbook &target, xlnt::zip_file &archive)
|
||||
{
|
||||
pugi::xml_document document;
|
||||
auto root_node = document.append_child("externalLink");
|
||||
write_document_to_archive(document, xlnt::constants::part_core(), archive);
|
||||
}
|
||||
|
||||
void write_metadata(const xlnt::workbook &target, xlnt::zip_file &archive)
|
||||
{
|
||||
pugi::xml_document document;
|
||||
auto root_node = document.append_child("metadata");
|
||||
write_document_to_archive(document, xlnt::constants::part_core(), archive);
|
||||
}
|
||||
|
||||
void write_pivot_table(const xlnt::workbook &target, xlnt::zip_file &archive)
|
||||
{
|
||||
pugi::xml_document document;
|
||||
auto root_node = document.append_child("pivotTableDefinition");
|
||||
write_document_to_archive(document, xlnt::constants::part_core(), archive);
|
||||
}
|
||||
|
||||
void write_shared_string_table(const xlnt::workbook &target, xlnt::zip_file &archive)
|
||||
{
|
||||
pugi::xml_document document;
|
||||
auto root_node = document.append_child("sst");
|
||||
write_document_to_archive(document, xlnt::constants::part_core(), archive);
|
||||
}
|
||||
|
||||
void write_shared_workbook_revision_headers(const xlnt::workbook &target, xlnt::zip_file &archive)
|
||||
{
|
||||
pugi::xml_document document;
|
||||
auto root_node = document.append_child("headers");
|
||||
write_document_to_archive(document, xlnt::constants::part_core(), archive);
|
||||
}
|
||||
|
||||
void write_shared_workbook(const xlnt::workbook &target, xlnt::zip_file &archive)
|
||||
{
|
||||
pugi::xml_document document;
|
||||
auto root_node = document.append_child("revisions");
|
||||
write_document_to_archive(document, xlnt::constants::part_core(), archive);
|
||||
}
|
||||
|
||||
void write_shared_workbook_user_data(const xlnt::workbook &target, xlnt::zip_file &archive)
|
||||
{
|
||||
pugi::xml_document document;
|
||||
auto root_node = document.append_child("users");
|
||||
write_document_to_archive(document, xlnt::constants::part_core(), archive);
|
||||
}
|
||||
|
||||
void write_styles(const xlnt::workbook &target, xlnt::zip_file &archive)
|
||||
{
|
||||
pugi::xml_document document;
|
||||
auto root_node = document.append_child("styleSheet");
|
||||
write_document_to_archive(document, xlnt::constants::part_core(), archive);
|
||||
}
|
||||
|
||||
void write_theme(const xlnt::workbook &target, xlnt::zip_file &archive)
|
||||
{
|
||||
pugi::xml_document document;
|
||||
auto root_node = document.append_child("theme");
|
||||
write_document_to_archive(document, xlnt::constants::part_core(), archive);
|
||||
}
|
||||
|
||||
void write_volatile_dependencies(const xlnt::workbook &target, xlnt::zip_file &archive)
|
||||
{
|
||||
pugi::xml_document document;
|
||||
auto root_node = document.append_child("volTypes");
|
||||
write_document_to_archive(document, xlnt::constants::part_core(), archive);
|
||||
}
|
||||
|
||||
void write_worksheet(const xlnt::worksheet &target, xlnt::zip_file &archive)
|
||||
{
|
||||
pugi::xml_document document;
|
||||
|
||||
auto worksheet_node = document.append_child("worksheet");
|
||||
worksheet_node.append_attribute("xmlns").set_value("http://schemas.openxmlformats.org/spreadsheetml/2006/main");
|
||||
worksheet_node.append_attribute("xmlns:r").set_value("http://schemas.openxmlformats.org/package/2006/relationships");
|
||||
|
||||
worksheet_node.append_child("sheetData");
|
||||
|
||||
write_document_to_archive(document, xlnt::path("sheet1.xml"), archive);
|
||||
}
|
||||
|
||||
// Sheet Relationship Target Parts
|
||||
|
||||
void write_comments(const xlnt::workbook &target, xlnt::zip_file &archive)
|
||||
{
|
||||
pugi::xml_document document;
|
||||
auto root_node = document.append_child("comments");
|
||||
write_document_to_archive(document, xlnt::constants::part_core(), archive);
|
||||
}
|
||||
|
||||
void write_drawings(const xlnt::worksheet &target, xlnt::zip_file &archive)
|
||||
{
|
||||
pugi::xml_document document;
|
||||
auto root_node = document.append_child("wsDr");
|
||||
write_document_to_archive(document, xlnt::constants::part_core(), archive);
|
||||
}
|
||||
|
||||
// Unknown Parts
|
||||
|
||||
void write_unknown_parts(const xlnt::workbook &target, xlnt::zip_file &archive)
|
||||
{
|
||||
pugi::xml_document document;
|
||||
auto root_node = document.append_child("relationships");
|
||||
write_document_to_archive(document, xlnt::constants::part_core(), archive);
|
||||
}
|
||||
|
||||
void write_unknown_relationships(const xlnt::workbook &target, xlnt::zip_file &archive)
|
||||
{
|
||||
pugi::xml_document document;
|
||||
auto root_node = document.append_child("Relationships");
|
||||
write_document_to_archive(document, xlnt::constants::part_core(), archive);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace xlnt
|
||||
{
|
||||
|
||||
xlsx_writer::xlsx_writer(const workbook &target) : target_(target)
|
||||
{
|
||||
}
|
||||
|
||||
void xlsx_writer::write(const path &destination)
|
||||
{
|
||||
xlnt::zip_file archive;
|
||||
populate_archive(archive);
|
||||
archive.save(destination);
|
||||
}
|
||||
|
||||
void xlsx_writer::write(std::ostream &destination)
|
||||
{
|
||||
xlnt::zip_file archive;
|
||||
populate_archive(archive);
|
||||
archive.save(destination);
|
||||
}
|
||||
|
||||
void xlsx_writer::write(std::vector<std::uint8_t> &destination)
|
||||
{
|
||||
xlnt::zip_file archive;
|
||||
populate_archive(archive);
|
||||
archive.save(destination);
|
||||
}
|
||||
|
||||
void xlsx_writer::populate_archive(zip_file &archive)
|
||||
{
|
||||
write_package_relationships(target_, archive);
|
||||
write_content_types(target_, archive);
|
||||
|
||||
write_workbook(target_, archive);
|
||||
write_workbook_relationships(target_, archive);
|
||||
|
||||
for (auto ws : target_)
|
||||
{
|
||||
write_worksheet(ws, archive);
|
||||
}
|
||||
}
|
||||
|
||||
} // namepsace xlnt
|
65
source/detail/xlsx_writer.hpp
Normal file
65
source/detail/xlsx_writer.hpp
Normal file
|
@ -0,0 +1,65 @@
|
|||
// 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
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
#include <xlnt/xlnt_config.hpp>
|
||||
|
||||
namespace xlnt {
|
||||
|
||||
class path;
|
||||
class workbook;
|
||||
class zip_file;
|
||||
|
||||
/// <summary>
|
||||
/// Handles writing a workbook into an XLSX file.
|
||||
/// </summary>
|
||||
class XLNT_CLASS xlsx_writer
|
||||
{
|
||||
public:
|
||||
xlsx_writer(const workbook &target);
|
||||
|
||||
void write(const path &destination);
|
||||
|
||||
void write(std::ostream &destination);
|
||||
|
||||
void write(std::vector<std::uint8_t> &destination);
|
||||
|
||||
private:
|
||||
/// <summary>
|
||||
/// Write all files needed to create a valid XLSX file which represents all
|
||||
/// data contained in workbook.
|
||||
/// </summary>
|
||||
void populate_archive(zip_file &archive);
|
||||
|
||||
/// <summary>
|
||||
/// A reference to the workbook which is the object of read/write operations.
|
||||
/// </summary>
|
||||
const workbook &target_;
|
||||
};
|
||||
|
||||
} // namespace xlnt
|
|
@ -39,9 +39,9 @@ bool manifest::has_default_type(const std::string &extension) const
|
|||
return default_types_.find(extension) != default_types_.end();
|
||||
}
|
||||
|
||||
bool manifest::has_override_type(const std::string &part_name) const
|
||||
bool manifest::has_override_type(const path &part) const
|
||||
{
|
||||
auto absolute = part_name.front() == '/' ? part_name : ("/" + part_name);
|
||||
auto absolute = part.is_absolute() ? part : part.make_absolute(path("/"));
|
||||
return override_types_.find(absolute) != override_types_.end();
|
||||
}
|
||||
|
||||
|
@ -50,9 +50,9 @@ void manifest::add_default_type(const std::string &extension, const std::string
|
|||
default_types_[extension] = default_type(extension, content_type);
|
||||
}
|
||||
|
||||
void manifest::add_override_type(const std::string &part_name, const std::string &content_type)
|
||||
void manifest::add_override_type(const path &part, const std::string &content_type)
|
||||
{
|
||||
auto absolute = part_name.front() == '/' ? part_name : ("/" + part_name);
|
||||
auto absolute = part.is_absolute() ? part : part.make_absolute(path("/"));
|
||||
override_types_[absolute] = override_type(absolute, content_type);
|
||||
}
|
||||
|
||||
|
@ -61,18 +61,18 @@ std::string manifest::get_default_type(const std::string &extension) const
|
|||
return default_types_.at(extension).get_content_type();
|
||||
}
|
||||
|
||||
std::string manifest::get_override_type(const std::string &part_name) const
|
||||
std::string manifest::get_override_type(const path &part) const
|
||||
{
|
||||
auto absolute = part_name.front() == '/' ? part_name : ("/" + part_name);
|
||||
auto absolute = part.is_absolute() ? part : part.make_absolute(path("/"));
|
||||
return override_types_.at(absolute).get_content_type();
|
||||
}
|
||||
|
||||
const std::unordered_map<std::string, default_type> &manifest::get_default_types() const
|
||||
const manifest::default_types_container &manifest::get_default_types() const
|
||||
{
|
||||
return default_types_;
|
||||
}
|
||||
|
||||
const std::unordered_map<std::string, override_type> &manifest::get_override_types() const
|
||||
const manifest::override_types_container &manifest::get_override_types() const
|
||||
{
|
||||
return override_types_;
|
||||
}
|
||||
|
|
|
@ -29,27 +29,27 @@ override_type::override_type()
|
|||
{
|
||||
}
|
||||
|
||||
override_type::override_type(const std::string &part_name, const std::string &content_type)
|
||||
: part_name_(part_name), content_type_(content_type)
|
||||
override_type::override_type(const path &part, const std::string &content_type)
|
||||
: part_(part), content_type_(content_type)
|
||||
{
|
||||
}
|
||||
|
||||
override_type::override_type(const override_type &other)
|
||||
: part_name_(other.part_name_), content_type_(other.content_type_)
|
||||
: part_(other.part_), content_type_(other.content_type_)
|
||||
{
|
||||
}
|
||||
|
||||
override_type &override_type::operator=(const override_type &other)
|
||||
{
|
||||
part_name_ = other.part_name_;
|
||||
part_ = other.part_;
|
||||
content_type_ = other.content_type_;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::string override_type::get_part_name() const
|
||||
path override_type::get_part() const
|
||||
{
|
||||
return part_name_;
|
||||
return part_;
|
||||
}
|
||||
|
||||
std::string override_type::get_content_type() const
|
||||
|
|
|
@ -14,19 +14,18 @@ class test_core : public CxxTest::TestSuite
|
|||
public:
|
||||
void test_read_properties_core()
|
||||
{
|
||||
auto path = path_helper::get_data_directory() + "/genuine/empty.xlsx";
|
||||
xlnt::workbook wb;
|
||||
wb.load(path);
|
||||
auto &prop = wb.get_properties();
|
||||
TS_ASSERT_EQUALS(prop.creator, "*.*");
|
||||
TS_ASSERT_EQUALS(prop.last_modified_by, "Charlie Clark");
|
||||
TS_ASSERT_EQUALS(prop.created, xlnt::datetime(2010, 4, 9, 20, 43, 12));
|
||||
TS_ASSERT_EQUALS(prop.modified, xlnt::datetime(2014, 1, 2, 14, 53, 6));
|
||||
wb.load(path_helper::get_data_directory("genuine/empty.xlsx"));
|
||||
|
||||
TS_ASSERT_EQUALS(wb.get_creator(), "*.*");
|
||||
TS_ASSERT_EQUALS(wb.get_last_modified_by(), "Charlie Clark");
|
||||
TS_ASSERT_EQUALS(wb.get_created(), xlnt::datetime(2010, 4, 9, 20, 43, 12));
|
||||
TS_ASSERT_EQUALS(wb.get_modified(), xlnt::datetime(2014, 1, 2, 14, 53, 6));
|
||||
}
|
||||
|
||||
void test_read_sheets_titles()
|
||||
{
|
||||
auto path = path_helper::get_data_directory() + "/genuine/empty.xlsx";
|
||||
auto path = path_helper::get_data_directory("genuine/empty.xlsx");
|
||||
|
||||
const std::vector<std::string> expected_titles = {"Sheet1 - Text", "Sheet2 - Numbers", "Sheet3 - Formulas", "Sheet4 - Dates"};
|
||||
|
||||
|
@ -43,58 +42,49 @@ public:
|
|||
|
||||
void test_read_properties_core_libre()
|
||||
{
|
||||
xlnt::zip_file archive(path_helper::get_data_directory() + "/genuine/empty_libre.xlsx");
|
||||
auto content = archive.read("docProps/core.xml");
|
||||
xlnt::workbook wb;
|
||||
xlnt::workbook_serializer serializer(wb);
|
||||
pugi::xml_document xml;
|
||||
serializer.read_properties_core(xml);
|
||||
auto &prop = wb.get_properties();
|
||||
TS_ASSERT_EQUALS(prop.excel_base_date, xlnt::calendar::windows_1900);
|
||||
wb.load(path_helper::get_data_directory("genuine/empty_libre.xlsx"));
|
||||
TS_ASSERT_EQUALS(wb.get_base_date(), xlnt::calendar::windows_1900);
|
||||
}
|
||||
|
||||
void test_read_sheets_titles_libre()
|
||||
{
|
||||
auto path = path_helper::get_data_directory() + "/genuine/empty_libre.xlsx";
|
||||
|
||||
const std::vector<std::string> expected_titles = {"Sheet1 - Text", "Sheet2 - Numbers", "Sheet3 - Formulas", "Sheet4 - Dates"};
|
||||
|
||||
std::size_t i = 0;
|
||||
|
||||
xlnt::workbook wb;
|
||||
wb.load(path);
|
||||
wb.load(path_helper::get_data_directory("genuine/empty_libre.xlsx"));
|
||||
auto title_iter = expected_titles.begin();
|
||||
|
||||
for(auto sheet : wb)
|
||||
for(auto ws : wb)
|
||||
{
|
||||
TS_ASSERT_EQUALS(sheet.get_title(), expected_titles.at(i++));
|
||||
TS_ASSERT_EQUALS(ws.get_title(), *(title_iter++));
|
||||
}
|
||||
}
|
||||
|
||||
void test_write_properties_core()
|
||||
{
|
||||
xlnt::workbook wb;
|
||||
xlnt::document_properties &prop = wb.get_properties();
|
||||
prop.creator = "TEST_USER";
|
||||
prop.last_modified_by = "SOMEBODY";
|
||||
prop.created = xlnt::datetime(2010, 4, 1, 20, 30, 00);
|
||||
prop.modified = xlnt::datetime(2010, 4, 5, 14, 5, 30);
|
||||
wb.set_creator("TEST_USER");
|
||||
wb.set_last_modified_by("SOMEBODY");
|
||||
wb.set_created(xlnt::datetime(2010, 4, 1, 20, 30, 00));
|
||||
wb.set_modified(xlnt::datetime(2010, 4, 5, 14, 5, 30));
|
||||
xlnt::workbook_serializer serializer(wb);
|
||||
pugi::xml_document xml;
|
||||
serializer.write_properties_core(xml);
|
||||
TS_ASSERT(xml_helper::compare_xml(path_helper::get_data_directory() + "/writer/expected/core.xml", xml));
|
||||
TS_ASSERT(xml_helper::file_matches_document(path_helper::get_data_directory("writer/expected/core.xml"), xml));
|
||||
}
|
||||
|
||||
void test_write_properties_app()
|
||||
{
|
||||
xlnt::workbook wb;
|
||||
wb.get_app_properties().application = "Microsoft Excel";
|
||||
wb.get_app_properties().app_version = "12.0000";
|
||||
wb.get_app_properties().company = "Company";
|
||||
wb.set_application("Microsoft Excel");
|
||||
wb.set_app_version("12.0000");
|
||||
wb.set_company("Company");
|
||||
wb.create_sheet();
|
||||
wb.create_sheet();
|
||||
xlnt::workbook_serializer serializer(wb);
|
||||
pugi::xml_document xml;
|
||||
serializer.write_properties_app(xml);
|
||||
TS_ASSERT(xml_helper::compare_xml(path_helper::get_data_directory() + "/writer/expected/app.xml", xml));
|
||||
TS_ASSERT(xml_helper::file_matches_document(path_helper::get_data_directory("writer/expected/app.xml"), xml));
|
||||
}
|
||||
};
|
||||
|
|
|
@ -38,104 +38,23 @@
|
|||
|
||||
#include <detail/include_windows.hpp>
|
||||
#include <xlnt/packaging/zip_file.hpp>
|
||||
#include <xlnt/utils/path.hpp>
|
||||
|
||||
namespace {
|
||||
|
||||
std::string get_working_directory()
|
||||
void mkdir_recursive(const xlnt::path &path)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
TCHAR buffer[MAX_PATH];
|
||||
GetCurrentDirectory(MAX_PATH, buffer);
|
||||
std::basic_string<TCHAR> working_directory(buffer);
|
||||
return std::string(working_directory.begin(), working_directory.end());
|
||||
#else
|
||||
char buffer[2048];
|
||||
getcwd(buffer, 2048);
|
||||
return std::string(buffer);
|
||||
#endif
|
||||
}
|
||||
if (path.exists()) return;
|
||||
|
||||
#ifdef _WIN32
|
||||
char directory_separator = '\\';
|
||||
char alt_directory_separator = '/';
|
||||
#else
|
||||
char directory_separator = '/';
|
||||
char alt_directory_separator = '\\';
|
||||
#endif
|
||||
auto parent = path.parent();
|
||||
|
||||
std::string join_path(const std::vector<std::string> &parts)
|
||||
{
|
||||
std::string joined;
|
||||
std::size_t i = 0;
|
||||
for (auto part : parts)
|
||||
if (!parent.is_root())
|
||||
{
|
||||
joined.append(part);
|
||||
|
||||
if (i++ != parts.size() - 1)
|
||||
{
|
||||
joined.append(1, '/');
|
||||
}
|
||||
}
|
||||
return joined;
|
||||
}
|
||||
|
||||
std::vector<std::string> split_path(const std::string &path, char delim = directory_separator)
|
||||
{
|
||||
std::vector<std::string> split;
|
||||
std::string::size_type previous_index = 0;
|
||||
auto separator_index = path.find(delim);
|
||||
|
||||
while (separator_index != std::string::npos)
|
||||
{
|
||||
auto part = path.substr(previous_index, separator_index - previous_index);
|
||||
if (part != "..")
|
||||
{
|
||||
split.push_back(part);
|
||||
}
|
||||
else
|
||||
{
|
||||
split.pop_back();
|
||||
}
|
||||
previous_index = separator_index + 1;
|
||||
separator_index = path.find(delim, previous_index);
|
||||
}
|
||||
|
||||
split.push_back(path.substr(previous_index));
|
||||
|
||||
if (split.size() == 1 && delim == directory_separator)
|
||||
{
|
||||
auto alternative = split_path(path, alt_directory_separator);
|
||||
if (alternative.size() > 1)
|
||||
{
|
||||
return alternative;
|
||||
}
|
||||
}
|
||||
|
||||
return split;
|
||||
}
|
||||
|
||||
bool directory_exists(const std::string path)
|
||||
{
|
||||
struct stat info;
|
||||
return stat(path.c_str(), &info) == 0 && (info.st_mode & S_IFDIR);
|
||||
}
|
||||
|
||||
void mkdir_recursive(const std::string path)
|
||||
{
|
||||
if (directory_exists(path)) return;
|
||||
|
||||
auto split = split_path(path);
|
||||
auto last = split.back();
|
||||
split.pop_back();
|
||||
|
||||
if (!split.empty())
|
||||
{
|
||||
auto parent = join_path(split);
|
||||
mkdir_recursive(parent);
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
_mkdir(path.c_str());
|
||||
_mkdir(path.to_string().c_str());
|
||||
#else
|
||||
mkdir(path.c_str(), 0755);
|
||||
#endif
|
||||
|
@ -249,7 +168,7 @@ zip_file::zip_file() : archive_(new mz_zip_archive())
|
|||
reset();
|
||||
}
|
||||
|
||||
zip_file::zip_file(const std::string &filename) : zip_file()
|
||||
zip_file::zip_file(const path &filename) : zip_file()
|
||||
{
|
||||
load(filename);
|
||||
}
|
||||
|
@ -277,10 +196,10 @@ void zip_file::load(std::istream &stream)
|
|||
start_read();
|
||||
}
|
||||
|
||||
void zip_file::load(const std::string &filename)
|
||||
void zip_file::load(const path &filename)
|
||||
{
|
||||
filename_ = filename;
|
||||
std::ifstream stream(filename, std::ios::binary);
|
||||
std::ifstream stream(filename.to_string(), std::ios::binary);
|
||||
load(stream);
|
||||
}
|
||||
|
||||
|
@ -292,10 +211,10 @@ void zip_file::load(const std::vector<unsigned char> &bytes)
|
|||
start_read();
|
||||
}
|
||||
|
||||
void zip_file::save(const std::string &filename)
|
||||
void zip_file::save(const path &filename)
|
||||
{
|
||||
filename_ = filename;
|
||||
std::ofstream stream(filename, std::ios::binary);
|
||||
std::ofstream stream(filename.to_string(), std::ios::binary);
|
||||
save(stream);
|
||||
}
|
||||
|
||||
|
@ -409,14 +328,14 @@ void zip_file::reset()
|
|||
mz_zip_writer_end(archive_.get());
|
||||
}
|
||||
|
||||
zip_info zip_file::getinfo(const std::string &name)
|
||||
zip_info zip_file::getinfo(const path &name)
|
||||
{
|
||||
if (archive_->m_zip_mode != MZ_ZIP_MODE_READING)
|
||||
{
|
||||
start_read();
|
||||
}
|
||||
|
||||
int index = mz_zip_reader_locate_file(archive_.get(), name.c_str(), nullptr, 0);
|
||||
int index = mz_zip_reader_locate_file(archive_.get(), name.to_string('/').c_str(), nullptr, 0);
|
||||
|
||||
if (index == -1)
|
||||
{
|
||||
|
@ -438,7 +357,7 @@ zip_info zip_file::getinfo(int index)
|
|||
|
||||
zip_info result;
|
||||
|
||||
result.filename = std::string(stat.m_filename, stat.m_filename + std::strlen(stat.m_filename));
|
||||
result.filename = path(std::string(stat.m_filename, stat.m_filename + std::strlen(stat.m_filename)));
|
||||
result.comment = std::string(stat.m_comment, stat.m_comment + stat.m_comment_size);
|
||||
result.compress_size = static_cast<std::size_t>(stat.m_comp_size);
|
||||
result.file_size = static_cast<std::size_t>(stat.m_uncomp_size);
|
||||
|
@ -531,40 +450,54 @@ void zip_file::start_write()
|
|||
mz_zip_writer_init(archive_.get(), 0);
|
||||
}
|
||||
|
||||
void zip_file::write(const std::string &filename)
|
||||
void zip_file::write_file(const path &filename)
|
||||
{
|
||||
auto split = split_path(filename);
|
||||
if (split.size() > 1)
|
||||
path arcname(filename);
|
||||
|
||||
if (filename.is_absolute())
|
||||
{
|
||||
split.erase(split.begin());
|
||||
arcname = path();
|
||||
bool first = true;
|
||||
|
||||
for (auto part : filename)
|
||||
{
|
||||
if (first)
|
||||
{
|
||||
first = false;
|
||||
continue;
|
||||
}
|
||||
auto arcname = join_path(split);
|
||||
write(filename, arcname);
|
||||
|
||||
arcname.append(part);
|
||||
}
|
||||
}
|
||||
|
||||
write_file(filename, arcname);
|
||||
}
|
||||
|
||||
void zip_file::write(const std::string &filename, const std::string &arcname)
|
||||
void zip_file::write_file(const path &filename, const path &arcname)
|
||||
{
|
||||
std::fstream file(filename, std::ios::binary | std::ios::in);
|
||||
std::fstream file(filename.to_string(), std::ios::binary | std::ios::in);
|
||||
|
||||
std::stringstream ss;
|
||||
ss << file.rdbuf();
|
||||
std::string bytes = ss.str();
|
||||
|
||||
writestr(arcname, bytes);
|
||||
write_string(ss.str(), arcname);
|
||||
}
|
||||
|
||||
void zip_file::writestr(const std::string &arcname, const std::string &bytes)
|
||||
void zip_file::write_string(const std::string &bytes, const path &arcname)
|
||||
{
|
||||
if (archive_->m_zip_mode != MZ_ZIP_MODE_WRITING)
|
||||
{
|
||||
start_write();
|
||||
}
|
||||
|
||||
mz_zip_writer_add_mem(archive_.get(), arcname.c_str(), bytes.data(), bytes.size(), MZ_BEST_COMPRESSION);
|
||||
mz_zip_writer_add_mem(archive_.get(), arcname.to_string('/').c_str(),
|
||||
bytes.data(), bytes.size(), MZ_BEST_COMPRESSION);
|
||||
}
|
||||
|
||||
void zip_file::writestr(const zip_info &info, const std::string &bytes)
|
||||
void zip_file::write_string(const std::string &bytes, const zip_info &info)
|
||||
{
|
||||
if (info.filename.empty() || info.date_time.year < 1980)
|
||||
if (info.filename.to_string().empty() || info.date_time.year < 1980)
|
||||
{
|
||||
throw std::runtime_error("must specify a filename and valid date (year >= 1980");
|
||||
}
|
||||
|
@ -576,7 +509,7 @@ void zip_file::writestr(const zip_info &info, const std::string &bytes)
|
|||
|
||||
auto crc = crc32buf(bytes.c_str(), bytes.size());
|
||||
|
||||
mz_zip_writer_add_mem_ex(archive_.get(), info.filename.c_str(), bytes.data(), bytes.size(),
|
||||
mz_zip_writer_add_mem_ex(archive_.get(), info.filename.to_string('/').c_str(), bytes.data(), bytes.size(),
|
||||
info.comment.c_str(), static_cast<mz_uint16>(info.comment.size()),
|
||||
MZ_BEST_COMPRESSION, 0, crc);
|
||||
}
|
||||
|
@ -584,30 +517,34 @@ void zip_file::writestr(const zip_info &info, const std::string &bytes)
|
|||
std::string zip_file::read(const zip_info &info)
|
||||
{
|
||||
std::size_t size;
|
||||
char *data =
|
||||
static_cast<char *>(mz_zip_reader_extract_file_to_heap(archive_.get(), info.filename.c_str(), &size, 0));
|
||||
if (data == nullptr)
|
||||
void *data_raw = mz_zip_reader_extract_file_to_heap(archive_.get(),
|
||||
info.filename.to_string('/').c_str(), &size, 0);
|
||||
|
||||
if (data_raw == nullptr)
|
||||
{
|
||||
throw std::runtime_error("file couldn't be read");
|
||||
}
|
||||
|
||||
auto data = static_cast<char *>(data_raw);
|
||||
std::string extracted(data, data + size);
|
||||
mz_free(data);
|
||||
|
||||
return extracted;
|
||||
}
|
||||
|
||||
std::string zip_file::read(const std::string &name)
|
||||
std::string zip_file::read(const path &name)
|
||||
{
|
||||
return read(getinfo(name));
|
||||
}
|
||||
|
||||
bool zip_file::has_file(const std::string &name)
|
||||
bool zip_file::has_file(const path &name)
|
||||
{
|
||||
if (archive_->m_zip_mode != MZ_ZIP_MODE_READING)
|
||||
{
|
||||
start_read();
|
||||
}
|
||||
|
||||
int index = mz_zip_reader_locate_file(archive_.get(), name.c_str(), nullptr, 0);
|
||||
int index = mz_zip_reader_locate_file(archive_.get(), name.to_string('/').c_str(), nullptr, 0);
|
||||
|
||||
return index != -1;
|
||||
}
|
||||
|
@ -634,9 +571,9 @@ std::vector<zip_info> zip_file::infolist()
|
|||
return info;
|
||||
}
|
||||
|
||||
std::vector<std::string> zip_file::namelist()
|
||||
std::vector<path> zip_file::namelist()
|
||||
{
|
||||
std::vector<std::string> names;
|
||||
std::vector<path> names;
|
||||
|
||||
for (auto &info : infolist())
|
||||
{
|
||||
|
@ -646,7 +583,7 @@ std::vector<std::string> zip_file::namelist()
|
|||
return names;
|
||||
}
|
||||
|
||||
std::ostream &zip_file::open(const std::string &name)
|
||||
std::ostream &zip_file::open(const path &name)
|
||||
{
|
||||
return open(getinfo(name));
|
||||
}
|
||||
|
@ -659,118 +596,7 @@ std::ostream &zip_file::open(const zip_info &name)
|
|||
return open_stream_;
|
||||
}
|
||||
|
||||
void zip_file::extract(const std::string &member)
|
||||
{
|
||||
extract(member, get_working_directory());
|
||||
}
|
||||
|
||||
void zip_file::extract(const std::string &member, const std::string &path)
|
||||
{
|
||||
auto member_split = split_path(member);
|
||||
auto fullpath_parts = split_path(path);
|
||||
fullpath_parts.insert(fullpath_parts.end(), member_split.begin(), member_split.end());
|
||||
auto fullpath = join_path(fullpath_parts);
|
||||
|
||||
auto directory = fullpath_parts;
|
||||
directory.pop_back();
|
||||
mkdir_recursive(join_path(directory));
|
||||
|
||||
std::fstream stream(fullpath, std::ios::binary | std::ios::out);
|
||||
stream << open(member).rdbuf();
|
||||
}
|
||||
|
||||
void zip_file::extract(const zip_info &member)
|
||||
{
|
||||
extract(member, get_working_directory());
|
||||
}
|
||||
|
||||
void zip_file::extract(const zip_info &member, const std::string &path)
|
||||
{
|
||||
std::fstream stream(join_path({ path, member.filename }), std::ios::binary | std::ios::out);
|
||||
stream << open(member).rdbuf();
|
||||
}
|
||||
|
||||
void zip_file::extractall(const std::string &path)
|
||||
{
|
||||
extractall(path, infolist());
|
||||
}
|
||||
|
||||
void zip_file::extractall(const std::string &path, const std::vector<std::string> &members)
|
||||
{
|
||||
for (auto &member : members)
|
||||
{
|
||||
extract(member, path);
|
||||
}
|
||||
}
|
||||
|
||||
void zip_file::extractall(const std::string &path, const std::vector<zip_info> &members)
|
||||
{
|
||||
for (auto &member : members)
|
||||
{
|
||||
extract(member, path);
|
||||
}
|
||||
}
|
||||
|
||||
void zip_file::printdir()
|
||||
{
|
||||
printdir(std::cout);
|
||||
}
|
||||
|
||||
void zip_file::printdir(std::ostream &stream)
|
||||
{
|
||||
stream << " Length "
|
||||
<< " "
|
||||
<< " "
|
||||
<< "Date"
|
||||
<< " "
|
||||
<< " "
|
||||
<< "Time "
|
||||
<< " "
|
||||
<< "Name" << std::endl;
|
||||
stream << "--------- ---------- ----- ----" << std::endl;
|
||||
|
||||
std::size_t sum_length = 0;
|
||||
std::size_t file_count = 0;
|
||||
|
||||
for (auto &member : infolist())
|
||||
{
|
||||
sum_length += member.file_size;
|
||||
file_count++;
|
||||
|
||||
std::string length_string = std::to_string(member.file_size);
|
||||
while (length_string.length() < 9)
|
||||
{
|
||||
length_string = " " + length_string;
|
||||
}
|
||||
stream << length_string;
|
||||
|
||||
stream << " ";
|
||||
stream << (member.date_time.month < 10 ? "0" : "") << member.date_time.month;
|
||||
stream << "/";
|
||||
stream << (member.date_time.day < 10 ? "0" : "") << member.date_time.day;
|
||||
stream << "/";
|
||||
stream << member.date_time.year;
|
||||
stream << " ";
|
||||
stream << (member.date_time.hours < 10 ? "0" : "") << member.date_time.hours;
|
||||
stream << ":";
|
||||
stream << (member.date_time.minutes < 10 ? "0" : "") << member.date_time.minutes;
|
||||
stream << " ";
|
||||
stream << member.filename;
|
||||
stream << std::endl;
|
||||
}
|
||||
|
||||
stream << "--------- -------" << std::endl;
|
||||
|
||||
std::string length_string = std::to_string(sum_length);
|
||||
while (length_string.length() < 9)
|
||||
{
|
||||
length_string = " " + length_string;
|
||||
}
|
||||
stream << length_string << " " << file_count << " " << (file_count == 1 ? "file" : "files");
|
||||
stream << std::endl;
|
||||
}
|
||||
|
||||
std::pair<bool, std::string> zip_file::testzip()
|
||||
bool zip_file::check_crc()
|
||||
{
|
||||
if (archive_->m_zip_mode == MZ_ZIP_MODE_INVALID)
|
||||
{
|
||||
|
@ -784,14 +610,14 @@ std::pair<bool, std::string> zip_file::testzip()
|
|||
|
||||
if (crc != file.crc)
|
||||
{
|
||||
return { false, file.filename };
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return { true, "" };
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string zip_file::get_filename() const
|
||||
path zip_file::get_filename() const
|
||||
{
|
||||
return filename_;
|
||||
}
|
||||
|
|
|
@ -17,11 +17,12 @@ public:
|
|||
void test_from_simple()
|
||||
{
|
||||
pugi::xml_document doc;
|
||||
auto xml = path_helper::read_file(path_helper::get_data_directory("/reader/styles/simple-styles.xml"));
|
||||
doc.load(xml.c_str());
|
||||
doc.load_file(path_helper::get_data_directory("reader/styles/simple-styles.xml").to_string().c_str());
|
||||
|
||||
xlnt::workbook wb;
|
||||
xlnt::excel_serializer e(wb);
|
||||
xlnt::style_serializer s(e.get_stylesheet());
|
||||
|
||||
TS_ASSERT(s.read_stylesheet(doc));
|
||||
TS_ASSERT_EQUALS(e.get_stylesheet().number_formats.size(), 1);
|
||||
}
|
||||
|
@ -29,11 +30,12 @@ public:
|
|||
void test_from_complex()
|
||||
{
|
||||
pugi::xml_document doc;
|
||||
auto xml = path_helper::read_file(path_helper::get_data_directory("/reader/styles/complex-styles.xml"));
|
||||
doc.load(xml.c_str());
|
||||
doc.load_file(path_helper::get_data_directory("reader/styles/complex-styles.xml").to_string().c_str());
|
||||
|
||||
xlnt::workbook wb;
|
||||
xlnt::excel_serializer e(wb);
|
||||
xlnt::style_serializer s(e.get_stylesheet());
|
||||
|
||||
TS_ASSERT(s.read_stylesheet(doc));
|
||||
TS_ASSERT_EQUALS(e.get_stylesheet().borders.size(), 7);
|
||||
TS_ASSERT_EQUALS(e.get_stylesheet().fills.size(), 6);
|
||||
|
|
391
source/utils/path.cpp
Normal file
391
source/utils/path.cpp
Normal file
|
@ -0,0 +1,391 @@
|
|||
// 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
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
|
||||
#include <detail/include_windows.hpp>
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <mach-o/dyld.h>
|
||||
#include <sys/stat.h>
|
||||
#elif defined(_MSC_VER)
|
||||
#include <Shlwapi.h>
|
||||
#elif defined(__linux)
|
||||
#include <unistd.h>
|
||||
#include <linux/limits.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
|
||||
#include <xlnt/utils/path.hpp>
|
||||
|
||||
namespace {
|
||||
|
||||
#ifdef _MSC_VER
|
||||
|
||||
char system_separator()
|
||||
{
|
||||
return '\\';
|
||||
}
|
||||
|
||||
bool is_root(const std::string &part)
|
||||
{
|
||||
return part.size() == 2 && part.back() == ':'
|
||||
&& part.front() >= 'A' && part.front() <= 'Z';
|
||||
}
|
||||
|
||||
bool file_exists(const std::string &path_string)
|
||||
{
|
||||
std::wstring path_wide(path_string.begin(), path_string.end());
|
||||
return PathFileExists(path_wide.c_str()) && !PathIsDirectory(path_wide.c_str());
|
||||
}
|
||||
|
||||
std::string get_working_directory()
|
||||
{
|
||||
TCHAR buffer[MAX_PATH];
|
||||
GetCurrentDirectory(MAX_PATH, buffer);
|
||||
std::basic_string<TCHAR> working_directory(buffer);
|
||||
return std::string(working_directory.begin(), working_directory.end());
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
char system_separator()
|
||||
{
|
||||
return '/';
|
||||
}
|
||||
|
||||
bool is_root(const std::string &part)
|
||||
{
|
||||
return part.empty();
|
||||
}
|
||||
|
||||
bool file_exists(const std::string &path_string)
|
||||
{
|
||||
try
|
||||
{
|
||||
struct stat fileAtt;
|
||||
|
||||
if (stat(path.c_str(), &fileAtt) == 0)
|
||||
{
|
||||
return S_ISREG(fileAtt.st_mode);
|
||||
}
|
||||
}
|
||||
catch (...) {}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string get_working_directory()
|
||||
{
|
||||
std::size_t buffer_size = 100;
|
||||
std::vector<char> buffer(buffer_size, '\0');
|
||||
|
||||
while (getcwd(&buffer[0], buffer_size) == nullptr)
|
||||
{
|
||||
buffer_size *= 2;
|
||||
buffer.resize(buffer_size, '\0');
|
||||
}
|
||||
|
||||
return std::string(&buffer[0]);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
std::vector<std::string> split_path(const std::string &path, char delim)
|
||||
{
|
||||
std::vector<std::string> split;
|
||||
std::string::size_type previous_index = 0;
|
||||
auto separator_index = path.find(delim);
|
||||
|
||||
while (separator_index != std::string::npos)
|
||||
{
|
||||
auto part = path.substr(previous_index, separator_index - previous_index);
|
||||
split.push_back(part);
|
||||
|
||||
previous_index = separator_index + 1;
|
||||
separator_index = path.find(delim, previous_index);
|
||||
}
|
||||
|
||||
// Don't add trailing slash
|
||||
if (previous_index < path.size())
|
||||
{
|
||||
split.push_back(path.substr(previous_index));
|
||||
}
|
||||
|
||||
return split;
|
||||
}
|
||||
|
||||
std::vector<std::string> split_path_universal(const std::string &path)
|
||||
{
|
||||
auto initial = split_path(path, system_separator());
|
||||
|
||||
if (initial.size() == 1 && system_separator() == '\\')
|
||||
{
|
||||
auto alternative = split_path(path, '/');
|
||||
|
||||
if (alternative.size() > 1)
|
||||
{
|
||||
return alternative;
|
||||
}
|
||||
}
|
||||
|
||||
return initial;
|
||||
}
|
||||
|
||||
bool directory_exists(const std::string path)
|
||||
{
|
||||
struct stat info;
|
||||
return stat(path.c_str(), &info) == 0 && (info.st_mode & S_IFDIR);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace xlnt {
|
||||
|
||||
char path::separator()
|
||||
{
|
||||
return system_separator();
|
||||
}
|
||||
|
||||
path::path()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
path::path(const std::string &path_string) : parts_(split_path_universal(path_string))
|
||||
{
|
||||
}
|
||||
|
||||
path::path(const std::string &path_string, char sep) : parts_(split_path(path_string, sep))
|
||||
{
|
||||
}
|
||||
|
||||
// general attributes
|
||||
|
||||
bool path::is_relative() const
|
||||
{
|
||||
return !is_absolute();
|
||||
}
|
||||
|
||||
bool path::is_absolute() const
|
||||
{
|
||||
return !parts_.empty() && ::is_root(parts_.front());
|
||||
}
|
||||
|
||||
bool path::is_root() const
|
||||
{
|
||||
return parts_.size() == 1 && ::is_root(parts_.front());
|
||||
}
|
||||
|
||||
path path::parent() const
|
||||
{
|
||||
path result;
|
||||
result.parts_ = parts_;
|
||||
|
||||
if (result.parts_.size() > 1)
|
||||
{
|
||||
result.parts_.pop_back();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string path::basename()
|
||||
{
|
||||
return parts_.empty() ? "" : parts_.back();
|
||||
}
|
||||
|
||||
// conversion
|
||||
|
||||
std::string path::to_string(char sep) const
|
||||
{
|
||||
if (parts_.empty()) return "";
|
||||
|
||||
std::string result;
|
||||
|
||||
for (const auto &part : parts_)
|
||||
{
|
||||
result.append(part);
|
||||
result.push_back(sep);
|
||||
}
|
||||
|
||||
result.pop_back();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
path path::make_absolute(const path &base_path) const
|
||||
{
|
||||
if (is_absolute())
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
|
||||
path copy = base_path;
|
||||
|
||||
for (const auto &part : parts_)
|
||||
{
|
||||
if (part == ".")
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else if (part == ".." && copy.parts_.size() > 1)
|
||||
{
|
||||
copy.parts_.pop_back();
|
||||
}
|
||||
else
|
||||
{
|
||||
copy.parts_.push_back(part);
|
||||
}
|
||||
}
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
// filesystem attributes
|
||||
|
||||
bool path::exists() const
|
||||
{
|
||||
return is_file() || is_directory();
|
||||
}
|
||||
|
||||
bool path::is_directory() const
|
||||
{
|
||||
return directory_exists(to_string());
|
||||
}
|
||||
|
||||
bool path::is_file() const
|
||||
{
|
||||
return file_exists(to_string());
|
||||
}
|
||||
|
||||
// filesystem
|
||||
|
||||
std::string path::read_contents() const
|
||||
{
|
||||
std::ifstream f(to_string());
|
||||
std::ostringstream ss;
|
||||
ss << f.rdbuf();
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
// mutators
|
||||
|
||||
path &path::append(const std::string &to_append)
|
||||
{
|
||||
parts_.push_back(to_append);
|
||||
return *this;
|
||||
}
|
||||
|
||||
path path::append(const std::string &to_append) const
|
||||
{
|
||||
path copy(*this);
|
||||
copy.append(to_append);
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
path &path::append(const path &to_append)
|
||||
{
|
||||
parts_.insert(parts_.end(), to_append.begin(), to_append.end());
|
||||
return *this;
|
||||
}
|
||||
|
||||
path path::append(const path &to_append) const
|
||||
{
|
||||
path copy(*this);
|
||||
copy.append(to_append);
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
// iterators
|
||||
|
||||
path::iterator path::begin()
|
||||
{
|
||||
return parts_.begin();
|
||||
}
|
||||
|
||||
path::iterator path::end()
|
||||
{
|
||||
return parts_.end();
|
||||
}
|
||||
|
||||
path::const_iterator path::begin() const
|
||||
{
|
||||
return cbegin();
|
||||
}
|
||||
|
||||
path::const_iterator path::end() const
|
||||
{
|
||||
return cend();
|
||||
}
|
||||
|
||||
path::const_iterator path::cbegin() const
|
||||
{
|
||||
return parts_.cbegin();
|
||||
}
|
||||
|
||||
path::const_iterator path::cend() const
|
||||
{
|
||||
return parts_.cend();
|
||||
}
|
||||
|
||||
path::reverse_iterator path::rbegin()
|
||||
{
|
||||
return parts_.rbegin();
|
||||
}
|
||||
|
||||
path::reverse_iterator path::rend()
|
||||
{
|
||||
return parts_.rend();
|
||||
}
|
||||
|
||||
path::const_reverse_iterator path::rbegin() const
|
||||
{
|
||||
return crbegin();
|
||||
}
|
||||
|
||||
path::const_reverse_iterator path::rend() const
|
||||
{
|
||||
return crend();
|
||||
}
|
||||
|
||||
path::const_reverse_iterator path::crbegin() const
|
||||
{
|
||||
return parts_.crbegin();
|
||||
}
|
||||
|
||||
path::const_reverse_iterator path::crend() const
|
||||
{
|
||||
return parts_.crend();
|
||||
}
|
||||
|
||||
std::string path::to_hash_string() const
|
||||
{
|
||||
return to_string('/');
|
||||
}
|
||||
|
||||
} // namespace xlnt
|
|
@ -11,7 +11,7 @@ class test_zip_file : public CxxTest::TestSuite
|
|||
public:
|
||||
test_zip_file()
|
||||
{
|
||||
existing_file = path_helper::get_data_directory("/genuine/empty.xlsx");
|
||||
existing_file = path_helper::get_data_directory("genuine/empty.xlsx");
|
||||
expected_content_types_string = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\r\n<Types xmlns=\"http://schemas.openxmlformats.org/package/2006/content-types\"><Default Extension=\"xml\" ContentType=\"application/xml\"/><Default Extension=\"rels\" ContentType=\"application/vnd.openxmlformats-package.relationships+xml\"/><Override PartName=\"/xl/workbook.xml\" ContentType=\"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml\"/><Override PartName=\"/xl/worksheets/sheet1.xml\" ContentType=\"application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml\"/><Override PartName=\"/xl/worksheets/sheet2.xml\" ContentType=\"application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml\"/><Override PartName=\"/xl/worksheets/sheet3.xml\" ContentType=\"application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml\"/><Override PartName=\"/xl/worksheets/sheet4.xml\" ContentType=\"application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml\"/><Override PartName=\"/xl/theme/theme1.xml\" ContentType=\"application/vnd.openxmlformats-officedocument.theme+xml\"/><Override PartName=\"/xl/styles.xml\" ContentType=\"application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml\"/><Override PartName=\"/xl/sharedStrings.xml\" ContentType=\"application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml\"/><Override PartName=\"/xl/calcChain.xml\" ContentType=\"application/vnd.openxmlformats-officedocument.spreadsheetml.calcChain+xml\"/><Override PartName=\"/docProps/core.xml\" ContentType=\"application/vnd.openxmlformats-package.core-properties+xml\"/><Override PartName=\"/docProps/app.xml\" ContentType=\"application/vnd.openxmlformats-officedocument.extended-properties+xml\"/></Types>";
|
||||
expected_atxt_string = "<?xml version=\"1.0\" ?>\n<sst xmlns=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\" count=\"3\" uniqueCount=\"2\"><si><t>This is cell A1 in Sheet 1</t></si><si><t>This is cell G5</t></si></sst>";
|
||||
expected_printdir_string =
|
||||
|
@ -35,31 +35,19 @@ public:
|
|||
" 22849 14 files\n";
|
||||
}
|
||||
|
||||
void remove_temp_file()
|
||||
bool files_equal(const xlnt::path &left, const xlnt::path &right)
|
||||
{
|
||||
std::remove(temp_file.get_filename().c_str());
|
||||
}
|
||||
|
||||
void make_temp_directory()
|
||||
{
|
||||
}
|
||||
|
||||
void remove_temp_directory()
|
||||
{
|
||||
}
|
||||
|
||||
bool files_equal(const std::string &a, const std::string &b)
|
||||
{
|
||||
if(a == b)
|
||||
if(left.to_string() == right.to_string())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
std::ifstream stream_a(a, std::ios::binary), stream_b(a, std::ios::binary);
|
||||
std::ifstream stream_left(left.to_string(), std::ios::binary);
|
||||
std::ifstream stream_right(right.to_string(), std::ios::binary);
|
||||
|
||||
while(stream_a && stream_b)
|
||||
while(stream_left && stream_right)
|
||||
{
|
||||
if(stream_a.get() != stream_b.get())
|
||||
if(stream_left.get() != stream_right.get())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -70,46 +58,46 @@ public:
|
|||
|
||||
void test_load_file()
|
||||
{
|
||||
remove_temp_file();
|
||||
temporary_file temp_file;
|
||||
xlnt::zip_file f(existing_file);
|
||||
f.save(temp_file.get_filename());
|
||||
TS_ASSERT(files_equal(existing_file, temp_file.get_filename()));
|
||||
remove_temp_file();
|
||||
f.save(temp_file.get_path());
|
||||
TS_ASSERT(files_equal(existing_file, temp_file.get_path()));
|
||||
}
|
||||
|
||||
void test_load_stream()
|
||||
{
|
||||
remove_temp_file();
|
||||
{
|
||||
std::ifstream in_stream(existing_file, std::ios::binary);
|
||||
temporary_file temp;
|
||||
|
||||
std::ifstream in_stream(existing_file.to_string(), std::ios::binary);
|
||||
xlnt::zip_file f(in_stream);
|
||||
std::ofstream out_stream(temp_file.get_filename(), std::ios::binary);
|
||||
std::ofstream out_stream(temp.get_path().to_string(), std::ios::binary);
|
||||
f.save(out_stream);
|
||||
}
|
||||
TS_ASSERT(files_equal(existing_file, temp_file.get_filename()));
|
||||
remove_temp_file();
|
||||
out_stream.close();
|
||||
|
||||
TS_ASSERT(files_equal(existing_file, temp.get_path()));
|
||||
}
|
||||
|
||||
void test_load_bytes()
|
||||
{
|
||||
remove_temp_file();
|
||||
std::vector<unsigned char> source_bytes, result_bytes;
|
||||
std::ifstream in_stream(existing_file, std::ios::binary);
|
||||
temporary_file temp_file;
|
||||
|
||||
std::vector<std::uint8_t> source_bytes;
|
||||
std::ifstream in_stream(existing_file.to_string(), std::ios::binary);
|
||||
|
||||
while(in_stream)
|
||||
{
|
||||
source_bytes.push_back((unsigned char)in_stream.get());
|
||||
source_bytes.push_back(static_cast<std::uint8_t>(in_stream.get()));
|
||||
}
|
||||
|
||||
xlnt::zip_file f(source_bytes);
|
||||
f.save(temp_file.get_filename());
|
||||
f.save(temp_file.get_path());
|
||||
|
||||
xlnt::zip_file f2;
|
||||
f2.load(temp_file.get_filename());
|
||||
result_bytes = std::vector<unsigned char>();
|
||||
f2.load(temp_file.get_path());
|
||||
std::vector<std::uint8_t> result_bytes;
|
||||
f2.save(result_bytes);
|
||||
|
||||
TS_ASSERT(source_bytes == result_bytes);
|
||||
|
||||
remove_temp_file();
|
||||
}
|
||||
|
||||
void test_reset()
|
||||
|
@ -120,7 +108,7 @@ public:
|
|||
|
||||
try
|
||||
{
|
||||
f.read("[Content_Types].xml");
|
||||
f.read(xlnt::path("[Content_Types].xml"));
|
||||
}
|
||||
catch(std::exception e)
|
||||
{
|
||||
|
@ -133,28 +121,28 @@ public:
|
|||
|
||||
try
|
||||
{
|
||||
f.read("[Content_Types].xml");
|
||||
f.read(xlnt::path("[Content_Types].xml"));
|
||||
TS_ASSERT(false);
|
||||
}
|
||||
catch(std::exception e)
|
||||
{
|
||||
}
|
||||
|
||||
f.writestr("a", "b");
|
||||
f.write_string("b", xlnt::path("a"));
|
||||
f.reset();
|
||||
|
||||
TS_ASSERT(f.namelist().empty());
|
||||
|
||||
f.writestr("a", "b");
|
||||
f.write_string("b", xlnt::path("a"));
|
||||
|
||||
TS_ASSERT_DIFFERS(f.getinfo("a").file_size, 0);
|
||||
TS_ASSERT_DIFFERS(f.getinfo(xlnt::path("a")).file_size, 0);
|
||||
}
|
||||
|
||||
void test_getinfo()
|
||||
{
|
||||
xlnt::zip_file f(existing_file);
|
||||
auto info = f.getinfo("[Content_Types].xml");
|
||||
TS_ASSERT(info.filename == "[Content_Types].xml");
|
||||
auto info = f.getinfo(xlnt::path("[Content_Types].xml"));
|
||||
TS_ASSERT(info.filename.to_string() == "[Content_Types].xml");
|
||||
}
|
||||
|
||||
void test_infolist()
|
||||
|
@ -173,7 +161,7 @@ public:
|
|||
{
|
||||
xlnt::zip_file f(existing_file);
|
||||
std::stringstream ss;
|
||||
ss << f.open("[Content_Types].xml").rdbuf();
|
||||
ss << f.open(xlnt::path("[Content_Types].xml")).rdbuf();
|
||||
std::string result = ss.str();
|
||||
TS_ASSERT(result == expected_content_types_string);
|
||||
}
|
||||
|
@ -182,149 +170,84 @@ public:
|
|||
{
|
||||
xlnt::zip_file f(existing_file);
|
||||
std::stringstream ss;
|
||||
ss << f.open("[Content_Types].xml").rdbuf();
|
||||
ss << f.open(xlnt::path("[Content_Types].xml")).rdbuf();
|
||||
std::string result = ss.str();
|
||||
TS_ASSERT(result == expected_content_types_string);
|
||||
}
|
||||
|
||||
void test_extract_current_directory()
|
||||
{
|
||||
xlnt::zip_file f(existing_file);
|
||||
}
|
||||
|
||||
void test_extract_path()
|
||||
{
|
||||
xlnt::zip_file f(existing_file);
|
||||
}
|
||||
|
||||
void test_extractall_current_directory()
|
||||
{
|
||||
xlnt::zip_file f(existing_file);
|
||||
}
|
||||
|
||||
void test_extractall_path()
|
||||
{
|
||||
xlnt::zip_file f(existing_file);
|
||||
}
|
||||
|
||||
void test_extractall_members_name()
|
||||
{
|
||||
xlnt::zip_file f(existing_file);
|
||||
}
|
||||
|
||||
void test_extractall_members_info()
|
||||
{
|
||||
xlnt::zip_file f(existing_file);
|
||||
}
|
||||
|
||||
void test_printdir()
|
||||
{
|
||||
xlnt::zip_file f(existing_file);
|
||||
std::stringstream ss;
|
||||
f.printdir(ss);
|
||||
auto printed = ss.str();
|
||||
TS_ASSERT_EQUALS(printed, expected_printdir_string);
|
||||
}
|
||||
|
||||
void test_read()
|
||||
{
|
||||
xlnt::zip_file f(existing_file);
|
||||
TS_ASSERT(f.read("[Content_Types].xml") == expected_content_types_string);
|
||||
TS_ASSERT(f.read(f.getinfo("[Content_Types].xml")) == expected_content_types_string);
|
||||
TS_ASSERT(f.read(xlnt::path("[Content_Types].xml")) == expected_content_types_string);
|
||||
TS_ASSERT(f.read(f.getinfo(xlnt::path("[Content_Types].xml"))) == expected_content_types_string);
|
||||
}
|
||||
|
||||
void test_testzip()
|
||||
{
|
||||
xlnt::zip_file f(existing_file);
|
||||
TS_ASSERT(f.testzip().first);
|
||||
TS_ASSERT(!f.check_crc());
|
||||
}
|
||||
|
||||
void test_write()
|
||||
void test_write_file()
|
||||
{
|
||||
remove_temp_file();
|
||||
temporary_file temp_file;
|
||||
|
||||
xlnt::zip_file f;
|
||||
auto text_file = path_helper::get_data_directory("/reader/sharedStrings.xml");
|
||||
f.write(text_file);
|
||||
f.write(text_file, "sharedStrings2.xml");
|
||||
f.save(temp_file.get_filename());
|
||||
auto text_file = path_helper::get_data_directory("reader/sharedStrings.xml");
|
||||
f.write_file(text_file);
|
||||
f.write_file(text_file, xlnt::path("sharedStrings2.xml"));
|
||||
f.save(temp_file.get_path());
|
||||
|
||||
xlnt::zip_file f2(temp_file.get_filename());
|
||||
xlnt::zip_file f2(temp_file.get_path());
|
||||
|
||||
for(auto &info : f2.infolist())
|
||||
{
|
||||
if(info.filename == "sharedStrings2.xml")
|
||||
if(info.filename.to_string() == "sharedStrings2.xml")
|
||||
{
|
||||
TS_ASSERT(f2.read(info) == expected_atxt_string);
|
||||
}
|
||||
else if(info.filename.substr(info.filename.size() - 17) == "sharedStrings.xml")
|
||||
else if(info.filename.basename() == "sharedStrings.xml")
|
||||
{
|
||||
TS_ASSERT(f2.read(info) == expected_atxt_string);
|
||||
}
|
||||
}
|
||||
|
||||
remove_temp_file();
|
||||
}
|
||||
|
||||
void test_writestr()
|
||||
void test_write_string()
|
||||
{
|
||||
remove_temp_file();
|
||||
|
||||
xlnt::zip_file f;
|
||||
f.writestr("a.txt", "a\na");
|
||||
f.write_string("a\na", xlnt::path("a.txt"));
|
||||
xlnt::zip_info info;
|
||||
info.filename = "b.txt";
|
||||
info.filename = xlnt::path("b.txt");
|
||||
info.date_time.year = 2014;
|
||||
f.writestr(info, "b\nb");
|
||||
f.save(temp_file.get_filename());
|
||||
f.write_string("b\nb", info);
|
||||
|
||||
xlnt::zip_file f2(temp_file.get_filename());
|
||||
TS_ASSERT(f2.read("a.txt") == "a\na");
|
||||
TS_ASSERT(f2.read(f2.getinfo("b.txt")) == "b\nb");
|
||||
temporary_file temp_file;
|
||||
f.save(temp_file.get_path());
|
||||
|
||||
remove_temp_file();
|
||||
xlnt::zip_file f2(temp_file.get_path());
|
||||
TS_ASSERT(f2.read(xlnt::path("a.txt")) == "a\na");
|
||||
TS_ASSERT(f2.read(f2.getinfo(xlnt::path("b.txt"))) == "b\nb");
|
||||
}
|
||||
|
||||
void test_comment()
|
||||
{
|
||||
remove_temp_file();
|
||||
|
||||
xlnt::zip_file f;
|
||||
f.comment = "comment";
|
||||
f.save(temp_file.get_filename());
|
||||
temporary_file temp_file;
|
||||
f.save(temp_file.get_path());
|
||||
|
||||
xlnt::zip_file f2(temp_file.get_filename());
|
||||
xlnt::zip_file f2(temp_file.get_path());
|
||||
TS_ASSERT(f2.comment == "comment");
|
||||
|
||||
xlnt::zip_file f3;
|
||||
std::vector<std::uint8_t> bytes { 1, 2, 3 };
|
||||
TS_ASSERT_THROWS(f3.load(bytes), std::runtime_error);
|
||||
|
||||
remove_temp_file();
|
||||
}
|
||||
|
||||
void test_extract()
|
||||
{
|
||||
xlnt::zip_file f;
|
||||
f.load(path_helper::get_data_directory("/genuine/empty.xlsx"));
|
||||
|
||||
auto expected = path_helper::get_working_directory() + "/xl/styles.xml";
|
||||
|
||||
TS_ASSERT(!path_helper::file_exists(expected));
|
||||
f.extract("xl/styles.xml");
|
||||
TS_ASSERT(path_helper::file_exists(expected));
|
||||
path_helper::delete_file(expected);
|
||||
|
||||
auto info = f.getinfo("xl/styles.xml");
|
||||
TS_ASSERT(!path_helper::file_exists(expected));
|
||||
f.extract(info);
|
||||
TS_ASSERT(path_helper::file_exists(expected));
|
||||
path_helper::delete_file(expected);
|
||||
}
|
||||
|
||||
private:
|
||||
temporary_file temp_file;
|
||||
std::string existing_file;
|
||||
xlnt::path existing_file;
|
||||
std::string expected_content_types_string;
|
||||
std::string expected_atxt_string;
|
||||
std::string expected_printdir_string;
|
||||
|
|
|
@ -21,7 +21,7 @@ public:
|
|||
xlnt::workbook standard_workbook()
|
||||
{
|
||||
xlnt::workbook wb;
|
||||
auto path = path_helper::get_data_directory("/genuine/empty.xlsx");
|
||||
auto path = path_helper::get_data_directory("genuine/empty.xlsx");
|
||||
wb.load(path);
|
||||
|
||||
return wb;
|
||||
|
@ -34,8 +34,8 @@ public:
|
|||
|
||||
void test_read_standard_workbook_from_fileobj()
|
||||
{
|
||||
auto path = path_helper::get_data_directory("/genuine/empty.xlsx");
|
||||
std::ifstream fo(path, std::ios::binary);
|
||||
auto path = path_helper::get_data_directory("genuine/empty.xlsx");
|
||||
std::ifstream fo(path.to_string(), std::ios::binary);
|
||||
|
||||
xlnt::workbook wb;
|
||||
TS_ASSERT(wb.load(fo));
|
||||
|
@ -55,7 +55,7 @@ public:
|
|||
|
||||
void test_read_nostring_workbook()
|
||||
{
|
||||
auto path = path_helper::get_data_directory("/genuine/empty-no-string.xlsx");
|
||||
auto path = path_helper::get_data_directory("genuine/empty-no-string.xlsx");
|
||||
|
||||
xlnt::workbook wb;
|
||||
TS_ASSERT_THROWS_NOTHING(wb.load(path));
|
||||
|
@ -63,40 +63,26 @@ public:
|
|||
|
||||
void test_read_empty_file()
|
||||
{
|
||||
auto path = path_helper::get_data_directory("/reader/null_file.xlsx");
|
||||
|
||||
xlnt::workbook wb;
|
||||
xlnt::excel_serializer serializer(wb);
|
||||
|
||||
TS_ASSERT_THROWS(serializer.load_workbook(path), xlnt::invalid_file);
|
||||
TS_ASSERT_THROWS(wb.load(path_helper::get_data_directory("reader/null_file.xlsx")), xlnt::invalid_file);
|
||||
}
|
||||
|
||||
void test_read_empty_archive()
|
||||
{
|
||||
auto path = path_helper::get_data_directory("/reader/null_archive.xlsx");
|
||||
|
||||
xlnt::workbook wb;
|
||||
xlnt::excel_serializer serializer(wb);
|
||||
|
||||
TS_ASSERT_THROWS(serializer.load_workbook(path), xlnt::invalid_file);
|
||||
TS_ASSERT_THROWS(wb.load(path_helper::get_data_directory("reader/null_archive.xlsx")), xlnt::invalid_file);
|
||||
}
|
||||
|
||||
void test_read_workbook_with_no_properties()
|
||||
{
|
||||
auto path = path_helper::get_data_directory("/genuine/empty_with_no_properties.xlsx");
|
||||
|
||||
xlnt::workbook wb;
|
||||
xlnt::excel_serializer serializer(wb);
|
||||
|
||||
serializer.load_workbook(path);
|
||||
TS_ASSERT_THROWS_NOTHING(wb.load(path_helper::get_data_directory("genuine/empty_with_no_properties.xlsx")));
|
||||
}
|
||||
|
||||
xlnt::workbook workbook_with_styles()
|
||||
{
|
||||
auto path = path_helper::get_data_directory("/genuine/empty-with-styles.xlsx");
|
||||
|
||||
xlnt::workbook wb;
|
||||
wb.load(path);
|
||||
wb.load(path_helper::get_data_directory("genuine/empty-with-styles.xlsx"));
|
||||
|
||||
return wb;
|
||||
}
|
||||
|
@ -148,12 +134,9 @@ public:
|
|||
|
||||
void test_read_charset_excel()
|
||||
{
|
||||
auto path = path_helper::get_data_directory("/reader/charset-excel.xlsx");
|
||||
|
||||
xlnt::workbook wb;
|
||||
xlnt::excel_serializer serializer(wb);
|
||||
|
||||
serializer.load_workbook(path);
|
||||
auto path = path_helper::get_data_directory("reader/charset-excel.xlsx");
|
||||
wb.load(path);
|
||||
|
||||
auto ws = wb["Sheet1"];
|
||||
auto val = ws.get_cell("A1").get_value<std::string>();
|
||||
|
@ -162,12 +145,9 @@ public:
|
|||
|
||||
void test_read_shared_strings_max_range()
|
||||
{
|
||||
auto path = path_helper::get_data_directory("/reader/shared_strings-max_range.xlsx");
|
||||
|
||||
xlnt::workbook wb;
|
||||
xlnt::excel_serializer serializer(wb);
|
||||
|
||||
serializer.load_workbook(path);
|
||||
const auto path = path_helper::get_data_directory("reader/shared_strings-max_range.xlsx");
|
||||
wb.load(path);
|
||||
|
||||
auto ws = wb["Sheet1"];
|
||||
auto val = ws.get_cell("A1").get_value<std::string>();
|
||||
|
@ -176,12 +156,10 @@ public:
|
|||
|
||||
void test_read_shared_strings_multiple_r_nodes()
|
||||
{
|
||||
auto path = path_helper::get_data_directory("/reader/shared_strings-multiple_r_nodes.xlsx");
|
||||
auto path = path_helper::get_data_directory("reader/shared_strings-multiple_r_nodes.xlsx");
|
||||
|
||||
xlnt::workbook wb;
|
||||
xlnt::excel_serializer serializer(wb);
|
||||
|
||||
serializer.load_workbook(path);
|
||||
wb.load(path);
|
||||
|
||||
auto ws = wb["Sheet1"];
|
||||
auto val = ws.get_cell("A1").get_value<std::string>();
|
||||
|
@ -190,20 +168,16 @@ public:
|
|||
|
||||
xlnt::workbook date_mac_1904()
|
||||
{
|
||||
auto path = path_helper::get_data_directory("/reader/date_1904.xlsx");
|
||||
|
||||
xlnt::workbook wb;
|
||||
wb.load(path);
|
||||
wb.load(path_helper::get_data_directory("reader/date_1904.xlsx"));
|
||||
|
||||
return wb;
|
||||
}
|
||||
|
||||
xlnt::workbook date_std_1900()
|
||||
{
|
||||
auto path = path_helper::get_data_directory("/reader/date_1900.xlsx");
|
||||
|
||||
xlnt::workbook wb;
|
||||
wb.load(path);
|
||||
wb.load(path_helper::get_data_directory("reader/date_1900.xlsx"));
|
||||
|
||||
return wb;
|
||||
}
|
||||
|
@ -211,13 +185,13 @@ public:
|
|||
void test_read_win_base_date()
|
||||
{
|
||||
auto wb = date_std_1900();
|
||||
TS_ASSERT_EQUALS(wb.get_properties().excel_base_date, xlnt::calendar::windows_1900);
|
||||
TS_ASSERT_EQUALS(wb.get_base_date(), xlnt::calendar::windows_1900);
|
||||
}
|
||||
|
||||
void test_read_mac_base_date()
|
||||
{
|
||||
auto wb = date_mac_1904();
|
||||
TS_ASSERT_EQUALS(wb.get_properties().excel_base_date, xlnt::calendar::mac_1904);
|
||||
TS_ASSERT_EQUALS(wb.get_base_date(), xlnt::calendar::mac_1904);
|
||||
}
|
||||
|
||||
void test_read_date_style_win()
|
||||
|
@ -260,7 +234,7 @@ public:
|
|||
|
||||
void test_read_no_theme()
|
||||
{
|
||||
auto path = path_helper::get_data_directory("/genuine/libreoffice_nrt.xlsx");
|
||||
auto path = path_helper::get_data_directory("genuine/libreoffice_nrt.xlsx");
|
||||
|
||||
xlnt::workbook wb;
|
||||
TS_ASSERT_THROWS_NOTHING(wb.load(path));
|
||||
|
@ -269,7 +243,7 @@ public:
|
|||
void _test_read_complex_formulae()
|
||||
{
|
||||
/*
|
||||
auto path = PathHelper::GetDataDirectory("/reader/formulae.xlsx");
|
||||
auto path = PathHelper::GetDataDirectory("reader/formulae.xlsx");
|
||||
auto wb = xlnt::reader::load_workbook(path);
|
||||
auto ws = wb.get_active_sheet();
|
||||
|
||||
|
@ -325,12 +299,11 @@ public:
|
|||
|
||||
void test_data_only()
|
||||
{
|
||||
auto path = path_helper::get_data_directory("/reader/formulae.xlsx");
|
||||
auto path = path_helper::get_data_directory("reader/formulae.xlsx");
|
||||
|
||||
xlnt::workbook wb;
|
||||
xlnt::excel_serializer serializer(wb);
|
||||
|
||||
serializer.load_workbook(path, false, true);
|
||||
wb.set_data_only(true);
|
||||
wb.load(path);
|
||||
|
||||
auto ws = wb.get_active_sheet();
|
||||
|
||||
|
@ -362,7 +335,7 @@ public:
|
|||
{xlnt::relationship::type::styles, "rId4", "styles.xml"}
|
||||
};
|
||||
|
||||
auto path = path_helper::get_data_directory("/reader/bug137.xlsx");
|
||||
auto path = path_helper::get_data_directory("reader/bug137.xlsx");
|
||||
xlnt::zip_file archive(path);
|
||||
xlnt::relationship_serializer serializer(archive);
|
||||
|
||||
|
@ -382,7 +355,7 @@ public:
|
|||
{xlnt::relationship::type::theme, "rId4", "/xl/theme/theme.xml"}
|
||||
};
|
||||
|
||||
auto path = path_helper::get_data_directory("/reader/bug304.xlsx");
|
||||
auto path = path_helper::get_data_directory("reader/bug304.xlsx");
|
||||
xlnt::zip_file archive(path);
|
||||
xlnt::relationship_serializer serializer(archive);
|
||||
|
||||
|
@ -410,7 +383,7 @@ public:
|
|||
{"/docProps/app.xml", "application/vnd.openxmlformats-officedocument.extended-properties+xml"}
|
||||
};
|
||||
|
||||
auto path = path_helper::get_data_directory("/reader/contains_chartsheets.xlsx");
|
||||
auto path = path_helper::get_data_directory("reader/contains_chartsheets.xlsx");
|
||||
|
||||
xlnt::workbook wb;
|
||||
wb.load(path);
|
||||
|
@ -425,8 +398,8 @@ public:
|
|||
|
||||
for(std::size_t i = 0; i < expected.size(); i++)
|
||||
{
|
||||
TS_ASSERT(wb.get_manifest().has_override_type(expected[i].first));
|
||||
TS_ASSERT_EQUALS(wb.get_manifest().get_override_type(expected[i].first), expected[i].second);
|
||||
TS_ASSERT(wb.get_manifest().has_override_type(xlnt::path(expected[i].first)));
|
||||
TS_ASSERT_EQUALS(wb.get_manifest().get_override_type(xlnt::path(expected[i].first)), expected[i].second);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -439,12 +412,11 @@ public:
|
|||
for(const auto &expected : test_cases)
|
||||
{
|
||||
std::tie(guess, dtype) = expected;
|
||||
auto path = path_helper::get_data_directory("/genuine/guess_types.xlsx");
|
||||
auto path = path_helper::get_data_directory("genuine/guess_types.xlsx");
|
||||
|
||||
xlnt::workbook wb;
|
||||
xlnt::excel_serializer serializer(wb);
|
||||
|
||||
serializer.load_workbook(path, guess);
|
||||
wb.set_guess_types(guess);
|
||||
wb.load(path);
|
||||
|
||||
auto ws = wb.get_active_sheet();
|
||||
TS_ASSERT(ws.get_cell("D2").get_data_type() == dtype);
|
||||
|
@ -453,12 +425,10 @@ public:
|
|||
|
||||
void test_read_autofilter()
|
||||
{
|
||||
auto path = path_helper::get_data_directory("/reader/bug275.xlsx");
|
||||
auto path = path_helper::get_data_directory("reader/bug275.xlsx");
|
||||
|
||||
xlnt::workbook wb;
|
||||
xlnt::excel_serializer serializer(wb);
|
||||
|
||||
serializer.load_workbook(path);
|
||||
wb.load(path);
|
||||
|
||||
auto ws = wb.get_active_sheet();
|
||||
TS_ASSERT_EQUALS(ws.get_auto_filter().to_string(), "A1:B6");
|
||||
|
@ -466,32 +436,23 @@ public:
|
|||
|
||||
void test_bad_formats_xlsb()
|
||||
{
|
||||
auto path = path_helper::get_data_directory("/genuine/a.xlsb");
|
||||
|
||||
auto path = path_helper::get_data_directory("genuine/a.xlsb");
|
||||
xlnt::workbook wb;
|
||||
xlnt::excel_serializer serializer(wb);
|
||||
|
||||
TS_ASSERT_THROWS(serializer.load_workbook(path), xlnt::invalid_file);
|
||||
TS_ASSERT_THROWS(wb.load(path), xlnt::invalid_file);
|
||||
}
|
||||
|
||||
void test_bad_formats_xls()
|
||||
{
|
||||
auto path = path_helper::get_data_directory("/genuine/a.xls");
|
||||
|
||||
auto path = path_helper::get_data_directory("genuine/a.xls");
|
||||
xlnt::workbook wb;
|
||||
xlnt::excel_serializer serializer(wb);
|
||||
|
||||
TS_ASSERT_THROWS(serializer.load_workbook(path), xlnt::invalid_file);
|
||||
TS_ASSERT_THROWS(wb.load(path), xlnt::invalid_file);
|
||||
}
|
||||
|
||||
void test_bad_formats_no()
|
||||
{
|
||||
auto path = path_helper::get_data_directory("/genuine/a.no-format");
|
||||
|
||||
auto path = path_helper::get_data_directory("genuine/a.no-format");
|
||||
xlnt::workbook wb;
|
||||
xlnt::excel_serializer serializer(wb);
|
||||
|
||||
TS_ASSERT_THROWS(serializer.load_workbook(path), xlnt::invalid_file);
|
||||
TS_ASSERT_THROWS(wb.load(path), xlnt::invalid_file);
|
||||
}
|
||||
|
||||
|
||||
|
@ -550,7 +511,7 @@ public:
|
|||
void test_read_inlinestr()
|
||||
{
|
||||
xlnt::workbook wb;
|
||||
wb.load(path_helper::get_data_directory("/genuine/empty.xlsx"));
|
||||
wb.load(path_helper::get_data_directory("genuine/empty.xlsx"));
|
||||
TS_ASSERT_EQUALS(wb.get_sheet_by_index(0).get_cell("A1").get_value<std::string>(), "This is cell A1 in Sheet 1");
|
||||
}
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ public:
|
|||
void test_complex_formatting()
|
||||
{
|
||||
xlnt::workbook wb;
|
||||
wb.load(path_helper::get_data_directory("/reader/formatting.xlsx"));
|
||||
wb.load(path_helper::get_data_directory("reader/formatting.xlsx"));
|
||||
|
||||
// border_style
|
||||
auto ws = wb.get_active_sheet();
|
||||
|
|
|
@ -3,25 +3,23 @@
|
|||
#include <iostream>
|
||||
#include <cxxtest/TestSuite.h>
|
||||
|
||||
#include <detail/style_serializer.hpp>
|
||||
#include <detail/stylesheet.hpp>
|
||||
#include <detail/workbook_impl.hpp>
|
||||
#include <helpers/path_helper.hpp>
|
||||
#include <detail/constants.hpp>
|
||||
|
||||
class test_style_writer : public CxxTest::TestSuite
|
||||
{
|
||||
public:
|
||||
bool style_xml_matches(const std::string &expected_string, xlnt::workbook &wb)
|
||||
{
|
||||
xlnt::excel_serializer excel_serializer(wb);
|
||||
xlnt::style_serializer style_serializer(excel_serializer.get_stylesheet());
|
||||
pugi::xml_document observed;
|
||||
style_serializer.write_stylesheet(observed);
|
||||
pugi::xml_document expected;
|
||||
expected.load(expected_string.c_str());
|
||||
std::vector<std::uint8_t> bytes;
|
||||
wb.save(bytes);
|
||||
|
||||
auto comparison = xml_helper::compare_xml(expected.root(), observed.root());
|
||||
return (bool)comparison;
|
||||
xlnt::zip_file archive;
|
||||
archive.load(bytes);
|
||||
|
||||
pugi::xml_document observed;
|
||||
observed.load(archive.read(xlnt::constants::part_styles()).c_str());
|
||||
|
||||
return xml_helper::string_matches_document(expected_string, observed);
|
||||
}
|
||||
|
||||
void test_write_custom_number_format()
|
||||
|
@ -100,8 +98,8 @@ public:
|
|||
b.set_side(xlnt::border::side::top, prop);
|
||||
ws.get_cell("D10").set_border(b);
|
||||
|
||||
std::string expected = path_helper::read_file(path_helper::get_data_directory("/writer/expected/simple-styles.xml"));
|
||||
TS_ASSERT(style_xml_matches(expected, wb));
|
||||
auto expected = path_helper::get_data_directory("writer/expected/simple-styles.xml");
|
||||
TS_ASSERT(style_xml_matches(expected.read_contents(), wb));
|
||||
}
|
||||
|
||||
void test_empty_workbook()
|
||||
|
|
|
@ -16,7 +16,8 @@ public:
|
|||
xlnt::workbook wb;
|
||||
xlnt::theme_serializer serializer;
|
||||
pugi::xml_document xml;
|
||||
serializer.write_theme(wb.get_loaded_theme(), xml);
|
||||
TS_ASSERT(xml_helper::compare_xml(path_helper::get_data_directory() + "/writer/expected/theme1.xml", xml));
|
||||
serializer.write_theme(wb.get_theme(), xml);
|
||||
|
||||
TS_ASSERT(xml_helper::file_matches_document(path_helper::get_data_directory("writer/expected/theme1.xml"), xml));
|
||||
}
|
||||
};
|
||||
|
|
|
@ -181,10 +181,10 @@ public:
|
|||
auto sheet = book.get_active_sheet();
|
||||
sheet.get_cell("A1").set_value(today);
|
||||
temporary_file temp_file;
|
||||
book.save(temp_file.get_filename());
|
||||
book.save(temp_file.get_path());
|
||||
|
||||
xlnt::workbook test_book;
|
||||
test_book.load(temp_file.get_filename());
|
||||
test_book.load(temp_file.get_path());
|
||||
auto test_sheet = test_book.get_active_sheet();
|
||||
|
||||
TS_ASSERT_EQUALS(test_sheet.get_cell("A1").get_value<xlnt::datetime>(), today);
|
||||
|
@ -198,10 +198,10 @@ public:
|
|||
auto sheet = book.get_active_sheet();
|
||||
sheet.get_cell("A1").set_value(float_value);
|
||||
temporary_file temp_file;
|
||||
book.save(temp_file.get_filename());
|
||||
book.save(temp_file.get_path());
|
||||
|
||||
xlnt::workbook test_book;
|
||||
test_book.load(temp_file.get_filename());
|
||||
test_book.load(temp_file.get_path());
|
||||
auto test_sheet = test_book.get_active_sheet();
|
||||
|
||||
TS_ASSERT_EQUALS(test_sheet.get_cell("A1").get_value<long double>(), float_value);
|
||||
|
@ -265,13 +265,13 @@ public:
|
|||
|
||||
xlnt::override_type o;
|
||||
TS_ASSERT(o.get_content_type().empty());
|
||||
TS_ASSERT(o.get_part_name().empty());
|
||||
TS_ASSERT(o.get_part().to_string().empty());
|
||||
|
||||
xlnt::manifest m;
|
||||
TS_ASSERT(!m.has_default_type("xml"));
|
||||
TS_ASSERT_THROWS(m.get_default_type("xml"), std::out_of_range);
|
||||
TS_ASSERT(!m.has_override_type("xl/workbook.xml"));
|
||||
TS_ASSERT_THROWS(m.get_override_type("xl/workbook.xml"), std::out_of_range);
|
||||
TS_ASSERT(!m.has_override_type(xlnt::path("xl/workbook.xml")));
|
||||
TS_ASSERT_THROWS(m.get_override_type(xlnt::path("xl/workbook.xml")), std::out_of_range);
|
||||
}
|
||||
|
||||
void test_get_bad_relationship()
|
||||
|
@ -322,19 +322,13 @@ public:
|
|||
|
||||
const auto &wb_const = wb;
|
||||
//TODO these aren't tests...
|
||||
wb_const.get_app_properties();
|
||||
wb_const.get_manifest();
|
||||
|
||||
TS_ASSERT(!wb.has_loaded_theme());
|
||||
TS_ASSERT(wb.has_theme());
|
||||
|
||||
wb.create_style("style1");
|
||||
wb.get_style("style1");
|
||||
wb_const.get_style("style1");
|
||||
wb.get_style_by_id(0);
|
||||
}
|
||||
|
||||
void test_limits()
|
||||
{
|
||||
|
||||
}
|
||||
};
|
||||
|
|
|
@ -21,16 +21,16 @@ public:
|
|||
wbk.get_active_sheet().get_cell("A2").set_value("xlnt");
|
||||
wbk.get_active_sheet().get_cell("B5").set_value(88);
|
||||
wbk.get_active_sheet().get_cell("B5").set_number_format(xlnt::number_format::percentage_00());
|
||||
wbk.save(temp_file.get_filename());
|
||||
wbk.save(temp_file.get_path());
|
||||
|
||||
if(path_helper::file_exists(temp_file.get_filename()))
|
||||
if(temp_file.get_path().exists())
|
||||
{
|
||||
path_helper::delete_file(temp_file.get_filename());
|
||||
path_helper::delete_file(temp_file.get_path());
|
||||
}
|
||||
|
||||
TS_ASSERT(!path_helper::file_exists(temp_file.get_filename()));
|
||||
wb_.save(temp_file.get_filename());
|
||||
TS_ASSERT(path_helper::file_exists(temp_file.get_filename()));
|
||||
TS_ASSERT(!temp_file.get_path().exists());
|
||||
wb_.save(temp_file.get_path());
|
||||
TS_ASSERT(temp_file.get_path().exists());
|
||||
}
|
||||
|
||||
void test_write_virtual_workbook()
|
||||
|
@ -50,9 +50,9 @@ public:
|
|||
xlnt::relationship_serializer serializer(archive);
|
||||
serializer.write_relationships(wb.get_relationships(), "xl/workbook.xml");
|
||||
pugi::xml_document xml;
|
||||
xml.load(archive.read("xl/_rels/workbook.xml.rels").c_str());
|
||||
xml.load(archive.read(xlnt::path("xl/_rels/workbook.xml.rels")).c_str());
|
||||
|
||||
TS_ASSERT(xml_helper::compare_xml(path_helper::get_data_directory() + "/writer/expected/workbook.xml.rels", xml));
|
||||
TS_ASSERT(xml_helper::file_matches_document(path_helper::get_data_directory("writer/expected/workbook.xml.rels"), xml));
|
||||
}
|
||||
|
||||
void test_write_workbook()
|
||||
|
@ -62,7 +62,7 @@ public:
|
|||
pugi::xml_document xml;
|
||||
serializer.write_workbook(xml);
|
||||
|
||||
TS_ASSERT(xml_helper::compare_xml(path_helper::get_data_directory() + "/writer/expected/workbook.xml", xml));
|
||||
TS_ASSERT(xml_helper::file_matches_document(path_helper::get_data_directory("writer/expected/workbook.xml"), xml));
|
||||
}
|
||||
|
||||
void test_write_string_table()
|
||||
|
@ -77,7 +77,7 @@ public:
|
|||
pugi::xml_document xml;
|
||||
xlnt::shared_strings_serializer::write_shared_strings(wb.get_shared_strings(), xml);
|
||||
|
||||
TS_ASSERT(xml_helper::compare_xml(path_helper::get_data_directory() + "/writer/expected/sharedStrings.xml", xml));
|
||||
TS_ASSERT(xml_helper::file_matches_document(path_helper::get_data_directory("writer/expected/sharedStrings.xml"), xml));
|
||||
}
|
||||
|
||||
void test_write_worksheet()
|
||||
|
@ -89,7 +89,7 @@ public:
|
|||
pugi::xml_document xml;
|
||||
serializer.write_worksheet(xml);
|
||||
|
||||
TS_ASSERT(xml_helper::compare_xml(path_helper::get_data_directory() + "/writer/expected/sheet1.xml", xml));
|
||||
TS_ASSERT(xml_helper::file_matches_document(path_helper::get_data_directory("writer/expected/sheet1.xml"), xml));
|
||||
}
|
||||
|
||||
void test_write_hidden_worksheet()
|
||||
|
@ -102,7 +102,7 @@ public:
|
|||
pugi::xml_document xml;
|
||||
serializer.write_worksheet(xml);
|
||||
|
||||
TS_ASSERT(xml_helper::compare_xml(path_helper::get_data_directory() + "/writer/expected/sheet1.xml", xml));
|
||||
TS_ASSERT(xml_helper::file_matches_document(path_helper::get_data_directory("writer/expected/sheet1.xml"), xml));
|
||||
}
|
||||
|
||||
void test_write_bool()
|
||||
|
@ -115,7 +115,7 @@ public:
|
|||
pugi::xml_document xml;
|
||||
serializer.write_worksheet(xml);
|
||||
|
||||
TS_ASSERT(xml_helper::compare_xml(path_helper::get_data_directory() + "/writer/expected/sheet1_bool.xml", xml));
|
||||
TS_ASSERT(xml_helper::file_matches_document(path_helper::get_data_directory("writer/expected/sheet1_bool.xml"), xml));
|
||||
}
|
||||
|
||||
void test_write_formula()
|
||||
|
@ -129,7 +129,7 @@ public:
|
|||
pugi::xml_document xml;
|
||||
serializer.write_worksheet(xml);
|
||||
|
||||
TS_ASSERT(xml_helper::compare_xml(path_helper::get_data_directory() + "/writer/expected/sheet1_formula.xml", xml));
|
||||
TS_ASSERT(xml_helper::file_matches_document(path_helper::get_data_directory("writer/expected/sheet1_formula.xml"), xml));
|
||||
}
|
||||
|
||||
void test_write_height()
|
||||
|
@ -142,7 +142,7 @@ public:
|
|||
pugi::xml_document xml;
|
||||
serializer.write_worksheet(xml);
|
||||
|
||||
TS_ASSERT(xml_helper::compare_xml(path_helper::get_data_directory() + "/writer/expected/sheet1_height.xml", xml));
|
||||
TS_ASSERT(xml_helper::file_matches_document(path_helper::get_data_directory("writer/expected/sheet1_height.xml"), xml));
|
||||
}
|
||||
|
||||
void test_write_hyperlink()
|
||||
|
@ -157,7 +157,7 @@ public:
|
|||
pugi::xml_document xml;
|
||||
serializer.write_worksheet(xml);
|
||||
|
||||
TS_ASSERT(xml_helper::compare_xml(path_helper::get_data_directory() + "/writer/expected/sheet1_hyperlink.xml", xml));
|
||||
TS_ASSERT(xml_helper::file_matches_document(path_helper::get_data_directory("writer/expected/sheet1_hyperlink.xml"), xml));
|
||||
}
|
||||
|
||||
void test_write_hyperlink_rels()
|
||||
|
@ -175,9 +175,9 @@ public:
|
|||
xlnt::relationship_serializer serializer(archive);
|
||||
serializer.write_relationships(ws.get_relationships(), "xl/worksheets/sheet1.xml");
|
||||
pugi::xml_document xml;
|
||||
xml.load(archive.read("xl/worksheets/_rels/sheet1.xml.rels").c_str());
|
||||
xml.load(archive.read(xlnt::path("xl/worksheets/_rels/sheet1.xml.rels")).c_str());
|
||||
|
||||
TS_ASSERT(xml_helper::compare_xml(path_helper::get_data_directory() + "/writer/expected/sheet1_hyperlink.xml.rels", xml));
|
||||
TS_ASSERT(xml_helper::file_matches_document(path_helper::get_data_directory("writer/expected/sheet1_hyperlink.xml.rels"), xml));
|
||||
}
|
||||
|
||||
void _test_write_hyperlink_image_rels()
|
||||
|
@ -205,13 +205,13 @@ public:
|
|||
pugi::xml_document xml;
|
||||
ws_serializer.write_worksheet(xml);
|
||||
|
||||
TS_ASSERT(xml_helper::compare_xml(path_helper::get_data_directory() + "/writer/expected/sheet1_auto_filter.xml", xml));
|
||||
TS_ASSERT(xml_helper::file_matches_document(path_helper::get_data_directory("writer/expected/sheet1_auto_filter.xml"), xml));
|
||||
|
||||
xlnt::workbook_serializer wb_serializer(wb);
|
||||
pugi::xml_document xml2;
|
||||
wb_serializer.write_workbook(xml2);
|
||||
|
||||
TS_ASSERT(xml_helper::compare_xml(path_helper::get_data_directory() + "/writer/expected/workbook_auto_filter.xml", xml2));
|
||||
TS_ASSERT(xml_helper::file_matches_document(path_helper::get_data_directory("writer/expected/workbook_auto_filter.xml"), xml2));
|
||||
}
|
||||
|
||||
void test_write_auto_filter_filter_column()
|
||||
|
@ -234,7 +234,7 @@ public:
|
|||
pugi::xml_document xml;
|
||||
serializer.write_worksheet(xml);
|
||||
|
||||
TS_ASSERT(xml_helper::compare_xml(path_helper::get_data_directory() + "/writer/expected/sheet1_freeze_panes_horiz.xml", xml));
|
||||
TS_ASSERT(xml_helper::file_matches_document(path_helper::get_data_directory("writer/expected/sheet1_freeze_panes_horiz.xml"), xml));
|
||||
}
|
||||
|
||||
void test_freeze_panes_vert()
|
||||
|
@ -247,7 +247,7 @@ public:
|
|||
pugi::xml_document xml;
|
||||
serializer.write_worksheet(xml);
|
||||
|
||||
TS_ASSERT(xml_helper::compare_xml(path_helper::get_data_directory() + "/writer/expected/sheet1_freeze_panes_vert.xml", xml));
|
||||
TS_ASSERT(xml_helper::file_matches_document(path_helper::get_data_directory("writer/expected/sheet1_freeze_panes_vert.xml"), xml));
|
||||
}
|
||||
|
||||
void test_freeze_panes_both()
|
||||
|
@ -260,7 +260,7 @@ public:
|
|||
pugi::xml_document xml;
|
||||
serializer.write_worksheet(xml);
|
||||
|
||||
TS_ASSERT(xml_helper::compare_xml(path_helper::get_data_directory() + "/writer/expected/sheet1_freeze_panes_both.xml", xml));
|
||||
TS_ASSERT(xml_helper::file_matches_document(path_helper::get_data_directory("writer/expected/sheet1_freeze_panes_both.xml"), xml));
|
||||
}
|
||||
|
||||
void test_long_number()
|
||||
|
@ -272,7 +272,7 @@ public:
|
|||
pugi::xml_document xml;
|
||||
serializer.write_worksheet(xml);
|
||||
|
||||
TS_ASSERT(xml_helper::compare_xml(path_helper::get_data_directory() + "/writer/expected/long_number.xml", xml));
|
||||
TS_ASSERT(xml_helper::file_matches_document(path_helper::get_data_directory("writer/expected/long_number.xml"), xml));
|
||||
}
|
||||
|
||||
void test_short_number()
|
||||
|
@ -284,12 +284,7 @@ public:
|
|||
pugi::xml_document xml;
|
||||
serializer.write_worksheet(xml);
|
||||
|
||||
TS_ASSERT(xml_helper::compare_xml(path_helper::get_data_directory() + "/writer/expected/short_number.xml", xml));
|
||||
}
|
||||
|
||||
void _test_write_images()
|
||||
{
|
||||
TS_SKIP("not implemented");
|
||||
TS_ASSERT(xml_helper::file_matches_document(path_helper::get_data_directory("writer/expected/short_number.xml"), xml));
|
||||
}
|
||||
|
||||
void test_write_page_setup()
|
||||
|
@ -318,7 +313,7 @@ public:
|
|||
|
||||
xlnt::zip_file archive;
|
||||
archive.load(bytes);
|
||||
auto worksheet_xml_string = archive.read("xl/worksheets/sheet1.xml");
|
||||
auto worksheet_xml_string = archive.read(xlnt::path("xl/worksheets/sheet1.xml"));
|
||||
|
||||
pugi::xml_document worksheet_xml;
|
||||
worksheet_xml.load(worksheet_xml_string.c_str());
|
||||
|
@ -342,7 +337,7 @@ public:
|
|||
" <pageSetup orientation=\"landscape\" paperSize=\"11\" fitToHeight=\"1\" fitToWidth=\"1\" />"
|
||||
"</worksheet>";
|
||||
|
||||
TS_ASSERT(xml_helper::compare_xml(expected, worksheet_xml));
|
||||
TS_ASSERT(xml_helper::string_matches_document(expected, worksheet_xml));
|
||||
}
|
||||
|
||||
private:
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include <iostream>
|
||||
#include <cxxtest/TestSuite.h>
|
||||
|
||||
#include <detail/xlsx_writer.hpp>
|
||||
#include <detail/shared_strings_serializer.hpp>
|
||||
#include <detail/workbook_serializer.hpp>
|
||||
#include <helpers/path_helper.hpp>
|
||||
|
@ -22,7 +23,7 @@ public:
|
|||
pugi::xml_document xml;
|
||||
serializer.write_workbook(xml);
|
||||
|
||||
TS_ASSERT(xml_helper::compare_xml(path_helper::get_data_directory("/writer/expected/workbook_auto_filter.xml"), xml));
|
||||
TS_ASSERT(xml_helper::file_matches_document(path_helper::get_data_directory("writer/expected/workbook_auto_filter.xml"), xml));
|
||||
}
|
||||
|
||||
void test_write_hidden_worksheet()
|
||||
|
@ -53,7 +54,7 @@ public:
|
|||
pugi::xml_document expected;
|
||||
expected.load(expected_string.c_str());
|
||||
|
||||
TS_ASSERT(xml_helper::compare_xml(expected.child("workbook").child("sheets"),
|
||||
TS_ASSERT(xml_helper::compare_xml_nodes(expected.child("workbook").child("sheets"),
|
||||
xml.child("workbook").child("sheets")));
|
||||
}
|
||||
|
||||
|
@ -74,10 +75,10 @@ public:
|
|||
xlnt::workbook wb;
|
||||
temporary_file file;
|
||||
|
||||
TS_ASSERT(!file.get_path().exists())
|
||||
xlnt::excel_serializer serializer(wb);
|
||||
serializer.save_workbook(file.get_filename());
|
||||
|
||||
TS_ASSERT(path_helper::file_exists(file.get_filename()));
|
||||
wb.save(file.get_path());
|
||||
TS_ASSERT(file.get_path().exists());
|
||||
}
|
||||
|
||||
void test_write_virtual_workbook()
|
||||
|
@ -102,9 +103,9 @@ public:
|
|||
xlnt::relationship_serializer serializer(archive);
|
||||
serializer.write_relationships(wb.get_relationships(), "xl/workbook.xml");
|
||||
pugi::xml_document observed;
|
||||
observed.load(archive.read("xl/_rels/workbook.xml.rels").c_str());
|
||||
observed.load(archive.read(xlnt::path("xl/_rels/workbook.xml.rels")).c_str());
|
||||
|
||||
TS_ASSERT(xml_helper::compare_xml(path_helper::get_data_directory("/writer/expected/workbook.xml.rels"), observed));
|
||||
TS_ASSERT(xml_helper::file_matches_document(path_helper::get_data_directory("writer/expected/workbook.xml.rels"), observed));
|
||||
}
|
||||
|
||||
void test_write_workbook_part()
|
||||
|
@ -113,9 +114,9 @@ public:
|
|||
xlnt::workbook_serializer serializer(wb);
|
||||
pugi::xml_document xml;
|
||||
serializer.write_workbook(xml);
|
||||
auto filename = path_helper::get_data_directory("/writer/expected/workbook.xml");
|
||||
|
||||
TS_ASSERT(xml_helper::compare_xml(filename, xml));
|
||||
auto filename = path_helper::get_data_directory("writer/expected/workbook.xml");
|
||||
TS_ASSERT(xml_helper::file_matches_document(filename, xml));
|
||||
}
|
||||
|
||||
void test_write_named_range()
|
||||
|
@ -132,7 +133,7 @@ public:
|
|||
"<s:definedName xmlns:s=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\" name=\"test_range\">'Sheet'!$A$1:$B$5</s:definedName>"
|
||||
"</root>";
|
||||
|
||||
TS_ASSERT(xml_helper::compare_xml(expected, xml));
|
||||
TS_ASSERT(xml_helper::string_matches_document(expected, xml));
|
||||
}
|
||||
|
||||
void test_read_workbook_code_name()
|
||||
|
@ -165,7 +166,7 @@ public:
|
|||
pugi::xml_document expected_xml;
|
||||
expected_xml.load(expected.c_str());
|
||||
|
||||
TS_ASSERT(xml_helper::compare_xml(expected_xml.child("workbook").child("workbookPr"),
|
||||
TS_ASSERT(xml_helper::compare_xml_nodes(expected_xml.child("workbook").child("workbookPr"),
|
||||
xml.child("workbook").child("workbookPr")));
|
||||
}
|
||||
|
||||
|
@ -176,7 +177,7 @@ public:
|
|||
xlnt::relationship_serializer serializer(archive);
|
||||
serializer.write_relationships(wb.get_root_relationships(), "");
|
||||
pugi::xml_document observed;
|
||||
observed.load(archive.read("_rels/.rels").c_str());
|
||||
observed.load(archive.read(xlnt::path("_rels/.rels")).c_str());
|
||||
|
||||
std::string expected =
|
||||
"<Relationships xmlns=\"http://schemas.openxmlformats.org/package/2006/relationships\">"
|
||||
|
@ -185,7 +186,7 @@ public:
|
|||
" <Relationship Id=\"rId3\" Target=\"docProps/app.xml\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties\"/>"
|
||||
"</Relationships>";
|
||||
|
||||
TS_ASSERT(xml_helper::compare_xml(expected, observed));
|
||||
TS_ASSERT(xml_helper::string_matches_document(expected, observed));
|
||||
}
|
||||
|
||||
void test_write_shared_strings_with_runs()
|
||||
|
@ -223,44 +224,27 @@ public:
|
|||
" </si>"
|
||||
"</sst>";
|
||||
|
||||
TS_ASSERT(xml_helper::compare_xml(expected, xml));
|
||||
TS_ASSERT(xml_helper::string_matches_document(expected, xml));
|
||||
}
|
||||
|
||||
void test_write_worksheet_order()
|
||||
{
|
||||
auto path = path_helper::get_data_directory("/genuine/tab_order.xlsx");
|
||||
auto path = path_helper::get_data_directory("genuine/tab_order.xlsx");
|
||||
|
||||
// Load an original workbook produced by Excel
|
||||
xlnt::workbook wb_src;
|
||||
{
|
||||
xlnt::excel_serializer serializer(wb_src);
|
||||
serializer.load_workbook(path);
|
||||
}
|
||||
wb_src.load(path);
|
||||
|
||||
// Save it to a new file, unmodified
|
||||
temporary_file file;
|
||||
{
|
||||
xlnt::excel_serializer serializer(wb_src);
|
||||
serializer.save_workbook(file.get_filename());
|
||||
TS_ASSERT(path_helper::file_exists(file.get_filename()));
|
||||
}
|
||||
wb_src.save(file.get_path());
|
||||
TS_ASSERT(file.get_path().exists());
|
||||
|
||||
// Load it again
|
||||
xlnt::workbook wb_dst;
|
||||
{
|
||||
xlnt::excel_serializer serializer(wb_dst);
|
||||
serializer.load_workbook(file.get_filename());
|
||||
}
|
||||
wb_dst.load(file.get_path());
|
||||
|
||||
// Make sure the number of worksheets is the same
|
||||
auto count_src = std::distance(wb_src.begin(), wb_src.end());
|
||||
auto count_dst = std::distance(wb_dst.begin(), wb_dst.end());
|
||||
TS_ASSERT(count_src == count_dst);
|
||||
|
||||
// Make sure the title of the first sheet matches
|
||||
auto ws1title_src = wb_src[0].get_title();
|
||||
auto ws1title_dst = wb_dst[0].get_title();
|
||||
TS_ASSERT(ws1title_src.compare(ws1title_dst) == 0);
|
||||
TS_ASSERT_EQUALS(wb_src.get_sheet_titles(), wb_dst.get_sheet_titles());
|
||||
}
|
||||
|
||||
private:
|
||||
|
|
|
@ -48,6 +48,7 @@
|
|||
#include <xlnt/styles/number_format.hpp>
|
||||
#include <xlnt/styles/protection.hpp>
|
||||
#include <xlnt/utils/exceptions.hpp>
|
||||
#include <xlnt/utils/path.hpp>
|
||||
#include <xlnt/workbook/const_worksheet_iterator.hpp>
|
||||
#include <xlnt/workbook/named_range.hpp>
|
||||
#include <xlnt/workbook/theme.hpp>
|
||||
|
@ -57,39 +58,64 @@
|
|||
#include <xlnt/worksheet/worksheet.hpp>
|
||||
|
||||
namespace xlnt {
|
||||
namespace detail {
|
||||
|
||||
workbook_impl::workbook_impl()
|
||||
: active_sheet_index_(0),
|
||||
guess_types_(false),
|
||||
data_only_(false)
|
||||
workbook workbook::minimal()
|
||||
{
|
||||
auto impl = new detail::workbook_impl();
|
||||
workbook wb(impl);
|
||||
|
||||
return wb;
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
workbook::workbook() : d_(new detail::workbook_impl())
|
||||
workbook workbook::empty_excel()
|
||||
{
|
||||
create_sheet();
|
||||
auto impl = new detail::workbook_impl();
|
||||
xlnt::workbook wb(impl);
|
||||
|
||||
create_relationship("rId2", "styles.xml", relationship::type::styles);
|
||||
create_relationship("rId3", "theme/theme1.xml", relationship::type::theme);
|
||||
wb.set_application("Microsoft Excel");
|
||||
wb.create_sheet();
|
||||
wb.add_format(format());
|
||||
wb.create_style("Normal");
|
||||
wb.set_theme(theme());
|
||||
|
||||
d_->manifest_.add_default_type("rels", "application/vnd.openxmlformats-package.relationships+xml");
|
||||
d_->manifest_.add_default_type("xml", "application/xml");
|
||||
auto &manifest = wb.d_->manifest_;
|
||||
manifest.add_override_type(constants::part_workbook(), "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml");
|
||||
manifest.add_override_type(constants::part_theme(), "application/vnd.openxmlformats-officedocument.theme+xml");
|
||||
manifest.add_override_type(constants::part_styles(), "application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml");
|
||||
manifest.add_override_type(constants::part_core(), "application/vnd.openxmlformats-package.core-properties+xml");
|
||||
manifest.add_override_type(constants::part_app(), "application/vnd.openxmlformats-officedocument.extended-properties+xml");
|
||||
|
||||
d_->manifest_.add_override_type("/" + constants::part_workbook(), "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml");
|
||||
d_->manifest_.add_override_type("/" + constants::part_theme(), "application/vnd.openxmlformats-officedocument.theme+xml");
|
||||
d_->manifest_.add_override_type("/" + constants::part_styles(), "application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml");
|
||||
d_->manifest_.add_override_type("/" + constants::part_core(), "application/vnd.openxmlformats-package.core-properties+xml");
|
||||
d_->manifest_.add_override_type("/" + constants::part_app(), "application/vnd.openxmlformats-officedocument.extended-properties+xml");
|
||||
|
||||
add_format(format());
|
||||
create_style("Normal");
|
||||
d_->stylesheet_.format_styles.front() = "Normal";
|
||||
wb.d_->stylesheet_.format_styles.front() = "Normal";
|
||||
|
||||
xlnt::fill gray125 = xlnt::fill::pattern(xlnt::pattern_fill::type::gray125);
|
||||
d_->stylesheet_.fills.push_back(gray125);
|
||||
wb.d_->stylesheet_.fills.push_back(gray125);
|
||||
|
||||
return wb;
|
||||
}
|
||||
|
||||
workbook workbook::empty_libre_office()
|
||||
{
|
||||
auto impl = new detail::workbook_impl();
|
||||
workbook wb(impl);
|
||||
|
||||
return wb;
|
||||
}
|
||||
|
||||
workbook workbook::empty_numbers()
|
||||
{
|
||||
auto impl = new detail::workbook_impl();
|
||||
workbook wb(impl);
|
||||
|
||||
return wb;
|
||||
}
|
||||
|
||||
workbook::workbook()
|
||||
{
|
||||
swap(*this, empty_excel());
|
||||
}
|
||||
|
||||
workbook::workbook(detail::workbook_impl *impl) : d_(impl)
|
||||
{
|
||||
}
|
||||
|
||||
const worksheet workbook::get_sheet_by_name(const std::string &name) const
|
||||
|
@ -120,17 +146,29 @@ worksheet workbook::get_sheet_by_name(const std::string &name)
|
|||
|
||||
worksheet workbook::get_sheet_by_index(std::size_t index)
|
||||
{
|
||||
return worksheet(&d_->worksheets_[index]);
|
||||
auto iter = d_->worksheets_.begin();
|
||||
|
||||
for (std::size_t i = 0; i < index; ++i, ++iter)
|
||||
{
|
||||
}
|
||||
|
||||
return worksheet(&*iter);
|
||||
}
|
||||
|
||||
const worksheet workbook::get_sheet_by_index(std::size_t index) const
|
||||
{
|
||||
return worksheet(&d_->worksheets_.at(index));
|
||||
auto iter = d_->worksheets_.begin();
|
||||
|
||||
for (std::size_t i = 0; i < index; ++i, ++iter)
|
||||
{
|
||||
}
|
||||
|
||||
return worksheet(&*iter);
|
||||
}
|
||||
|
||||
worksheet workbook::get_active_sheet()
|
||||
{
|
||||
return worksheet(&d_->worksheets_[d_->active_sheet_index_]);
|
||||
return get_sheet_by_index(d_->active_sheet_index_);
|
||||
}
|
||||
|
||||
bool workbook::has_named_range(const std::string &name) const
|
||||
|
@ -157,13 +195,13 @@ worksheet workbook::create_sheet()
|
|||
|
||||
auto sheet_id = d_->worksheets_.size() + 1;
|
||||
std::string sheet_filename = "sheet" + std::to_string(sheet_id) + ".xml";
|
||||
path sheet_path = constants::package_worksheets().append(sheet_filename);
|
||||
|
||||
d_->worksheets_.push_back(detail::worksheet_impl(this, sheet_id, title));
|
||||
create_relationship("rId" + std::to_string(sheet_id),
|
||||
"worksheets/" + sheet_filename,
|
||||
relationship::type::worksheet);
|
||||
d_->manifest_.add_override_type("/" + constants::package_worksheets()
|
||||
+ "/" + sheet_filename,
|
||||
d_->manifest_.add_override_type(sheet_path,
|
||||
"application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml");
|
||||
|
||||
return worksheet(&d_->worksheets_.back());
|
||||
|
@ -185,7 +223,13 @@ void workbook::copy_sheet(xlnt::worksheet worksheet, std::size_t index)
|
|||
|
||||
if (index != d_->worksheets_.size() - 1)
|
||||
{
|
||||
d_->worksheets_.insert(d_->worksheets_.begin() + index, d_->worksheets_.back());
|
||||
auto iter = d_->worksheets_.begin();
|
||||
|
||||
for (std::size_t i = 0; i < index; ++i, ++iter)
|
||||
{
|
||||
}
|
||||
|
||||
d_->worksheets_.insert(iter, d_->worksheets_.back());
|
||||
d_->worksheets_.pop_back();
|
||||
}
|
||||
}
|
||||
|
@ -256,6 +300,11 @@ bool workbook::load(const std::vector<unsigned char> &data)
|
|||
}
|
||||
|
||||
bool workbook::load(const std::string &filename)
|
||||
{
|
||||
return load(path(filename));
|
||||
}
|
||||
|
||||
bool workbook::load(const path &filename)
|
||||
{
|
||||
excel_serializer serializer_(*this);
|
||||
serializer_.load_workbook(filename);
|
||||
|
@ -320,11 +369,17 @@ worksheet workbook::create_sheet(std::size_t index)
|
|||
|
||||
if (index != d_->worksheets_.size() - 1)
|
||||
{
|
||||
d_->worksheets_.insert(d_->worksheets_.begin() + index, d_->worksheets_.back());
|
||||
auto iter = d_->worksheets_.begin();
|
||||
|
||||
for (std::size_t i = 0; i < index; ++i, ++iter)
|
||||
{
|
||||
}
|
||||
|
||||
d_->worksheets_.insert(iter, d_->worksheets_.back());
|
||||
d_->worksheets_.pop_back();
|
||||
}
|
||||
|
||||
return worksheet(&d_->worksheets_[index]);
|
||||
return get_sheet_by_index(index);
|
||||
}
|
||||
|
||||
worksheet workbook::create_sheet_with_rel(const std::string &title, const relationship &rel)
|
||||
|
@ -384,7 +439,7 @@ worksheet workbook::operator[](const std::string &name)
|
|||
|
||||
worksheet workbook::operator[](std::size_t index)
|
||||
{
|
||||
return worksheet(&d_->worksheets_.at(index));
|
||||
return get_sheet_by_index(index);
|
||||
}
|
||||
|
||||
void workbook::clear()
|
||||
|
@ -392,7 +447,6 @@ void workbook::clear()
|
|||
d_->worksheets_.clear();
|
||||
d_->relationships_.clear();
|
||||
d_->active_sheet_index_ = 0;
|
||||
d_->properties_ = document_properties();
|
||||
d_->manifest_.clear();
|
||||
clear_styles();
|
||||
clear_formats();
|
||||
|
@ -407,6 +461,11 @@ bool workbook::save(std::vector<unsigned char> &data)
|
|||
}
|
||||
|
||||
bool workbook::save(const std::string &filename)
|
||||
{
|
||||
return save(path(filename));
|
||||
}
|
||||
|
||||
bool workbook::save(const path &filename)
|
||||
{
|
||||
excel_serializer serializer(*this);
|
||||
serializer.save_workbook(filename);
|
||||
|
@ -429,41 +488,26 @@ const std::vector<relationship> &xlnt::workbook::get_relationships() const
|
|||
return d_->relationships_;
|
||||
}
|
||||
|
||||
document_properties &workbook::get_properties()
|
||||
{
|
||||
return d_->properties_;
|
||||
}
|
||||
|
||||
const document_properties &workbook::get_properties() const
|
||||
{
|
||||
return d_->properties_;
|
||||
}
|
||||
|
||||
app_properties &workbook::get_app_properties()
|
||||
{
|
||||
return d_->app_properties_;
|
||||
}
|
||||
|
||||
const app_properties &workbook::get_app_properties() const
|
||||
{
|
||||
return d_->app_properties_;
|
||||
}
|
||||
|
||||
|
||||
void swap(workbook &left, workbook &right)
|
||||
{
|
||||
using std::swap;
|
||||
swap(left.d_, right.d_);
|
||||
|
||||
if (left.d_ != nullptr)
|
||||
{
|
||||
for (auto ws : left)
|
||||
{
|
||||
ws.set_parent(left);
|
||||
}
|
||||
}
|
||||
|
||||
if (right.d_ != nullptr)
|
||||
{
|
||||
for (auto ws : right)
|
||||
{
|
||||
ws.set_parent(right);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
workbook &workbook::operator=(workbook other)
|
||||
|
@ -472,7 +516,7 @@ workbook &workbook::operator=(workbook other)
|
|||
return *this;
|
||||
}
|
||||
|
||||
workbook::workbook(workbook &&other) : workbook()
|
||||
workbook::workbook(workbook &&other) : workbook(nullptr)
|
||||
{
|
||||
swap(*this, other);
|
||||
}
|
||||
|
@ -505,16 +549,42 @@ void workbook::set_code_name(const std::string & /*code_name*/)
|
|||
{
|
||||
}
|
||||
|
||||
bool workbook::has_loaded_theme() const
|
||||
bool workbook::has_theme() const
|
||||
{
|
||||
return false;
|
||||
return d_->has_theme_;
|
||||
}
|
||||
|
||||
const theme &workbook::get_loaded_theme() const
|
||||
const theme &workbook::get_theme() const
|
||||
{
|
||||
return d_->theme_;
|
||||
}
|
||||
|
||||
void workbook::set_theme(const theme &value)
|
||||
{
|
||||
if (!d_->has_theme_)
|
||||
{
|
||||
bool has_theme_relationship = false;
|
||||
|
||||
for (const auto &rel : get_relationships())
|
||||
{
|
||||
if (rel.get_type() == relationship::type::theme)
|
||||
{
|
||||
has_theme_relationship = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!has_theme_relationship)
|
||||
{
|
||||
create_relationship(next_relationship_id(), "theme/theme1.xml", relationship::type::theme);
|
||||
d_->manifest_.add_override_type(constants::part_theme(), "application/vnd.openxmlformats-officedocument.spreadsheetml.theme+xml");
|
||||
}
|
||||
}
|
||||
|
||||
d_->has_theme_ = true;
|
||||
d_->theme_ = value;
|
||||
}
|
||||
|
||||
std::vector<named_range> workbook::get_named_ranges() const
|
||||
{
|
||||
std::vector<named_range> named_ranges;
|
||||
|
@ -532,11 +602,51 @@ std::vector<named_range> workbook::get_named_ranges() const
|
|||
|
||||
std::size_t workbook::add_format(const format &to_add)
|
||||
{
|
||||
if (d_->stylesheet_.formats.empty())
|
||||
{
|
||||
bool has_style_relationship = false;
|
||||
|
||||
for (const auto &rel : get_relationships())
|
||||
{
|
||||
if (rel.get_type() == relationship::type::styles)
|
||||
{
|
||||
has_style_relationship = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!has_style_relationship)
|
||||
{
|
||||
create_relationship(next_relationship_id(), "styles.xml", relationship::type::styles);
|
||||
d_->manifest_.add_override_type(constants::part_styles(), "application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml");
|
||||
}
|
||||
}
|
||||
|
||||
return d_->stylesheet_.add_format(to_add);
|
||||
}
|
||||
|
||||
std::size_t workbook::add_style(const style &to_add)
|
||||
{
|
||||
if (d_->stylesheet_.formats.empty())
|
||||
{
|
||||
bool has_style_relationship = false;
|
||||
|
||||
for (const auto &rel : get_relationships())
|
||||
{
|
||||
if (rel.get_type() == relationship::type::styles)
|
||||
{
|
||||
has_style_relationship = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!has_style_relationship)
|
||||
{
|
||||
create_relationship(next_relationship_id(), "styles.xml", relationship::type::styles);
|
||||
d_->manifest_.add_override_type(constants::part_styles(), "application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml");
|
||||
}
|
||||
}
|
||||
|
||||
return d_->stylesheet_.add_style(to_add);
|
||||
}
|
||||
|
||||
|
@ -604,11 +714,11 @@ const std::vector<relationship> &workbook::get_root_relationships() const
|
|||
if (d_->root_relationships_.empty())
|
||||
{
|
||||
d_->root_relationships_.push_back(
|
||||
relationship(relationship::type::core_properties, "rId1", constants::part_core()));
|
||||
relationship(relationship::type::core_properties, "rId1", constants::part_core().to_string()));
|
||||
d_->root_relationships_.push_back(
|
||||
relationship(relationship::type::extended_properties, "rId2", constants::part_app()));
|
||||
relationship(relationship::type::extended_properties, "rId2", constants::part_app().to_string()));
|
||||
d_->root_relationships_.push_back(
|
||||
relationship(relationship::type::office_document, "rId3", constants::part_workbook()));
|
||||
relationship(relationship::type::office_document, "rId3", constants::part_workbook().to_string()));
|
||||
}
|
||||
|
||||
return d_->root_relationships_;
|
||||
|
@ -642,7 +752,7 @@ void workbook::add_shared_string(const text &shared, bool allow_duplicates)
|
|||
if (!has_shared_strings)
|
||||
{
|
||||
create_relationship(next_relationship_id(), "sharedStrings.xml", relationship::type::shared_strings);
|
||||
d_->manifest_.add_override_type("/" + constants::part_shared_strings(), "application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml");
|
||||
d_->manifest_.add_override_type(constants::part_shared_strings(), "application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -723,4 +833,146 @@ std::string workbook::next_relationship_id() const
|
|||
return "rId" + std::to_string(i);
|
||||
}
|
||||
|
||||
std::string workbook::get_application() const
|
||||
{
|
||||
return d_->application_;
|
||||
}
|
||||
|
||||
void workbook::set_application(const std::string &application)
|
||||
{
|
||||
d_->write_app_properties_ = true;
|
||||
d_->application_ = application;
|
||||
}
|
||||
|
||||
calendar workbook::get_base_date() const
|
||||
{
|
||||
return d_->base_date_;
|
||||
}
|
||||
|
||||
void workbook::set_base_date(calendar base_date)
|
||||
{
|
||||
d_->base_date_ = base_date;
|
||||
}
|
||||
|
||||
std::string workbook::get_creator() const
|
||||
{
|
||||
return d_->creator_;
|
||||
}
|
||||
|
||||
void workbook::set_creator(const std::string &creator)
|
||||
{
|
||||
d_->creator_ = creator;
|
||||
}
|
||||
|
||||
std::string workbook::get_last_modified_by() const
|
||||
{
|
||||
return d_->last_modified_by_;
|
||||
}
|
||||
|
||||
void workbook::set_last_modified_by(const std::string &last_modified_by)
|
||||
{
|
||||
d_->last_modified_by_ = last_modified_by;
|
||||
}
|
||||
|
||||
datetime workbook::get_created() const
|
||||
{
|
||||
return d_->created_;
|
||||
}
|
||||
|
||||
void workbook::set_created(const datetime &when)
|
||||
{
|
||||
d_->created_ = when;
|
||||
}
|
||||
|
||||
datetime workbook::get_modified() const
|
||||
{
|
||||
return d_->modified_;
|
||||
}
|
||||
|
||||
void workbook::set_modified(const datetime &when)
|
||||
{
|
||||
d_->modified_ = when;
|
||||
}
|
||||
|
||||
int workbook::get_doc_security() const
|
||||
{
|
||||
return d_->doc_security_;
|
||||
}
|
||||
|
||||
void workbook::set_doc_security(int doc_security)
|
||||
{
|
||||
d_->doc_security_ = doc_security;
|
||||
}
|
||||
|
||||
bool workbook::get_scale_crop() const
|
||||
{
|
||||
return d_->scale_crop_;
|
||||
}
|
||||
|
||||
void workbook::set_scale_crop(bool scale_crop)
|
||||
{
|
||||
d_->scale_crop_ = scale_crop;
|
||||
}
|
||||
|
||||
std::string workbook::get_company() const
|
||||
{
|
||||
return d_->company_;
|
||||
}
|
||||
|
||||
void workbook::set_company(const std::string &company)
|
||||
{
|
||||
d_->company_ = company;
|
||||
}
|
||||
|
||||
bool workbook::links_up_to_date() const
|
||||
{
|
||||
return d_->links_up_to_date_;
|
||||
}
|
||||
|
||||
void workbook::set_links_up_to_date(bool links_up_to_date)
|
||||
{
|
||||
d_->links_up_to_date_ = links_up_to_date;
|
||||
}
|
||||
|
||||
bool workbook::is_shared_doc() const
|
||||
{
|
||||
return d_->shared_doc_;
|
||||
}
|
||||
|
||||
void workbook::set_shared_doc(bool shared_doc)
|
||||
{
|
||||
d_->shared_doc_ = shared_doc;
|
||||
}
|
||||
|
||||
bool workbook::hyperlinks_changed() const
|
||||
{
|
||||
return d_->hyperlinks_changed_;
|
||||
}
|
||||
|
||||
void workbook::set_hyperlinks_changed(bool hyperlinks_changed)
|
||||
{
|
||||
d_->hyperlinks_changed_ = hyperlinks_changed;
|
||||
}
|
||||
|
||||
std::string workbook::get_app_version() const
|
||||
{
|
||||
return d_->app_version_;
|
||||
}
|
||||
|
||||
void workbook::set_app_version(const std::string &version)
|
||||
{
|
||||
d_->app_version_ = version;
|
||||
}
|
||||
|
||||
std::string workbook::get_title() const
|
||||
{
|
||||
return d_->title_;
|
||||
}
|
||||
|
||||
void workbook::set_title(const std::string &title)
|
||||
{
|
||||
d_->title_ = title;
|
||||
}
|
||||
|
||||
|
||||
} // namespace xlnt
|
||||
|
|
|
@ -22,39 +22,8 @@
|
|||
class path_helper
|
||||
{
|
||||
public:
|
||||
static std::string read_file(const std::string &filename)
|
||||
static xlnt::path get_executable_directory()
|
||||
{
|
||||
std::ifstream f(filename);
|
||||
std::ostringstream ss;
|
||||
ss << f.rdbuf();
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
static std::string windows_to_universal_path(const std::string &windows_path)
|
||||
{
|
||||
std::string fixed;
|
||||
std::stringstream ss(windows_path);
|
||||
std::string part;
|
||||
|
||||
while(std::getline(ss, part, '\\'))
|
||||
{
|
||||
if(fixed == "")
|
||||
{
|
||||
fixed = part;
|
||||
}
|
||||
else
|
||||
{
|
||||
fixed += "/" + part;
|
||||
}
|
||||
}
|
||||
|
||||
return fixed;
|
||||
}
|
||||
|
||||
static std::string get_executable_directory()
|
||||
{
|
||||
|
||||
#ifdef __APPLE__
|
||||
std::array<char, 1024> path;
|
||||
uint32_t size = static_cast<uint32_t>(path.size());
|
||||
|
@ -74,7 +43,8 @@ public:
|
|||
{
|
||||
throw std::runtime_error("GetModuleFileName failed or buffer was too small");
|
||||
}
|
||||
return windows_to_universal_path(std::string(buffer.begin(), buffer.begin() + result - 13)) + "/";
|
||||
|
||||
return xlnt::path(std::string(buffer.begin(), buffer.begin() + result - 13));
|
||||
#else
|
||||
char arg1[20];
|
||||
char exepath[PATH_MAX + 1] = {0};
|
||||
|
@ -86,13 +56,17 @@ public:
|
|||
#endif
|
||||
}
|
||||
|
||||
static std::string get_working_directory()
|
||||
static xlnt::path get_working_directory(const std::string &append = "")
|
||||
{
|
||||
#ifdef _WIN32
|
||||
#ifdef _MSC_VER
|
||||
TCHAR buffer[MAX_PATH];
|
||||
GetCurrentDirectory(MAX_PATH, buffer);
|
||||
|
||||
std::basic_string<TCHAR> working_directory(buffer);
|
||||
return windows_to_universal_path(std::string(working_directory.begin(), working_directory.end()));
|
||||
std::string working_directory_narrow(working_directory.begin(), working_directory.end());
|
||||
|
||||
return xlnt::path(working_directory_narrow)
|
||||
.append(xlnt::path(append));
|
||||
#else
|
||||
char buffer[PATH_MAX];
|
||||
|
||||
|
@ -105,59 +79,28 @@ public:
|
|||
#endif
|
||||
}
|
||||
|
||||
static std::string get_data_directory(const std::string &append = "")
|
||||
static xlnt::path get_data_directory(const std::string &append = "")
|
||||
{
|
||||
auto path = get_executable_directory() + "../../tests/data";
|
||||
|
||||
if (!append.empty())
|
||||
{
|
||||
if (append.front() != '/')
|
||||
{
|
||||
path.push_back('/');
|
||||
return xlnt::path("../../tests/data")
|
||||
.make_absolute(get_executable_directory())
|
||||
.append(xlnt::path(append));
|
||||
}
|
||||
|
||||
path.append(append);
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
static void copy_file(const std::string &source, const std::string &destination, bool overwrite)
|
||||
static void copy_file(const xlnt::path &source, const xlnt::path &destination, bool overwrite)
|
||||
{
|
||||
if(!overwrite && file_exists(destination))
|
||||
if(!overwrite && destination.exists())
|
||||
{
|
||||
throw std::runtime_error("destination file already exists and overwrite==false");
|
||||
}
|
||||
|
||||
std::ifstream src(source, std::ios::binary);
|
||||
std::ofstream dst(destination, std::ios::binary);
|
||||
std::ifstream src(source.to_string(), std::ios::binary);
|
||||
std::ofstream dst(destination.to_string(), std::ios::binary);
|
||||
|
||||
dst << src.rdbuf();
|
||||
}
|
||||
|
||||
static void delete_file(const std::string &path)
|
||||
static void delete_file(const xlnt::path &path)
|
||||
{
|
||||
std::remove(path.c_str());
|
||||
}
|
||||
|
||||
static bool file_exists(const std::string &path)
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
std::wstring path_wide(path.begin(), path.end());
|
||||
return PathFileExists(path_wide.c_str()) && !PathIsDirectory(path_wide.c_str());
|
||||
#else
|
||||
try
|
||||
{
|
||||
struct stat fileAtt;
|
||||
|
||||
if (stat(path.c_str(), &fileAtt) == 0)
|
||||
{
|
||||
return S_ISREG(fileAtt.st_mode);
|
||||
}
|
||||
}
|
||||
catch(...) {}
|
||||
|
||||
return false;
|
||||
#endif
|
||||
std::remove(path.to_string().c_str());
|
||||
}
|
||||
};
|
||||
|
|
|
@ -7,47 +7,50 @@
|
|||
#include <detail/include_windows.hpp>
|
||||
#include <helpers/path_helper.hpp>
|
||||
|
||||
class temporary_file
|
||||
namespace {
|
||||
|
||||
static std::string create_temporary_filename()
|
||||
{
|
||||
public:
|
||||
static std::string create()
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
std::array<TCHAR, MAX_PATH> buffer;
|
||||
DWORD result = GetTempPath(static_cast<DWORD>(buffer.size()), buffer.data());
|
||||
|
||||
if(result > MAX_PATH)
|
||||
if (result > MAX_PATH)
|
||||
{
|
||||
throw std::runtime_error("buffer is too small");
|
||||
}
|
||||
|
||||
if(result == 0)
|
||||
if (result == 0)
|
||||
{
|
||||
throw std::runtime_error("GetTempPath failed");
|
||||
}
|
||||
|
||||
std::string directory(buffer.begin(), buffer.begin() + result);
|
||||
return path_helper::windows_to_universal_path(directory + "xlnt.xlsx");
|
||||
return std::string(buffer.begin(), buffer.begin() + result) + "xlnt.xlsx";
|
||||
#else
|
||||
return "/tmp/xlnt.xlsx";
|
||||
#endif
|
||||
}
|
||||
|
||||
temporary_file() : filename_(create())
|
||||
} // namespace
|
||||
|
||||
class temporary_file
|
||||
{
|
||||
public:
|
||||
temporary_file() : path_(create_temporary_filename())
|
||||
{
|
||||
if(path_helper::file_exists(get_filename()))
|
||||
if(path_.exists())
|
||||
{
|
||||
std::remove(filename_.c_str());
|
||||
std::remove(path_.to_string().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
~temporary_file()
|
||||
{
|
||||
std::remove(filename_.c_str());
|
||||
std::remove(path_.to_string().c_str());
|
||||
}
|
||||
|
||||
std::string get_filename() const { return filename_; }
|
||||
xlnt::path get_path() const { return path_; }
|
||||
|
||||
private:
|
||||
const std::string filename_;
|
||||
const xlnt::path path_;
|
||||
};
|
||||
|
|
|
@ -32,46 +32,56 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
static comparison_result compare_xml(const pugi::xml_document &expected, const pugi::xml_document &observed)
|
||||
static bool documents_match(const pugi::xml_document &expected,
|
||||
const pugi::xml_document &observed)
|
||||
{
|
||||
return compare_xml(expected.root(), observed.root());
|
||||
auto result = compare_xml_nodes(expected.root(), observed.root());
|
||||
|
||||
if (!result)
|
||||
{
|
||||
std::cout << "documents don't match" << std::endl;
|
||||
|
||||
std::cout << "expected:" << std::endl;
|
||||
expected.save(std::cout);
|
||||
std::cout << std::endl;
|
||||
|
||||
std::cout << "observed:" << std::endl;
|
||||
observed.save(std::cout);
|
||||
std::cout << std::endl;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static comparison_result compare_xml(const std::string &expected, const pugi::xml_document &observed)
|
||||
{
|
||||
std::string expected_contents = expected;
|
||||
|
||||
if(path_helper::file_exists(expected))
|
||||
{
|
||||
std::ifstream f(expected);
|
||||
std::ostringstream s;
|
||||
f >> s.rdbuf();
|
||||
|
||||
expected_contents = s.str();
|
||||
return true;
|
||||
}
|
||||
|
||||
pugi::xml_document expected_xml;
|
||||
expected_xml.load(expected_contents.c_str());
|
||||
|
||||
std::ostringstream ss;
|
||||
observed.save(ss);
|
||||
auto observed_string = ss.str();
|
||||
|
||||
return compare_xml(expected_xml.root(), observed.root());
|
||||
static bool file_matches_document(const xlnt::path &expected,
|
||||
const pugi::xml_document &observed)
|
||||
{
|
||||
return string_matches_document(expected.read_contents(), observed);
|
||||
}
|
||||
|
||||
static comparison_result compare_xml(const std::string &left_contents, const std::string &right_contents)
|
||||
static bool string_matches_document(const std::string &expected_string,
|
||||
const pugi::xml_document &observed_document)
|
||||
{
|
||||
pugi::xml_document expected_document;
|
||||
expected_document.load(expected_string.c_str());
|
||||
|
||||
return documents_match(expected_document, observed_document);
|
||||
}
|
||||
|
||||
static bool strings_match(const std::string &expected_string, const std::string &observed_string)
|
||||
{
|
||||
pugi::xml_document left_xml;
|
||||
left_xml.load(left_contents.c_str());
|
||||
left_xml.load(expected_string.c_str());
|
||||
|
||||
pugi::xml_document right_xml;
|
||||
right_xml.load(right_contents.c_str());
|
||||
right_xml.load(observed_string.c_str());
|
||||
|
||||
return compare_xml(left_xml.root(), right_xml.root());
|
||||
return documents_match(left_xml, right_xml);
|
||||
}
|
||||
|
||||
static comparison_result compare_xml(const pugi::xml_node &left, const pugi::xml_node &right)
|
||||
static comparison_result compare_xml_nodes(const pugi::xml_node &left, const pugi::xml_node &right)
|
||||
{
|
||||
std::string left_temp = left.name();
|
||||
std::string right_temp = right.name();
|
||||
|
@ -136,7 +146,7 @@ public:
|
|||
auto right_child = *right_child_iter;
|
||||
right_child_iter++;
|
||||
|
||||
auto child_comparison_result = compare_xml(left_child, right_child);
|
||||
auto child_comparison_result = compare_xml_nodes(left_child, right_child);
|
||||
|
||||
if(!child_comparison_result)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue
Block a user