/* POLE - Portable C++ library to access OLE Storage Copyright (C) 2002-2007 Ariya Hidayat (ariya@kde.org). Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #pragma once #include #include #include #include #include namespace xlnt { namespace detail { using directory_id = std::int32_t; using sector_id = std::int32_t; using sector_chain = std::vector; struct compound_document_header { enum class byte_order_type : uint16_t { big_endian = 0xFFFE, little_endian = 0xFEFF }; std::uint64_t file_id = 0xe11ab1a1e011cfd0; std::array ignore1 = { { 0 } }; std::uint16_t revision = 0x003E; std::uint16_t version = 0x0003; byte_order_type byte_order = byte_order_type::little_endian; std::uint16_t sector_size_power = 9; std::uint16_t short_sector_size_power = 6; std::array ignore2 = { { 0 } }; std::uint32_t num_msat_sectors = 0; sector_id directory_start = -1; std::array ignore3 = { { 0 } }; std::uint32_t threshold = 4096; sector_id short_table_start = -1; std::uint32_t num_short_sectors = 0; sector_id extra_msat_start = -2; std::uint32_t num_extra_msat_sectors = 0; std::array msat = { 0 }; }; struct compound_document_entry { void name(const std::u16string &new_name) { name_length = std::min(static_cast(new_name.size()), std::uint16_t(31)); std::copy(new_name.begin(), new_name.begin() + name_length, name_array.begin()); name_array[name_length] = 0; name_length = (name_length + 1) * 2; } std::u16string name() const { return std::u16string(name_array.begin(), name_array.begin() + (name_length - 1) / 2); } enum class entry_type : std::uint8_t { Empty = 0, UserStorage = 1, UserStream = 2, LockBytes = 3, Property = 4, RootStorage = 5 }; enum class entry_color : std::uint8_t { Red = 0, Black = 1 }; std::array name_array = { { 0 } }; std::uint16_t name_length = 0; entry_type type = entry_type::Empty; entry_color color = entry_color::Red; directory_id prev = -1; directory_id next = -1; directory_id child = -1; std::array ignore; sector_id start = -1; std::uint32_t size = 0; std::uint32_t ignore2; }; class compound_document { public: compound_document(std::vector &data); compound_document(const std::vector &data); ~compound_document(); std::vector read_stream(const std::u16string &filename); void write_stream(const std::u16string &filename, const std::vector &data); private: std::size_t sector_size(); std::size_t short_sector_size(); std::size_t sector_data_start(); bool contains_entry(const std::u16string &path); compound_document_entry &find_entry(const std::u16string &path); std::vector read(sector_id start); std::vector read_short(sector_id start); void read_msat(); void read_sat(); void read_ssat(); void read_header(); void read_directory_tree(); void write(const std::vector &data, sector_id start); void write_short(const std::vector &data, sector_id start); void write_msat(); void write_sat(); void write_ssat(); void write_header(); void write_directory_tree(); sector_id allocate_sectors(std::size_t sectors); compound_document_entry &insert_entry(const std::u16string &path, compound_document_entry::entry_type type); std::unique_ptr reader_; std::unique_ptr writer_; compound_document_header header_; sector_chain msat_; sector_chain sat_; sector_chain ssat_; std::vector entries_; }; } // namespace detail } // namespace xlnt