intermediate commit

This commit is contained in:
Thomas Fussell 2017-06-15 18:10:27 -04:00
parent 9d312ee7f4
commit 342184139f
4 changed files with 122 additions and 40 deletions

View File

@ -26,6 +26,7 @@
#include <functional>
#include <iostream>
#include <memory>
#include <string>
#include <vector>
#include <xlnt/xlnt_config.hpp>
@ -33,7 +34,10 @@
namespace xlnt {
class cell;
template<typename T>
class optional;
class path;
class workbook;
class worksheet;
namespace detail {
@ -55,24 +59,23 @@ public:
void close();
/// <summary>
/// Registers callback as the function to be called when a cell is read.
/// Reads the next cell in the current worksheet and optionally returns it if
/// the last cell in the sheet has not yet been read.
/// </summary>
void on_cell(std::function<void(cell)> callback);
cell read_cell();
/// <summary>
/// Registers callback as the function to be called when a worksheet is
/// opened for reading. The callback will be called with the title of the
/// worksheet.
/// Beings reading of the next worksheet in the workbook and optionally
/// returns its title if the last worksheet has not yet been read.
/// </summary>
void on_worksheet_start(std::function<void(std::string)> callback);
std::string begin_worksheet();
/// <summary>
/// Registers callback as the function to be called when a worksheet is
/// finished being read. The callback will be called with the worksheet
/// object (which will not contain any cells). Cells should be handled
/// via registering a callback with on_cell.
/// Ends reading of the current worksheet in the workbook and optionally
/// returns a worksheet object corresponding to the worksheet with the title
/// returned by begin_worksheet().
/// </summary>
void on_worksheet_end(std::function<void(worksheet)> callback);
worksheet end_worksheet();
/// <summary>
/// Interprets byte vector data as an XLSX file and sets the content of this
@ -107,7 +110,8 @@ public:
void open(std::istream &stream);
private:
std::unique_ptr<xlnt::detail::xlsx_consumer> consumer_;
std::unique_ptr<detail::xlsx_consumer> consumer_;
std::unique_ptr<workbook> workbook_;
};
} // namespace xlnt

View File

