getting there

This commit is contained in:
Thomas Fussell 2017-04-30 20:21:47 -04:00
parent 4da901d387
commit ee642fc6c1
5 changed files with 115 additions and 149 deletions

View File

@ -25,6 +25,7 @@
#include <cstdint>
#include <cstring>
#include <iostream>
#include <vector>
#include <xlnt/utils/exceptions.hpp>

View File

@ -105,13 +105,15 @@ public:
compound_document_istreambuf(const compound_document_entry &entry, compound_document &document)
: entry_(entry),
document_(document),
position_(0),
sector_writer_(current_sector_)
sector_writer_(current_sector_),
position_(0)
{
}
compound_document_istreambuf(const compound_document_istreambuf &) = delete;
compound_document_istreambuf &operator=(const compound_document_istreambuf &) = delete;
virtual ~compound_document_istreambuf();
private:
int_type underflow()
@ -220,6 +222,10 @@ private:
std::size_t position_;
};
compound_document_istreambuf::~compound_document_istreambuf()
{
}
/// <summary>
/// Allows a std::vector to be written through a std::ostream.
/// </summary>
@ -231,164 +237,119 @@ public:
compound_document_ostreambuf(compound_document_entry &entry, compound_document &document)
: entry_(entry),
document_(document),
position_(0),
sector_reader_(current_sector_),
current_sector_(sector_size(), 0),
chain_(document_.follow_chain(entry_.start, table()))
current_sector_(document.header_.threshold),
position_(0)
{
setp(reinterpret_cast<char *>(current_sector_.data()),
reinterpret_cast<char *>(current_sector_.data() + current_sector_.size()));
}
compound_document_ostreambuf(const compound_document_ostreambuf &) = delete;
compound_document_ostreambuf &operator=(const compound_document_ostreambuf &) = delete;
virtual ~compound_document_ostreambuf()
{
if (position_ % 64 != 0)
{
write_sector();
}
}
virtual ~compound_document_ostreambuf();
private:
int sync()
{
auto written = pptr() - pbase();
if (written == 0)
{
return 0;
}
sector_reader_.reset();
if (short_stream())
{
if (position_ + written >= document_.header_.threshold)
{
convert_to_long_stream();
}
else
{
if (entry_.start < 0)
{
auto num_sectors = (position_ + written + document_.short_sector_size() - 1) / document_.short_sector_size();
chain_ = document_.allocate_short_sectors(num_sectors);
entry_.start = chain_.front();
}
for (auto link : chain_)
{
document_.write_short_sector(sector_reader_, link);
sector_reader_.offset(sector_reader_.offset() + document_.short_sector_size());
}
}
}
else
{
const auto sector_index = position_ / document_.sector_size();
document_.write_sector(sector_reader_, chain_[sector_index]);
}
position_ += written;
entry_.size = std::max(entry_.size, static_cast<std::uint32_t>(position_));
std::fill(current_sector_.begin(), current_sector_.end(), byte(0));
setp(reinterpret_cast<char *>(current_sector_.data()),
reinterpret_cast<char *>(current_sector_.data() + current_sector_.size()));
return 0;
}
bool short_stream()
{
return entry_.size < document_.header_.threshold;
}
sector_chain &table()
int_type overflow(int_type c = traits_type::eof())
{
return short_stream()
? document_.ssat_
: document_.sat_;
}
sync();
std::size_t sector_size()
{
return short_stream()
? document_.short_sector_size()
: document_.short_sector_size();
}
void write_sector()
{
if (short_stream())
{
auto next_sector = document_.allocate_short_sector();
document_.ssat_[chain_.back()] = next_sector;
chain_.push_back(next_sector);
document_.write_short_sector(sector_reader_, next_sector);
}
else
{
auto next_sector = document_.allocate_sector();
document_.sat_[chain_.back()] = next_sector;
chain_.push_back(next_sector);
document_.write_sector(sector_reader_, next_sector);
}
}
int_type overflow(int_type c = traits_type::eof())
{
auto value = static_cast<std::uint8_t>(c);
if (c != traits_type::eof())
{
current_sector_[position_ % sector_size()] = value;
current_sector_[position_ % current_sector_.size()] = value;
}
pbump(1);
if (entry_.start < 0)
{
entry_.start = entry_.size == document_.header_.threshold
? document_.allocate_sector()
: document_.allocate_short_sector();
chain_.push_back(entry_.start);
}
if (position_ % 64 == 0 && position_ > 0)
{
write_sector();
std::fill(current_sector_.begin(), current_sector_.end(), byte(0));
}
if (c != traits_type::eof())
{
++position_;
auto previous_size = entry_.size;
entry_.size = std::max(entry_.size, static_cast<std::uint32_t>(position_));
if (entry_.size >= document_.header_.threshold && previous_size < document_.header_.threshold)
{
convert_to_long_stream();
}
return traits_type::to_int_type(static_cast<char>(value));
}
else
{
return traits_type::eof();
}
return traits_type::to_int_type(static_cast<char>(value));
}
void convert_to_long_stream()
{
const auto sectors_per_sector = document_.sector_size() / document_.short_sector_size();
sector_reader_.reset();
current_sector_.resize(sector_size(), 0);
auto num_sectors = current_sector_.size() / document_.sector_size();
auto new_chain = document_.allocate_sectors(num_sectors);
for (auto link : new_chain)
{
document_.write_sector(sector_reader_, link);
sector_reader_.offset(sector_reader_.offset() + document_.short_sector_size());
}
current_sector_.resize(document_.sector_size(), 0);
std::fill(current_sector_.begin(), current_sector_.end(), byte(0));
auto sector_writer = binary_writer<byte>(current_sector_);
auto index = std::size_t(0);
auto long_chain = sector_chain();
entry_.start = document_.allocate_sector();
long_chain.push_back(entry_.start);
for (auto link : chain_)
{
document_.read_short_sector(link, sector_writer);
document_.header_.num_short_sectors--;
document_.ssat_[link] = FreeSector;
if (index % sectors_per_sector == 0 && index > 0)
{
document_.write_sector(sector_reader_, long_chain.back());
auto next_sector = document_.allocate_sector();
document_.sat_[long_chain.back()] = next_sector;
long_chain.push_back(next_sector);
}
}
if (index % sectors_per_sector != 0)
{
document_.write_sector(sector_reader_, long_chain.back());
}
index = 0;
auto previous = sector_id(0);
for (auto link : document_.follow_chain(document_.entries_[0].start, document_.sat_))
{
auto ssat_index_start = document_.ssat_.begin() + index * sectors_per_sector;
auto ssat_index_end = document_.ssat_.begin() + (index + 1) * sectors_per_sector;
if (std::size_t(std::count(ssat_index_start, ssat_index_end, FreeSector)) == sectors_per_sector)
{
if (index > 0)
{
document_.sat_[previous] = document_.sat_[link];
}
else
{
document_.entries_[0].start = document_.sat_[link];
}
document_.sat_[link] = FreeSector;
}
previous = link;
index++;
}
if (document_.header_.num_short_sectors == 0)
{
document_.entries_[0].start = EndOfChain;
@ -396,7 +357,8 @@ private:
// TODO: deallocate short sectors here
chain_ = long_chain;
chain_ = new_chain;
entry_.start = chain_.front();
}
std::streampos seekoff(std::streamoff off, std::ios_base::seekdir way, std::ios_base::openmode)
@ -465,6 +427,10 @@ private:
sector_chain chain_;
};
compound_document_ostreambuf::~compound_document_ostreambuf()
{
sync();
}
compound_document::compound_document(std::ostream &out)
: out_(&out),
@ -509,6 +475,11 @@ std::size_t compound_document::short_sector_size()
std::istream &compound_document::open_read_stream(const std::string &name)
{
if (!contains_entry(name, compound_document_entry::entry_type::UserStream))
{
throw xlnt::exception("not found");
}
const auto entry_id = find_entry(name, compound_document_entry::entry_type::UserStream);
const auto &entry = entries_.at(entry_id);
@ -662,6 +633,8 @@ sector_chain compound_document::allocate_sectors(std::size_t count)
sat_[current] = next;
current = next;
}
chain.push_back(current);
return chain;
}

