differential code coverage report with master
Current view: top level - source/detail/serialization - zstream.cpp (source / functions) Coverage Total Hit UBC CBC
Current: coverage.info Lines: 89.6 % 299 268 31 268
Current Date: 2025-12-07 02:01:22 Functions: 93.9 % 33 31 2 31
Baseline: coverage_master.info Branches: 64.8 % 261 169 184 338
Baseline Date: 2025-12-07 02:01:21

             Branch data    TLA  Line data    Source code
       1                 :                : /*
       2                 :                : PARTIO SOFTWARE
       3                 :                : Copyright 2010 Disney Enterprises, Inc. All rights reserved
       4                 :                : 
       5                 :                : Redistribution and use in source and binary forms, with or without
       6                 :                : modification, are permitted provided that the following conditions are
       7                 :                : met:
       8                 :                : 
       9                 :                : * Redistributions of source code must retain the above copyright
      10                 :                : notice, this list of conditions and the following disclaimer.
      11                 :                : 
      12                 :                : * Redistributions in binary form must reproduce the above copyright
      13                 :                : notice, this list of conditions and the following disclaimer in
      14                 :                : the documentation and/or other materials provided with the
      15                 :                : distribution.
      16                 :                : 
      17                 :                : * The names "Disney", "Walt Disney Pictures", "Walt Disney Animation
      18                 :                : Studios" or the names of its contributors may NOT be used to
      19                 :                : endorse or promote products derived from this software without
      20                 :                : specific prior written permission from Walt Disney Pictures.
      21                 :                : 
      22                 :                : Disclaimer: THIS SOFTWARE IS PROVIDED BY WALT DISNEY PICTURES AND
      23                 :                : CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
      24                 :                : BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
      25                 :                : FOR A PARTICULAR PURPOSE, NONINFRINGEMENT AND TITLE ARE DISCLAIMED.
      26                 :                : IN NO EVENT SHALL WALT DISNEY PICTURES, THE COPYRIGHT HOLDER OR
      27                 :                : CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
      28                 :                : EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
      29                 :                : PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
      30                 :                : PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND BASED ON ANY
      31                 :                : THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
      32                 :                : (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
      33                 :                : OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
      34                 :                : */
      35                 :                : 
      36                 :                : #include <algorithm>
      37                 :                : #include <array>
      38                 :                : #include <cassert>
      39                 :                : #include <cstring>
      40                 :                : #include <iostream>
      41                 :                : #include <iterator> // for std::back_inserter
      42                 :                : #include <string>
      43                 :                : #include <miniz.h>
      44                 :                : 
      45                 :                : #include <xlnt/utils/exceptions.hpp>
      46                 :                : #include <detail/serialization/vector_streambuf.hpp>
      47                 :                : #include <detail/serialization/zstream.hpp>
      48                 :                : 
      49                 :                : namespace {
      50                 :                : 
      51                 :                : template <class T>
      52                 :CBC       38783 : T read_int(std::istream &stream)
      53                 :                : {
      54                 :                :     T value;
      55            [ + ]:          38783 :     stream.read(reinterpret_cast<char *>(&value), sizeof(T));
      56                 :                : 
      57                 :          38783 :     return value;
      58                 :                : }
      59                 :                : 
      60                 :                : template <class T>
      61                 :          47395 : void write_int(std::ostream &stream, T value)
      62                 :                : {
      63                 :          47395 :     stream.write(reinterpret_cast<char *>(&value), sizeof(T));
      64                 :          47395 : }
      65                 :                : 
      66                 :           2712 : xlnt::detail::zheader read_header(std::istream &istream, const bool global)
      67                 :                : {
      68                 :           2712 :     xlnt::detail::zheader header;
      69                 :                : 
      70            [ + ]:           2712 :     auto sig = read_int<std::uint32_t>(istream);
      71                 :                : 
      72                 :                :     // read and check for local/global magic
      73         [ +  + ]:           2712 :     if (global)
      74                 :                :     {
      75         [ -  + ]:           1353 :         if (sig != 0x02014b50)
      76                 :                :         {
      77         [ #  # ]:UBC           0 :             throw xlnt::exception("missing global header signature");
      78                 :                :         }
      79                 :                : 
      80            [ + ]:CBC        1353 :         header.version = read_int<std::uint16_t>(istream);
      81                 :                :     }
      82         [ -  + ]:           1359 :     else if (sig != 0x04034b50)
      83                 :                :     {
      84         [ #  # ]:UBC           0 :         throw xlnt::exception("missing local header signature");
      85                 :                :     }
      86                 :                : 
      87                 :                :     // Read rest of header
      88            [ + ]:CBC        2712 :     header.version = read_int<std::uint16_t>(istream);
      89            [ + ]:           2712 :     header.flags = read_int<std::uint16_t>(istream);
      90            [ + ]:           2712 :     header.compression_type = read_int<std::uint16_t>(istream);
      91            [ + ]:           2712 :     header.stamp_date = read_int<std::uint16_t>(istream);
      92            [ + ]:           2712 :     header.stamp_time = read_int<std::uint16_t>(istream);
      93            [ + ]:           2712 :     header.crc = read_int<std::uint32_t>(istream);
      94            [ + ]:           2712 :     header.compressed_size = read_int<std::uint32_t>(istream);
      95            [ + ]:           2712 :     header.uncompressed_size = read_int<std::uint32_t>(istream);
      96                 :                : 
      97            [ + ]:           2712 :     auto filename_length = read_int<std::uint16_t>(istream);
      98            [ + ]:           2712 :     auto extra_length = read_int<std::uint16_t>(istream);
      99                 :                : 
     100                 :           2712 :     std::uint16_t comment_length = 0;
     101                 :                : 
     102         [ +  + ]:           2712 :     if (global)
     103                 :                :     {
     104            [ + ]:           1353 :         comment_length = read_int<std::uint16_t>(istream);
     105            [ + ]:           1353 :         /*std::uint16_t disk_number_start = */ read_int<std::uint16_t>(istream);
     106            [ + ]:           1353 :         /*std::uint16_t int_file_attrib = */ read_int<std::uint16_t>(istream);
     107            [ + ]:           1353 :         /*std::uint32_t ext_file_attrib = */ read_int<std::uint32_t>(istream);
     108            [ + ]:           1353 :         header.header_offset = read_int<std::uint32_t>(istream);
     109                 :                :     }
     110                 :                : 
     111            [ + ]:           2712 :     header.filename.resize(filename_length, '\0');
     112            [ + ]:           2712 :     istream.read(&header.filename[0], filename_length);
     113                 :                : 
     114            [ + ]:           2712 :     header.extra.resize(extra_length, 0);
     115            [ + ]:           2712 :     istream.read(reinterpret_cast<char *>(header.extra.data()), extra_length);
     116                 :                : 
     117         [ +  + ]:           2712 :     if (global)
     118                 :                :     {
     119            [ + ]:           1353 :         header.comment.resize(comment_length, '\0');
     120            [ + ]:           1353 :         istream.read(&header.comment[0], comment_length);
     121                 :                :     }
     122                 :                : 
     123                 :           2712 :     return header;
     124                 :UBC           0 : }
     125                 :                : 
     126                 :CBC        1473 : void write_header(const xlnt::detail::zheader &header, std::ostream &ostream, const bool global)
     127                 :                : {
     128         [ +  + ]:           1473 :     if (global)
     129                 :                :     {
     130                 :            491 :         write_int(ostream, static_cast<std::uint32_t>(0x02014b50)); // header sig
     131                 :            491 :         write_int(ostream, static_cast<std::uint16_t>(20)); // version made by
     132                 :                :     }
     133                 :                :     else
     134                 :                :     {
     135                 :            982 :         write_int(ostream, static_cast<std::uint32_t>(0x04034b50));
     136                 :                :     }
     137                 :                : 
     138                 :           1473 :     write_int(ostream, header.version);
     139                 :           1473 :     write_int(ostream, header.flags);
     140                 :           1473 :     write_int(ostream, header.compression_type);
     141                 :           1473 :     write_int(ostream, header.stamp_date);
     142                 :           1473 :     write_int(ostream, header.stamp_time);
     143                 :           1473 :     write_int(ostream, header.crc);
     144                 :           1473 :     write_int(ostream, header.compressed_size);
     145                 :           1473 :     write_int(ostream, header.uncompressed_size);
     146                 :           1473 :     write_int(ostream, static_cast<std::uint16_t>(header.filename.length()));
     147                 :           1473 :     write_int(ostream, static_cast<std::uint16_t>(0)); // extra lengthx
     148                 :                : 
     149         [ +  + ]:           1473 :     if (global)
     150                 :                :     {
     151                 :            491 :         write_int(ostream, static_cast<std::uint16_t>(0)); // filecomment
     152                 :            491 :         write_int(ostream, static_cast<std::uint16_t>(0)); // disk# start
     153                 :            491 :         write_int(ostream, static_cast<std::uint16_t>(0)); // internal file
     154                 :            491 :         write_int(ostream, static_cast<std::uint32_t>(0)); // ext final
     155                 :            491 :         write_int(ostream, static_cast<std::uint32_t>(header.header_offset)); // rel offset
     156                 :                :     }
     157                 :                : 
     158         [ +  + ]:          29367 :     for (auto c : header.filename)
     159                 :                :     {
     160            [ + ]:          27894 :         write_int(ostream, c);
     161                 :                :     }
     162                 :           1473 : }
     163                 :                : 
     164                 :                : } // namespace
     165                 :                : 
     166                 :                : namespace xlnt {
     167                 :                : namespace detail {
     168                 :                : 
     169                 :                : static const std::size_t buffer_size = 512;
     170                 :                : 
     171                 :                : class zip_streambuf_decompress : public std::streambuf
     172                 :                : {
     173                 :                :     std::istream &istream;
     174                 :                : 
     175                 :                :     z_stream strm;
     176                 :                :     std::array<char, buffer_size> in;
     177                 :                :     std::array<char, buffer_size> out;
     178                 :                :     zheader header;
     179                 :                :     std::size_t total_read;
     180                 :                :     std::size_t total_uncompressed;
     181                 :                :     bool valid;
     182                 :                :     bool compressed_data;
     183                 :                : 
     184                 :                :     static const unsigned short DEFLATE = 8;
     185                 :                :     static const unsigned short UNCOMPRESSED = 0;
     186                 :                : 
     187                 :                : public:
     188                 :           1359 :     zip_streambuf_decompress(std::istream &stream, zheader central_header)
     189            [ + ]:           1359 :         : istream(stream), header(central_header), total_read(0), total_uncompressed(0), valid(true)
     190                 :                :     {
     191            [ + ]:           1359 :         in.fill(0);
     192            [ + ]:           1359 :         out.fill(0);
     193                 :                : 
     194                 :           1359 :         strm.zalloc = nullptr;
     195                 :           1359 :         strm.zfree = nullptr;
     196                 :           1359 :         strm.opaque = nullptr;
     197                 :           1359 :         strm.avail_in = 0;
     198                 :           1359 :         strm.next_in = nullptr;
     199                 :                : 
     200                 :           5436 :         setg(in.data(), in.data(), in.data());
     201                 :           1359 :         setp(nullptr, nullptr);
     202                 :                : 
     203                 :                :         // skip the header
     204            [ + ]:           1359 :         read_header(istream, false);
     205                 :                : 
     206         [ +  + ]:           1359 :         if (header.compression_type == DEFLATE)
     207                 :                :         {
     208                 :           1322 :             compressed_data = true;
     209                 :                :         }
     210         [ +  - ]:             37 :         else if (header.compression_type == UNCOMPRESSED)
     211                 :                :         {
     212                 :             37 :             compressed_data = false;
     213                 :                :         }
     214                 :                :         else
     215                 :                :         {
     216                 :UBC           0 :             compressed_data = false;
     217         [ #  # ]:              0 :             throw xlnt::exception("unsupported compression type, should be DEFLATE or uncompressed");
     218                 :                :         }
     219                 :                : 
     220                 :                :         // initialize the inflate
     221   [ +  +  +  - ]:CBC        1359 :         if (compressed_data && valid)
     222                 :                :         {
     223                 :                : #pragma clang diagnostic push
     224                 :                : #pragma clang diagnostic ignored "-Wold-style-cast"
     225            [ + ]:           1322 :             int result = inflateInit2(&strm, -MAX_WBITS);
     226                 :                : #pragma clang diagnostic pop
     227                 :                : 
     228         [ -  + ]:           1322 :             if (result != Z_OK)
     229                 :                :             {
     230         [ #  # ]:UBC           0 :                 throw xlnt::exception("couldn't inflate ZIP, possibly corrupted");
     231                 :                :             }
     232                 :                :         }
     233                 :                : 
     234            [ + ]:CBC        1359 :         header = central_header;
     235                 :           1359 :     }
     236                 :                : 
     237                 :           2718 :     ~zip_streambuf_decompress() override
     238                 :           1359 :     {
     239   [ +  +  +  - ]:           1359 :         if (compressed_data && valid)
     240                 :                :         {
     241                 :           1322 :             inflateEnd(&strm);
     242                 :                :         }
     243                 :           2718 :     }
     244                 :                : 
     245                 :           9190 :     int process()
     246                 :                :     {
     247         [ -  + ]:           9190 :         if (!valid) return -1;
     248                 :                : 
     249         [ +  + ]:           9190 :         if (compressed_data)
     250                 :                :         {
     251                 :           8357 :             strm.avail_out = buffer_size - 4;
     252                 :           8357 :             strm.next_out = reinterpret_cast<Bytef *>(out.data() + 4);
     253                 :                : 
     254         [ +  + ]:          17392 :             while (strm.avail_out != 0)
     255                 :                :             {
     256         [ +  + ]:          11425 :                 if (strm.avail_in == 0)
     257                 :                :                 {
     258                 :                :                     // buffer empty, read some more from file
     259            [ + ]:           6741 :                     istream.read(in.data(),
     260                 :           6741 :                         static_cast<std::streamsize>(std::min(buffer_size, header.compressed_size - total_read)));
     261                 :           6741 :                     strm.avail_in = static_cast<unsigned int>(istream.gcount());
     262                 :           6741 :                     total_read += strm.avail_in;
     263                 :          13482 :                     strm.next_in = reinterpret_cast<Bytef *>(in.data());
     264                 :                :                 }
     265                 :                : 
     266                 :          11425 :                 const auto ret = inflate(&strm, Z_NO_FLUSH); // decompress
     267                 :                : 
     268   [ +  -  +  -  :          11425 :                 if (ret == Z_STREAM_ERROR || ret == Z_NEED_DICT || ret == Z_DATA_ERROR || ret == Z_MEM_ERROR)
             +  -  -  + ]
     269                 :                :                 {
     270         [ #  # ]:UBC           0 :                     throw xlnt::exception("couldn't inflate ZIP, possibly corrupted");
     271                 :                :                 }
     272                 :                : 
     273         [ +  + ]:CBC       11425 :                 if (ret == Z_STREAM_END) break;
     274                 :                :             }
     275                 :                : 
     276                 :           8357 :             auto unzip_count = buffer_size - strm.avail_out - 4;
     277                 :           8357 :             total_uncompressed += unzip_count;
     278                 :           8357 :             return static_cast<int>(unzip_count);
     279                 :                :         }
     280                 :                : 
     281                 :                :         // uncompressed, so just read
     282            [ + ]:            833 :         istream.read(out.data() + 4,
     283                 :            833 :             static_cast<std::streamsize>(std::min(buffer_size - 4, header.uncompressed_size - total_read)));
     284                 :            833 :         auto count = istream.gcount();
     285                 :            833 :         total_read += static_cast<std::size_t>(count);
     286                 :            833 :         return static_cast<int>(count);
     287                 :                :     }
     288                 :                : 
     289                 :           9190 :     virtual int underflow() override
     290                 :                :     {
     291   [ +  -  -  +  :           9190 :         if (gptr() && (gptr() < egptr()))
                   -  + ]
     292                 :UBC           0 :             return traits_type::to_int_type(*gptr()); // if we already have data just use it
     293                 :CBC        9190 :         auto put_back_count = gptr() - eback();
     294         [ +  + ]:           9190 :         if (put_back_count > 4) put_back_count = 4;
     295                 :          18380 :         std::memmove(
     296                 :           9190 :             out.data() + (4 - put_back_count), gptr() - put_back_count, static_cast<std::size_t>(put_back_count));
     297                 :           9190 :         int num = process();
     298                 :          36760 :         setg(out.data() + 4 - put_back_count, out.data() + 4, out.data() + 4 + num);
     299         [ +  + ]:           9190 :         if (num <= 0) return EOF;
     300                 :           7974 :         return traits_type::to_int_type(*gptr());
     301                 :                :     }
     302                 :                : 
     303                 :                :     virtual int overflow(int c = EOF) override;
     304                 :                : };
     305                 :                : 
     306                 :UBC           0 : int zip_streambuf_decompress::overflow(int)
     307                 :                : {
     308         [ #  # ]:              0 :     throw xlnt::exception("writing to read-only buffer");
     309                 :                : }
     310                 :                : 
     311                 :                : class zip_streambuf_compress : public std::streambuf
     312                 :                : {
     313                 :                :     std::ostream &ostream; // owned when header==0 (when not part of zip file)
     314                 :                : 
     315                 :                :     z_stream strm;
     316                 :                :     std::array<char, buffer_size> in;
     317                 :                :     std::array<char, buffer_size> out;
     318                 :                : 
     319                 :                :     zheader *header;
     320                 :                :     std::uint32_t uncompressed_size;
     321                 :                :     std::uint32_t crc;
     322                 :                : 
     323                 :                :     bool valid;
     324                 :                : 
     325                 :                : public:
     326                 :CBC         491 :     zip_streambuf_compress(zheader *central_header, std::ostream &stream)
     327                 :            491 :         : ostream(stream), header(central_header), valid(true)
     328                 :                :     {
     329                 :            491 :         strm.zalloc = nullptr;
     330                 :            491 :         strm.zfree = nullptr;
     331                 :            491 :         strm.opaque = nullptr;
     332                 :                : 
     333                 :                : #pragma clang diagnostic push
     334                 :                : #pragma clang diagnostic ignored "-Wold-style-cast"
     335            [ + ]:            491 :         int ret = deflateInit2(&strm, Z_DEFAULT_COMPRESSION, Z_DEFLATED, -MAX_WBITS, 8, Z_DEFAULT_STRATEGY);
     336                 :                : #pragma clang diagnostic pop
     337                 :                : 
     338         [ -  + ]:            491 :         if (ret != Z_OK)
     339                 :                :         {
     340         [ #  # ]:UBC           0 :             std::cerr << "libz: failed to deflateInit" << std::endl;
     341                 :              0 :             valid = false;
     342                 :              0 :             return;
     343                 :                :         }
     344                 :                : 
     345                 :CBC         491 :         setg(nullptr, nullptr, nullptr);
     346                 :           1473 :         setp(in.data(), in.data() + buffer_size - 4); // we want to be 4 aligned
     347                 :                : 
     348                 :                :         // Write appropriate header
     349         [ +  - ]:            491 :         if (header)
     350                 :                :         {
     351            [ + ]:            491 :             header->header_offset = static_cast<std::uint32_t>(stream.tellp());
     352            [ + ]:            491 :             write_header(*header, ostream, false);
     353                 :                :         }
     354                 :                : 
     355                 :            491 :         uncompressed_size = crc = 0;
     356                 :UBC           0 :     }
     357                 :                : 
     358                 :CBC         982 :     virtual ~zip_streambuf_compress() override
     359                 :            491 :     {
     360         [ +  - ]:            491 :         if (valid)
     361                 :                :         {
     362                 :            491 :             process(true);
     363                 :            491 :             deflateEnd(&strm);
     364         [ +  - ]:            491 :             if (header)
     365                 :                :             {
     366                 :            491 :                 auto final_position = ostream.tellp();
     367                 :            491 :                 header->uncompressed_size = uncompressed_size;
     368                 :            491 :                 header->crc = crc;
     369                 :            491 :                 ostream.seekp(header->header_offset);
     370                 :            491 :                 write_header(*header, ostream, false);
     371                 :            491 :                 ostream.seekp(final_position);
     372                 :                :             }
     373                 :                :             else
     374                 :                :             {
     375                 :UBC           0 :                 write_int(ostream, crc);
     376                 :              0 :                 write_int(ostream, uncompressed_size);
     377                 :                :             }
     378                 :                :         }
     379   [ -  +  -  - ]:CBC         491 :         if (!header) delete &ostream;
     380                 :            982 :     }
     381                 :                : 
     382                 :                : protected:
     383                 :           4446 :     int process(bool flush)
     384                 :                :     {
     385         [ -  + ]:           4446 :         if (!valid) return -1;
     386                 :                : 
     387                 :           4446 :         strm.next_in = reinterpret_cast<Bytef *>(pbase());
     388                 :           4446 :         strm.avail_in = static_cast<unsigned int>(pptr() - pbase());
     389                 :                : 
     390   [ +  +  +  + ]:          10149 :         while (strm.avail_in != 0 || flush)
     391                 :                :         {
     392                 :           6194 :             strm.avail_out = buffer_size;
     393                 :           6194 :             strm.next_out = reinterpret_cast<Bytef *>(out.data());
     394                 :                : 
     395         [ +  + ]:           6194 :             int ret = deflate(&strm, flush ? Z_FINISH : Z_NO_FLUSH);
     396                 :                : 
     397   [ +  -  -  + ]:           6194 :             if (!(ret != Z_BUF_ERROR && ret != Z_STREAM_ERROR))
     398                 :                :             {
     399                 :UBC           0 :                 valid = false;
     400                 :              0 :                 std::cerr << "gzip: gzip error " << strm.msg << std::endl;
     401                 :              0 :                 return -1;
     402                 :                :             }
     403                 :                : 
     404                 :CBC        6194 :             auto generated_output = static_cast<int>(strm.next_out - reinterpret_cast<std::uint8_t *>(out.data()));
     405                 :          12388 :             ostream.write(out.data(), generated_output);
     406         [ +  - ]:           6194 :             if (header) header->compressed_size += static_cast<std::uint32_t>(generated_output);
     407         [ +  + ]:           6194 :             if (ret == Z_STREAM_END) break;
     408                 :                :         }
     409                 :                : 
     410                 :                :         // update counts, crc's and buffers
     411                 :           4446 :         auto consumed_input = static_cast<std::uint32_t>(pptr() - pbase());
     412                 :           4446 :         uncompressed_size += consumed_input;
     413                 :           8892 :         crc = static_cast<std::uint32_t>(crc32(crc, reinterpret_cast<Bytef *>(in.data()), consumed_input));
     414                 :           4446 :         setp(pbase(), pbase() + buffer_size - 4);
     415                 :                : 
     416                 :           4446 :         return 1;
     417                 :                :     }
     418                 :                : 
     419                 :            457 :     virtual int sync() override
     420                 :                :     {
     421   [ +  -  +  -  :            457 :         if (pptr() && pptr() > pbase()) return process(false);
                   +  - ]
     422                 :UBC           0 :         return 0;
     423                 :                :     }
     424                 :                : 
     425                 :              0 :     virtual int underflow() override
     426                 :                :     {
     427         [ #  # ]:              0 :         throw xlnt::exception("Attempt to read write only ostream");
     428                 :                :     }
     429                 :                : 
     430                 :                :     virtual int overflow(int c = EOF) override;
     431                 :                : };
     432                 :                : 
     433                 :CBC        3498 : int zip_streambuf_compress::overflow(int c)
     434                 :                : {
     435         [ +  - ]:           3498 :     if (c != EOF)
     436                 :                :     {
     437                 :           3498 :         *pptr() = static_cast<char>(c);
     438                 :           3498 :         pbump(1);
     439                 :                :     }
     440         [ -  + ]:           3498 :     if (process(false) == EOF) return EOF;
     441                 :           3498 :     return c;
     442                 :                : }
     443                 :                : 
     444                 :             44 : ozstream::ozstream(std::ostream &stream)
     445                 :             44 :     : destination_stream_(stream)
     446                 :                : {
     447      [ +  -  + ]:             44 :     if (!destination_stream_)
     448                 :                :     {
     449         [ #  # ]:UBC           0 :         throw xlnt::exception("bad zip stream");
     450                 :                :     }
     451                 :CBC          44 : }
     452                 :                : 
     453                 :             88 : ozstream::~ozstream()
     454                 :                : {
     455                 :                :     // Write all file headers
     456                 :             44 :     auto final_position = destination_stream_.tellp();
     457                 :                : 
     458         [ +  + ]:            535 :     for (const auto &header : file_headers_)
     459                 :                :     {
     460                 :            491 :         write_header(header, destination_stream_, true);
     461                 :                :     }
     462                 :                : 
     463                 :             44 :     auto central_end = destination_stream_.tellp();
     464                 :                : 
     465                 :                :     // Write end of central
     466                 :             44 :     write_int(destination_stream_, static_cast<std::uint32_t>(0x06054b50)); // end of central
     467                 :             44 :     write_int(destination_stream_, static_cast<std::uint16_t>(0)); // this disk number
     468                 :             44 :     write_int(destination_stream_, static_cast<std::uint16_t>(0)); // this disk number
     469                 :             44 :     write_int(destination_stream_, static_cast<std::uint16_t>(file_headers_.size())); // one entry in center in this disk
     470                 :             44 :     write_int(destination_stream_, static_cast<std::uint16_t>(file_headers_.size())); // one entry in center
     471                 :             44 :     write_int(destination_stream_, static_cast<std::uint32_t>(central_end - final_position)); // size of header
     472                 :             44 :     write_int(destination_stream_, static_cast<std::uint32_t>(final_position)); // offset to header
     473                 :             44 :     write_int(destination_stream_, static_cast<std::uint16_t>(0)); // zip comment
     474                 :             88 : }
     475                 :                : 
     476                 :            491 : std::unique_ptr<std::streambuf> ozstream::open(const path &filename)
     477                 :                : {
     478                 :            491 :     zheader header;
     479         [ +  + ]:            491 :     header.filename = filename.string();
     480            [ + ]:            491 :     file_headers_.push_back(header);
     481   [ +  +  -  - ]:            491 :     auto buffer = new zip_streambuf_compress(&file_headers_.back(), destination_stream_);
     482                 :                : 
     483                 :            982 :     return std::unique_ptr<zip_streambuf_compress>(buffer);
     484                 :            491 : }
     485                 :                : 
     486                 :            119 : izstream::izstream(std::istream &stream)
     487                 :            119 :     : source_stream_(stream)
     488                 :                : {
     489      [ +  -  + ]:            119 :     if (!stream)
     490                 :                :     {
     491         [ #  # ]:UBC           0 :         throw xlnt::exception("Invalid file handle");
     492                 :                :     }
     493                 :                : 
     494            [ + ]:CBC         119 :     read_central_header();
     495                 :            119 : }
     496                 :                : 
     497                 :            216 : izstream::~izstream()
     498                 :                : {
     499                 :            216 : }
     500                 :                : 
     501                 :            119 : bool izstream::read_central_header()
     502                 :                : {
     503                 :                :     // Find the header
     504                 :                :     // NOTE: this assumes the zip file header is the last thing written to file...
     505            [ + ]:            119 :     source_stream_.seekg(0, std::ios_base::end);
     506            [ + ]:            119 :     auto end_position = source_stream_.tellg();
     507                 :                : 
     508                 :            119 :     auto max_comment_size = std::uint32_t(0xffff); // max size of header
     509                 :            119 :     auto read_size_before_comment = std::uint32_t(22);
     510                 :                : 
     511                 :            119 :     std::streamoff read_start = max_comment_size + read_size_before_comment;
     512                 :                : 
     513         [ +  + ]:            119 :     if (read_start > end_position)
     514                 :                :     {
     515                 :            117 :         read_start = end_position;
     516                 :                :     }
     517                 :                : 
     518         [ +  + ]:            119 :     source_stream_.seekg(end_position - read_start);
     519            [ + ]:            119 :     std::vector<std::uint8_t> buf(static_cast<std::size_t>(read_start), '\0');
     520                 :                : 
     521         [ -  + ]:            119 :     if (read_start <= 0)
     522                 :                :     {
     523         [ #  # ]:UBC           0 :         throw xlnt::exception("file is empty");
     524                 :                :     }
     525                 :                : 
     526            [ + ]:CBC         119 :     source_stream_.read(reinterpret_cast<char *>(buf.data()), read_start);
     527                 :                : 
     528   [ -  -  -  -  :            119 :     if (buf[0] == 0xd0 && buf[1] == 0xcf && buf[2] == 0x11 && buf[3] == 0xe0
                   -  - ]
     529   [ -  +  -  -  :            119 :         && buf[4] == 0xa1 && buf[5] == 0xb1 && buf[6] == 0x1a && buf[7] == 0xe1)
          -  -  -  -  -  
                -  -  + ]
     530                 :                :     {
     531         [ #  # ]:UBC           0 :         throw xlnt::exception("encrypted xlsx, password required");
     532                 :                :     }
     533                 :                : 
     534                 :CBC         119 :     auto found_header = false;
     535                 :            119 :     std::streamoff header_index = 0;
     536                 :                : 
     537         [ +  - ]:        1816341 :     for (std::streamoff i = 0; i < read_start - 3; ++i)
     538                 :                :     {
     539                 :        1816341 :         if (buf[static_cast<std::size_t>(i)] == 0x50
     540         [ +  + ]:           9476 :             && buf[static_cast<std::size_t>(i) + 1] == 0x4b
     541         [ +  + ]:           2867 :             && buf[static_cast<std::size_t>(i) + 2] == 0x05
     542   [ +  +  +  -  :        1825817 :             && buf[static_cast<std::size_t>(i) + 3] == 0x06)
                   +  + ]
     543                 :                :         {
     544                 :            119 :             found_header = true;
     545                 :            119 :             header_index = i;
     546                 :            119 :             break;
     547                 :                :         }
     548                 :                :     }
     549                 :                : 
     550         [ -  + ]:            119 :     if (!found_header)
     551                 :                :     {
     552         [ #  # ]:UBC           0 :         throw xlnt::exception("failed to find zip header");
     553                 :                :     }
     554                 :                : 
     555                 :                :     // seek to end of central header and read
     556         [ +  + ]:CBC         119 :     source_stream_.seekg(end_position - (read_start - header_index));
     557                 :                : 
     558            [ + ]:            119 :     /*auto word = */ read_int<std::uint32_t>(source_stream_);
     559            [ + ]:            119 :     auto disk_number1 = read_int<std::uint16_t>(source_stream_);
     560            [ + ]:            119 :     auto disk_number2 = read_int<std::uint16_t>(source_stream_);
     561                 :                : 
     562   [ +  -  -  + ]:            119 :     if (disk_number1 != disk_number2 || disk_number1 != 0)
     563                 :                :     {
     564         [ #  # ]:UBC           0 :         throw xlnt::exception("multiple disk zip files are not supported");
     565                 :                :     }
     566                 :                : 
     567            [ + ]:CBC         119 :     auto num_files = read_int<std::uint16_t>(source_stream_); // one entry in center in this disk
     568            [ + ]:            119 :     auto num_files_this_disk = read_int<std::uint16_t>(source_stream_); // one entry in center
     569                 :                : 
     570         [ -  + ]:            119 :     if (num_files != num_files_this_disk)
     571                 :                :     {
     572         [ #  # ]:UBC           0 :         throw xlnt::exception("multi disk zip files are not supported");
     573                 :                :     }
     574                 :                : 
     575            [ + ]:CBC         119 :     /*auto size_of_header = */ read_int<std::uint32_t>(source_stream_); // size of header
     576            [ + ]:            119 :     auto header_offset = read_int<std::uint32_t>(source_stream_); // offset to header
     577                 :                : 
     578                 :                :     // go to header and read all file headers
     579            [ + ]:            119 :     source_stream_.seekg(header_offset);
     580                 :                : 
     581         [ +  + ]:           1472 :     for (std::uint16_t i = 0; i < num_files; ++i)
     582                 :                :     {
     583            [ + ]:           1353 :         auto header = read_header(source_stream_, true);
     584         [ +  + ]:           1353 :         file_headers_[header.filename] = header;
     585                 :           1353 :     }
     586                 :                : 
     587                 :            119 :     return true;
     588                 :            119 : }
     589                 :                : 
     590                 :           1359 : std::unique_ptr<std::streambuf> izstream::open(const path &filename) const
     591                 :                : {
     592      [ +  -  + ]:           1359 :     if (!has_file(filename))
     593                 :                :     {
     594         [ #  # ]:UBC           0 :         throw xlnt::exception("file not found");
     595                 :                :     }
     596                 :                : 
     597      [ +  +  + ]:CBC        1359 :     auto header = file_headers_.at(filename.string());
     598            [ + ]:           1359 :     source_stream_.seekg(header.header_offset);
     599   [ +  +  +  -  :           1359 :     auto buffer = new zip_streambuf_decompress(source_stream_, header);
                      - ]
     600                 :                : 
     601                 :           2718 :     return std::unique_ptr<zip_streambuf_decompress>(buffer);
     602                 :           1359 : }
     603                 :                : 
     604                 :            256 : std::string izstream::read(const path &filename) const
     605                 :                : {
     606            [ + ]:            256 :     auto buffer = open(filename);
     607            [ + ]:            256 :     std::istream stream(buffer.get());
     608            [ + ]:            256 :     auto bytes = to_vector(stream);
     609                 :                : 
     610            [ + ]:            512 :     return std::string(bytes.begin(), bytes.end());
     611                 :            256 : }
     612                 :                : 
     613                 :            119 : std::vector<path> izstream::files() const
     614                 :                : {
     615                 :            119 :     std::vector<path> filenames;
     616         [ +  + ]:            119 :     std::transform(file_headers_.begin(), file_headers_.end(), std::back_inserter(filenames),
     617                 :           1353 :         [](const std::pair<std::string, zheader> &h) { return path(h.first); });
     618                 :                : 
     619                 :            119 :     return filenames;
     620                 :UBC           0 : }
     621                 :                : 
     622                 :CBC        2681 : bool izstream::has_file(const path &filename) const
     623                 :                : {
     624                 :           2681 :     return file_headers_.count(filename.string()) != 0;
     625                 :                : }
     626                 :                : 
     627                 :                : } // namespace detail
     628                 :                : } // namespace xlnt
        

Generated by: LCOV version 2.3.1-beta