@ -34,6 +34,7 @@
#include <xlnt/cell/cell.hpp>
#include <xlnt/cell/comment.hpp>
#include <xlnt/packaging/manifest.hpp>
#include <xlnt/utils/optional.hpp>
#include <xlnt/utils/path.hpp>
#include <xlnt/workbook/workbook.hpp>
#include <xlnt/worksheet/worksheet.hpp>
@ -135,7 +136,28 @@ xlsx_consumer::xlsx_consumer(workbook &target)
void xlsx_consumer::read(std::istream &source)
{
archive_.reset(new izstream(source));
populate_workbook();
populate_workbook(false);
}
void xlsx_consumer::open(std::istream &source)
{
archive_.reset(new izstream(source));
populate_workbook(true);
}
cell xlsx_consumer::read_cell()
{
return cell(nullptr);
}
std::string xlsx_consumer::begin_worksheet()
{
return "";
}
worksheet xlsx_consumer::end_worksheet()
{
return worksheet(nullptr);
}
xml::parser &xlsx_consumer::parser()
@ -179,7 +201,7 @@ std::vector<relationship> xlsx_consumer::read_relationships(const path &part)
return relationships;
}
void xlsx_consumer::read_part(const std::vector<relationship> &rel_chain)
void xlsx_consumer::read_part(const std::vector<relationship> &rel_chain, bool streaming)
{
const auto &manifest = target_.manifest();
const auto part_path = manifest.canonicalize(rel_chain);
@ -203,7 +225,7 @@ void xlsx_consumer::read_part(const std::vector<relationship> &rel_chain)
break;
case relationship_type::office_document:
read_office_document(manifest.content_type(part_path));
read_office_document(manifest.content_type(part_path), streaming);
break;
case relationship_type::connections:
@ -315,7 +337,7 @@ void xlsx_consumer::read_part(const std::vector<relationship> &rel_chain)
parser_ = nullptr;
}
void xlsx_consumer::populate_workbook()
void xlsx_consumer::populate_workbook(bool streaming)
{
target_.clear();
@ -335,7 +357,7 @@ void xlsx_consumer::populate_workbook()
continue;
}
read_part({package_rel});
read_part({package_rel}, streaming);
}
for (const auto &relationship_source_string : archive_->files())
@ -347,7 +369,7 @@ void xlsx_consumer::populate_workbook()
}
read_part({ manifest().relationship(root_path,
relationship_type::office_document) });
relationship_type::office_document) }, true);
}
// Package Parts
@ -442,7 +464,7 @@ void xlsx_consumer::read_custom_properties()
expect_end_element(qn("custom-properties", "Properties"));
}
void xlsx_consumer::read_office_document(const std::string &content_type) // CT_Workbook
void xlsx_consumer::read_office_document(const std::string &content_type, bool streaming) // CT_Workbook
{
if (content_type != "application/vnd."
"openxmlformats-officedocument.spreadsheetml.sheet.main+xml"
@ -634,22 +656,33 @@ void xlsx_consumer::read_office_document(const std::string &content_type) // CT_
if (manifest().has_relationship(workbook_path, relationship_type::shared_string_table))
{
read_part({workbook_rel, manifest().relationship(workbook_path, relationship_type::shared_string_table)});
read_part({workbook_rel,
manifest().relationship(workbook_path,
relationship_type::shared_string_table)}, false);
}
if (manifest().has_relationship(workbook_path, relationship_type::stylesheet))
{
read_part({workbook_rel, manifest().relationship(workbook_path, relationship_type::stylesheet)});
read_part({workbook_rel,
manifest().relationship(workbook_path,
relationship_type::stylesheet)}, false);
}
if (manifest().has_relationship(workbook_path, relationship_type::theme))
{
read_part({workbook_rel, manifest().relationship(workbook_path, relationship_type::theme)});
read_part({workbook_rel,
manifest().relationship(workbook_path,
relationship_type::theme)}, false);
}
if (streaming)
{
return;
}
for (auto worksheet_rel : manifest().relationships(workbook_path, relationship_type::worksheet))
{
read_part({workbook_rel, worksheet_rel});
read_part({workbook_rel, worksheet_rel}, false);
}
}
@ -1358,15 +1391,19 @@ void xlsx_consumer::read_stylesheet()
void xlsx_consumer::read_theme()
{
auto workbook_rel = manifest().relationship(path("/"), relationship_type::office_document);
auto theme_rel = manifest().relationship(workbook_rel.target().path(), relationship_type::theme);
auto workbook_rel = manifest().relationship(path("/"),
relationship_type::office_document);
auto theme_rel = manifest().relationship(workbook_rel.target().path(),
relationship_type::theme);
auto theme_path = manifest().canonicalize({workbook_rel, theme_rel});
target_.theme(theme());
if (manifest().has_relationship(theme_path, relationship_type::image))
{
read_part({workbook_rel, theme_rel, manifest().relationship(theme_path, relationship_type::image)});
read_part({workbook_rel, theme_rel,
manifest().relationship(theme_path,
relationship_type::image)}, false);
}
}

View File

@ -28,6 +28,7 @@
#include <functional>
#include <iostream>
#include <memory>
#include <string>
#include <unordered_map>
#include <vector>
@ -36,9 +37,12 @@
namespace xlnt {
class cell;
class color;
class rich_text;
class manifest;
template<typename T>
class optional;
class path;
class relationship;
class variant;
@ -57,6 +61,30 @@ class xlsx_consumer
public:
xlsx_consumer(workbook &destination);
void open(std::istream &source);
/// <summary>
/// Reads the next cell in the current worksheet and optionally returns it if
/// the last cell in the sheet has not yet been read. An exception will be thrown
/// if this is not open as a streaming consumer.
/// </summary>
cell read_cell();
/// <summary>
/// Beings reading of the next worksheet in the workbook and optionally
/// returns its title if the last worksheet has not yet been read. An
/// exception will be thrown if this is not open as a streaming consumer.
/// </summary>
std::string begin_worksheet();
/// <summary>
/// Ends reading of the current worksheet in the workbook and optionally
/// returns a worksheet object corresponding to the worksheet with the title
/// returned by begin_worksheet(). An exception will be thrown if this is
/// not open as a streaming consumer.
/// </summary>
worksheet end_worksheet();
void read(std::istream &source);
void read(std::istream &source, const std::string &password);
@ -66,7 +94,7 @@ private:
/// Read all the files needed from the XLSX archive and initialize all of
/// the data in the workbook to match.
/// </summary>
void populate_workbook();
void populate_workbook(bool streaming);
/// <summary>
///
@ -96,7 +124,7 @@ private:
/// Parse the main XML document about the workbook and then all child relationships
/// of the workbook (e.g. worksheets).
/// </summary>
void read_office_document(const std::string &content_type);
void read_office_document(const std::string &content_type, bool streaming);
// Workbook Relationship Target Parts
@ -257,7 +285,7 @@ private:
/// xlsx_consumer::parser() will return a reference to the parser that reads
/// this part.
/// </summary>
void read_part(const std::vector<relationship> &rel_chain);
void read_part(const std::vector<relationship> &rel_chain, bool streaming);
/// <summary>
/// libstudxml will throw an exception if all attributes on an element are not

View File

@ -22,8 +22,15 @@
// @license: http://www.opensource.org/licenses/mit-license.php
// @author: see AUTHORS file
#include <fstream>
#include <detail/serialization/vector_streambuf.hpp>
#include <detail/serialization/xlsx_consumer.hpp>
#include <xlnt/cell/cell.hpp>
#include <xlnt/utils/optional.hpp>
#include <xlnt/workbook/streaming_workbook_reader.hpp>
#include <xlnt/workbook/workbook.hpp>
#include <xlnt/worksheet/worksheet.hpp>
namespace xlnt {
@ -40,46 +47,52 @@ void streaming_workbook_reader::close()
}
}
void streaming_workbook_reader::on_cell(std::function<void(cell)> callback)
cell streaming_workbook_reader::read_cell()
{
//consumer_->on_cell(callback);
return consumer_->read_cell();
}
void streaming_workbook_reader::on_worksheet_start(std::function<void(std::string)> callback)
std::string streaming_workbook_reader::begin_worksheet()
{
//consumer_->on_worksheet_start(callback);
return consumer_->begin_worksheet();
}
void streaming_workbook_reader::on_worksheet_end(std::function<void(worksheet)> callback)
worksheet streaming_workbook_reader::end_worksheet()
{
//consumer_->on_worksheet_end(callback);
return consumer_->end_worksheet();
}
void streaming_workbook_reader::open(const std::vector<std::uint8_t> &data)
{
detail::vector_istreambuf buffer(data);
std::istream buffer_stream(&buffer);
open(buffer_stream);
}
void streaming_workbook_reader::open(const std::string &filename)
{
std::ifstream file_stream(filename, std::ios::binary);
open(file_stream);
}
#ifdef _MSC_VER
void streaming_workbook_reader::open(const std::wstring &filename)
{
std::ifstream file_stream(filename, std::ios::binary);
open(file_stream);
}
#endif
void streaming_workbook_reader::open(const xlnt::path &filename)
{
open(filename.string());
}
void streaming_workbook_reader::open(std::istream &stream)
{
workbook_.reset(new workbook());
consumer_.reset(new detail::xlsx_consumer(*workbook_));
consumer_->open(stream);
}
} // namespace xlnt