View File

@ -145,14 +145,14 @@ encryption_info::standard_encryption_info read_standard_encryption_info(std::ist
throw xlnt::exception("invalid header");
}
const auto csp_name_length = header_length - (info_stream.tellg() - index_at_start);
auto csp_name = xlnt::detail::read_string<char16_t>(info_stream, csp_name_length);
if (csp_name != u"Microsoft Enhanced RSA and AES Cryptographic Provider (Prototype)"
&& csp_name != u"Microsoft Enhanced RSA and AES Cryptographic Provider")
const auto csp_name_length = (header_length - (info_stream.tellg() - index_at_start) - 1) / 2;
auto csp_name = xlnt::detail::utf16_to_utf8(xlnt::detail::read_string<char16_t>(info_stream, csp_name_length));
if (csp_name != "Microsoft Enhanced RSA and AES Cryptographic Provider (Prototype)"
&& csp_name != "Microsoft Enhanced RSA and AES Cryptographic Provider")
{
throw xlnt::exception("invalid cryptographic provider");
}
info_stream.seekg(csp_name_length);
//info_stream.seekg((csp_name_length + 1) * 2);
const auto salt_size = read<std::uint32_t>(info_stream);
result.salt = xlnt::detail::read_vector<byte>(info_stream, salt_size);
@ -312,12 +312,14 @@ std::vector<std::uint8_t> decrypt_xlsx(
std::istream stream(&buffer);
xlnt::detail::compound_document document(stream);
auto &encryption_info_stream = document.open_read_stream("EncryptionInfo");
auto &encryption_info_stream = document.open_read_stream("/EncryptionInfo");
auto encryption_info = read_encryption_info(encryption_info_stream, password);
auto &encrypted_package_stream = document.open_read_stream("/EncryptedPackage");
return encryption_info.is_agile
? decrypt_xlsx_agile(encryption_info, document.open_read_stream("EncryptedPackage"))
: decrypt_xlsx_standard(encryption_info, document.open_read_stream("EncryptedPackage"));
? decrypt_xlsx_agile(encryption_info, encrypted_package_stream)
: decrypt_xlsx_standard(encryption_info, encrypted_package_stream);
}
} // namespace

View File

@ -22,6 +22,7 @@
// @author: see AUTHORS file
#include <detail/serialization/vector_streambuf.hpp>
#include <xlnt/utils/exceptions.hpp>
namespace xlnt {
namespace detail {
@ -214,6 +215,11 @@ std::streampos vector_ostreambuf::seekpos(std::streampos sp, std::ios_base::open
XLNT_API std::vector<std::uint8_t> to_vector(std::istream &in_stream)
{
if (!in_stream)
{
throw xlnt::exception("bad stream");
}
return std::vector<std::uint8_t>(
std::istreambuf_iterator<char>(in_stream),
std::istreambuf_iterator<char>());
@ -221,6 +227,11 @@ XLNT_API std::vector<std::uint8_t> to_vector(std::istream &in_stream)
XLNT_API void to_stream(const std::vector<std::uint8_t> &bytes, std::ostream &out_stream)
{
if (!out_stream)
{
throw xlnt::exception("bad stream");
}
out_stream.write(reinterpret_cast<const char *>(bytes.data()), bytes.size());
}

View File

@ -73,27 +73,6 @@ void print_summary()
int main()
{
std::ifstream file("C:/Users/Thomas/Development/xlnt/tests/data/6_encrypted_libre.xlsx", std::ios::binary);
const auto bytes2 = xlnt::detail::to_vector(file);
xlnt::detail::vector_istreambuf buffer(bytes2);
std::istream buffer_stream(&buffer);
xlnt::detail::compound_document doc2(buffer_stream);
auto info = xlnt::detail::to_vector(doc2.open_read_stream("/EncryptionInfo"));
auto package = xlnt::detail::to_vector(doc2.open_read_stream("/EncryptedPackage"));
std::vector<std::uint8_t> bytes;
xlnt::detail::vector_ostreambuf byte_buffer(bytes);
std::ostream byte_buffer_stream(&byte_buffer);
xlnt::detail::compound_document doc(byte_buffer_stream);
auto &a_stream = doc.open_write_stream("/aaa");
xlnt::detail::to_stream(std::vector<std::uint8_t>(4095, 'a'), a_stream);
auto &b_stream = doc.open_write_stream("/bbb");
xlnt::detail::to_stream(std::vector<std::uint8_t>(4095, 'b'), b_stream);
auto &c_stream = doc.open_write_stream("/ccc");
xlnt::detail::to_stream(std::vector<std::uint8_t>(4095, 'c'), c_stream);
std::ofstream file2("cd.xlsx", std::ios::binary);
xlnt::detail::to_stream(bytes, file2);
// cell
run_tests<cell_test_suite>();
run_tests<index_types_test_suite>();