• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

xlnt-community / xlnt / 3c28f24b-a03d-431f-9f91-e227e62092fd

26 Apr 2025 07:52PM UTC coverage: 81.886% (-0.4%) from 82.27%
3c28f24b-a03d-431f-9f91-e227e62092fd

Pull #79

circleci

m7913d
Removed run count argument again (as it is not used anymore)
Pull Request #79: Publishing coverage to github pages

14026 of 18604 branches covered (75.39%)

1 of 1 new or added line in 1 file covered. (100.0%)

58 existing lines in 6 files now uncovered.

11500 of 14044 relevant lines covered (81.89%)

10385.36 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

89.63
./source/detail/serialization/zstream.cpp
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
T read_int(std::istream &stream)
37,068✔
53
{
54
    T value;
55
    stream.read(reinterpret_cast<char *>(&value), sizeof(T));
37,068✔
56

57
    return value;
37,068✔
58
}
59

60
template <class T>
61
void write_int(std::ostream &stream, T value)
45,501✔
62
{
63
    stream.write(reinterpret_cast<char *>(&value), sizeof(T));
45,501✔
64
}
45,501✔
65

66
xlnt::detail::zheader read_header(std::istream &istream, const bool global)
2,593✔
67
{
68
    xlnt::detail::zheader header;
2,593✔
69

70
    auto sig = read_int<std::uint32_t>(istream);
2,593✔
71

72
    // read and check for local/global magic
73
    if (global)
2,593✔
74
    {
75
        if (sig != 0x02014b50)
1,290!
76
        {
77
            throw xlnt::exception("missing global header signature");
×
78
        }
79

80
        header.version = read_int<std::uint16_t>(istream);
1,290✔
81
    }
82
    else if (sig != 0x04034b50)
1,303!
83
    {
84
        throw xlnt::exception("missing local header signature");
×
85
    }
86

87
    // Read rest of header
88
    header.version = read_int<std::uint16_t>(istream);
2,593✔
89
    header.flags = read_int<std::uint16_t>(istream);
2,593✔
90
    header.compression_type = read_int<std::uint16_t>(istream);
2,593✔
91
    header.stamp_date = read_int<std::uint16_t>(istream);
2,593✔
92
    header.stamp_time = read_int<std::uint16_t>(istream);
2,593✔
93
    header.crc = read_int<std::uint32_t>(istream);
2,593✔
94
    header.compressed_size = read_int<std::uint32_t>(istream);
2,593✔
95
    header.uncompressed_size = read_int<std::uint32_t>(istream);
2,593✔
96

97
    auto filename_length = read_int<std::uint16_t>(istream);
2,593✔
98
    auto extra_length = read_int<std::uint16_t>(istream);
2,593✔
99

100
    std::uint16_t comment_length = 0;
2,593✔
101

102
    if (global)
2,593✔
103
    {
104
        comment_length = read_int<std::uint16_t>(istream);
1,290✔
105
        /*std::uint16_t disk_number_start = */ read_int<std::uint16_t>(istream);
1,290✔
106
        /*std::uint16_t int_file_attrib = */ read_int<std::uint16_t>(istream);
1,290✔
107
        /*std::uint32_t ext_file_attrib = */ read_int<std::uint32_t>(istream);
1,290✔
108
        header.header_offset = read_int<std::uint32_t>(istream);
1,290✔
109
    }
110

111
    header.filename.resize(filename_length, '\0');
2,593✔
112
    istream.read(&header.filename[0], filename_length);
2,593✔
113

114
    header.extra.resize(extra_length, 0);
2,593✔
115
    istream.read(reinterpret_cast<char *>(header.extra.data()), extra_length);
2,593✔
116

117
    if (global)
2,593✔
118
    {
119
        header.comment.resize(comment_length, '\0');
1,290✔
120
        istream.read(&header.comment[0], comment_length);
1,290✔
121
    }
122

123
    return header;
2,593✔
124
}
×
125

126
void write_header(const xlnt::detail::zheader &header, std::ostream &ostream, const bool global)
1,413✔
127
{
128
    if (global)
1,413✔
129
    {
130
        write_int(ostream, static_cast<std::uint32_t>(0x02014b50)); // header sig
471✔
131
        write_int(ostream, static_cast<std::uint16_t>(20)); // version made by
471✔
132
    }
133
    else
134
    {
135
        write_int(ostream, static_cast<std::uint32_t>(0x04034b50));
942✔
136
    }
137

138
    write_int(ostream, header.version);
1,413✔
139
    write_int(ostream, header.flags);
1,413✔
140
    write_int(ostream, header.compression_type);
1,413✔
141
    write_int(ostream, header.stamp_date);
1,413✔
142
    write_int(ostream, header.stamp_time);
1,413✔
143
    write_int(ostream, header.crc);
1,413✔
144
    write_int(ostream, header.compressed_size);
1,413✔
145
    write_int(ostream, header.uncompressed_size);
1,413✔
146
    write_int(ostream, static_cast<std::uint16_t>(header.filename.length()));
1,413✔
147
    write_int(ostream, static_cast<std::uint16_t>(0)); // extra lengthx
1,413✔
148

149
    if (global)
1,413✔
150
    {
151
        write_int(ostream, static_cast<std::uint16_t>(0)); // filecomment
471✔
152
        write_int(ostream, static_cast<std::uint16_t>(0)); // disk# start
471✔
153
        write_int(ostream, static_cast<std::uint16_t>(0)); // internal file
471✔
154
        write_int(ostream, static_cast<std::uint32_t>(0)); // ext final
471✔
155
        write_int(ostream, static_cast<std::uint32_t>(header.header_offset)); // rel offset
471✔
156
    }
157

158
    for (auto c : header.filename)
28,209✔
159
    {
160
        write_int(ostream, c);
26,796✔
161
    }
162
}
1,413✔
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
    zip_streambuf_decompress(std::istream &stream, zheader central_header)
1,303✔
189
        : istream(stream), header(central_header), total_read(0), total_uncompressed(0), valid(true)
1,303✔
190
    {
191
        in.fill(0);
1,303✔
192
        out.fill(0);
1,303✔
193

194
        strm.zalloc = nullptr;
1,303✔
195
        strm.zfree = nullptr;
1,303✔
196
        strm.opaque = nullptr;
1,303✔
197
        strm.avail_in = 0;
1,303✔
198
        strm.next_in = nullptr;
1,303✔
199

200
        setg(in.data(), in.data(), in.data());
5,212✔
201
        setp(nullptr, nullptr);
1,303✔
202

203
        // skip the header
204
        read_header(istream, false);
1,303✔
205

206
        if (header.compression_type == DEFLATE)
1,303✔
207
        {
208
            compressed_data = true;
1,266✔
209
        }
210
        else if (header.compression_type == UNCOMPRESSED)
37!
211
        {
212
            compressed_data = false;
37✔
213
        }
214
        else
215
        {
216
            compressed_data = false;
×
217
            throw xlnt::exception("unsupported compression type, should be DEFLATE or uncompressed");
×
218
        }
219

220
        // initialize the inflate
221
        if (compressed_data && valid)
1,303!
222
        {
223
#pragma clang diagnostic push
224
#pragma clang diagnostic ignored "-Wold-style-cast"
225
            int result = inflateInit2(&strm, -MAX_WBITS);
1,266✔
226
#pragma clang diagnostic pop
227

228
            if (result != Z_OK)
1,266!
229
            {
230
                throw xlnt::exception("couldn't inflate ZIP, possibly corrupted");
×
231
            }
232
        }
233

234
        header = central_header;
1,303✔
235
    }
1,303✔
236

237
    ~zip_streambuf_decompress() override
2,606✔
238
    {
1,303✔
239
        if (compressed_data && valid)
1,303!
240
        {
241
            inflateEnd(&strm);
1,266✔
242
        }
243
    }
2,606✔
244

245
    int process()
8,812✔
246
    {
247
        if (!valid) return -1;
8,812!
248

249
        if (compressed_data)
8,812✔
250
        {
251
            strm.avail_out = buffer_size - 4;
7,979✔
252
            strm.next_out = reinterpret_cast<Bytef *>(out.data() + 4);
7,979✔
253

254
            while (strm.avail_out != 0)
16,681✔
255
            {
256
                if (strm.avail_in == 0)
10,996✔
257
                {
258
                    // buffer empty, read some more from file
259
                    istream.read(in.data(),
6,524✔
260
                        static_cast<std::streamsize>(std::min(buffer_size, header.compressed_size - total_read)));
6,524✔
261
                    strm.avail_in = static_cast<unsigned int>(istream.gcount());
6,524✔
262
                    total_read += strm.avail_in;
6,524✔
263
                    strm.next_in = reinterpret_cast<Bytef *>(in.data());
13,048✔
264
                }
265

266
                const auto ret = inflate(&strm, Z_NO_FLUSH); // decompress
10,996✔
267

268
                if (ret == Z_STREAM_ERROR || ret == Z_NEED_DICT || ret == Z_DATA_ERROR || ret == Z_MEM_ERROR)
10,996!
269
                {
270
                    throw xlnt::exception("couldn't inflate ZIP, possibly corrupted");
×
271
                }
272

273
                if (ret == Z_STREAM_END) break;
10,996✔
274
            }
275

276
            auto unzip_count = buffer_size - strm.avail_out - 4;
7,979✔
277
            total_uncompressed += unzip_count;
7,979✔
278
            return static_cast<int>(unzip_count);
7,979✔
279
        }
280

281
        // uncompressed, so just read
282
        istream.read(out.data() + 4,
833✔
283
            static_cast<std::streamsize>(std::min(buffer_size - 4, header.uncompressed_size - total_read)));
833✔
284
        auto count = istream.gcount();
833✔
285
        total_read += static_cast<std::size_t>(count);
833✔
286
        return static_cast<int>(count);
833✔
287
    }
288

289
    virtual int underflow() override
8,812✔
290
    {
291
        if (gptr() && (gptr() < egptr()))
8,812!
292
            return traits_type::to_int_type(*gptr()); // if we already have data just use it
×
293
        auto put_back_count = gptr() - eback();
8,812✔
294
        if (put_back_count > 4) put_back_count = 4;
8,812✔
295
        std::memmove(
17,624✔
296
            out.data() + (4 - put_back_count), gptr() - put_back_count, static_cast<std::size_t>(put_back_count));
8,812✔
297
        int num = process();
8,812✔
298
        setg(out.data() + 4 - put_back_count, out.data() + 4, out.data() + 4 + num);
35,248✔
299
        if (num <= 0) return EOF;
8,812✔
300
        return traits_type::to_int_type(*gptr());
7,644✔
301
    }
302

303
    virtual int overflow(int c = EOF) override;
304
};
305

306
int zip_streambuf_decompress::overflow(int)
×
307
{
308
    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
    zip_streambuf_compress(zheader *central_header, std::ostream &stream)
471✔
327
        : ostream(stream), header(central_header), valid(true)
471✔
328
    {
329
        strm.zalloc = nullptr;
471✔
330
        strm.zfree = nullptr;
471✔
331
        strm.opaque = nullptr;
471✔
332

333
#pragma clang diagnostic push
334
#pragma clang diagnostic ignored "-Wold-style-cast"
335
        int ret = deflateInit2(&strm, Z_DEFAULT_COMPRESSION, Z_DEFLATED, -MAX_WBITS, 8, Z_DEFAULT_STRATEGY);
471✔
336
#pragma clang diagnostic pop
337

338
        if (ret != Z_OK)
471!
339
        {
340
            std::cerr << "libz: failed to deflateInit" << std::endl;
×
341
            valid = false;
×
342
            return;
×
343
        }
344

345
        setg(nullptr, nullptr, nullptr);
471✔
346
        setp(in.data(), in.data() + buffer_size - 4); // we want to be 4 aligned
1,413✔
347

348
        // Write appropriate header
349
        if (header)
471!
350
        {
351
            header->header_offset = static_cast<std::uint32_t>(stream.tellp());
471✔
352
            write_header(*header, ostream, false);
471✔
353
        }
354

355
        uncompressed_size = crc = 0;
471✔
356
    }
×
357

358
    virtual ~zip_streambuf_compress() override
942✔
359
    {
471✔
360
        if (valid)
471!
361
        {
362
            process(true);
471✔
363
            deflateEnd(&strm);
471✔
364
            if (header)
471!
365
            {
366
                auto final_position = ostream.tellp();
471✔
367
                header->uncompressed_size = uncompressed_size;
471✔
368
                header->crc = crc;
471✔
369
                ostream.seekp(header->header_offset);
471✔
370
                write_header(*header, ostream, false);
471✔
371
                ostream.seekp(final_position);
471✔
372
            }
373
            else
374
            {
375
                write_int(ostream, crc);
×
376
                write_int(ostream, uncompressed_size);
×
377
            }
378
        }
379
        if (!header) delete &ostream;
471!
380
    }
942✔
381

382
protected:
383
    int process(bool flush)
4,314✔
384
    {
385
        if (!valid) return -1;
4,314!
386

387
        strm.next_in = reinterpret_cast<Bytef *>(pbase());
4,314✔
388
        strm.avail_in = static_cast<unsigned int>(pptr() - pbase());
4,314✔
389

390
        while (strm.avail_in != 0 || flush)
9,873✔
391
        {
392
            strm.avail_out = buffer_size;
6,030✔
393
            strm.next_out = reinterpret_cast<Bytef *>(out.data());
6,030✔
394

395
            int ret = deflate(&strm, flush ? Z_FINISH : Z_NO_FLUSH);
6,030✔
396

397
            if (!(ret != Z_BUF_ERROR && ret != Z_STREAM_ERROR))
6,030!
398
            {
399
                valid = false;
×
400
                std::cerr << "gzip: gzip error " << strm.msg << std::endl;
×
401
                return -1;
×
402
            }
403

404
            auto generated_output = static_cast<int>(strm.next_out - reinterpret_cast<std::uint8_t *>(out.data()));
6,030✔
405
            ostream.write(out.data(), generated_output);
12,060✔
406
            if (header) header->compressed_size += static_cast<std::uint32_t>(generated_output);
6,030!
407
            if (ret == Z_STREAM_END) break;
6,030✔
408
        }
409

410
        // update counts, crc's and buffers
411
        auto consumed_input = static_cast<std::uint32_t>(pptr() - pbase());
4,314✔
412
        uncompressed_size += consumed_input;
4,314✔
413
        crc = static_cast<std::uint32_t>(crc32(crc, reinterpret_cast<Bytef *>(in.data()), consumed_input));
8,628✔
414
        setp(pbase(), pbase() + buffer_size - 4);
4,314✔
415

416
        return 1;
4,314✔
417
    }
418

419
    virtual int sync() override
439✔
420
    {
421
        if (pptr() && pptr() > pbase()) return process(false);
439!
UNCOV
422
        return 0;
×
423
    }
424

425
    virtual int underflow() override
×
426
    {
427
        throw xlnt::exception("Attempt to read write only ostream");
×
428
    }
429

430
    virtual int overflow(int c = EOF) override;
431
};
432

433
int zip_streambuf_compress::overflow(int c)
3,404✔
434
{
435
    if (c != EOF)
3,404!
436
    {
437
        *pptr() = static_cast<char>(c);
3,404✔
438
        pbump(1);
3,404✔
439
    }
440
    if (process(false) == EOF) return EOF;
3,404!
441
    return c;
3,404✔
442
}
443

444
ozstream::ozstream(std::ostream &stream)
42✔
445
    : destination_stream_(stream)
42✔
446
{
447
    if (!destination_stream_)
42!
448
    {
449
        throw xlnt::exception("bad zip stream");
×
450
    }
451
}
42✔
452

453
ozstream::~ozstream()
84✔
454
{
455
    // Write all file headers
456
    auto final_position = destination_stream_.tellp();
42✔
457

458
    for (const auto &header : file_headers_)
513✔
459
    {
460
        write_header(header, destination_stream_, true);
471✔
461
    }
462

463
    auto central_end = destination_stream_.tellp();
42✔
464

465
    // Write end of central
466
    write_int(destination_stream_, static_cast<std::uint32_t>(0x06054b50)); // end of central
42✔
467
    write_int(destination_stream_, static_cast<std::uint16_t>(0)); // this disk number
42✔
468
    write_int(destination_stream_, static_cast<std::uint16_t>(0)); // this disk number
42✔
469
    write_int(destination_stream_, static_cast<std::uint16_t>(file_headers_.size())); // one entry in center in this disk
42✔
470
    write_int(destination_stream_, static_cast<std::uint16_t>(file_headers_.size())); // one entry in center
42✔
471
    write_int(destination_stream_, static_cast<std::uint32_t>(central_end - final_position)); // size of header
42✔
472
    write_int(destination_stream_, static_cast<std::uint32_t>(final_position)); // offset to header
42✔
473
    write_int(destination_stream_, static_cast<std::uint16_t>(0)); // zip comment
42✔
474
}
84✔
475

476
std::unique_ptr<std::streambuf> ozstream::open(const path &filename)
471✔
477
{
478
    zheader header;
471✔
479
    header.filename = filename.string();
471✔
480
    file_headers_.push_back(header);
471✔
481
    auto buffer = new zip_streambuf_compress(&file_headers_.back(), destination_stream_);
471!
482

483
    return std::unique_ptr<zip_streambuf_compress>(buffer);
942✔
484
}
471✔
485

486
izstream::izstream(std::istream &stream)
115✔
487
    : source_stream_(stream)
115✔
488
{
489
    if (!stream)
115!
490
    {
491
        throw xlnt::exception("Invalid file handle");
×
492
    }
493

494
    read_central_header();
115✔
495
}
115✔
496

497
izstream::~izstream()
208✔
498
{
499
}
208✔
500

501
bool izstream::read_central_header()
115✔
502
{
503
    // Find the header
504
    // NOTE: this assumes the zip file header is the last thing written to file...
505
    source_stream_.seekg(0, std::ios_base::end);
115✔
506
    auto end_position = source_stream_.tellg();
115✔
507

508
    auto max_comment_size = std::uint32_t(0xffff); // max size of header
115✔
509
    auto read_size_before_comment = std::uint32_t(22);
115✔
510

511
    std::streamoff read_start = max_comment_size + read_size_before_comment;
115✔
512

513
    if (read_start > end_position)
115✔
514
    {
515
        read_start = end_position;
113✔
516
    }
517

518
    source_stream_.seekg(end_position - read_start);
115✔
519
    std::vector<std::uint8_t> buf(static_cast<std::size_t>(read_start), '\0');
115✔
520

521
    if (read_start <= 0)
115!
522
    {
523
        throw xlnt::exception("file is empty");
×
524
    }
525

526
    source_stream_.read(reinterpret_cast<char *>(buf.data()), read_start);
115✔
527

528
    if (buf[0] == 0xd0 && buf[1] == 0xcf && buf[2] == 0x11 && buf[3] == 0xe0
115!
529
        && buf[4] == 0xa1 && buf[5] == 0xb1 && buf[6] == 0x1a && buf[7] == 0xe1)
115!
530
    {
531
        throw xlnt::exception("encrypted xlsx, password required");
×
532
    }
533

534
    auto found_header = false;
115✔
535
    std::streamoff header_index = 0;
115✔
536

537
    for (std::streamoff i = 0; i < read_start - 3; ++i)
1,760,595!
538
    {
539
        if (buf[static_cast<std::size_t>(i)] == 0x50
1,760,595✔
540
            && buf[static_cast<std::size_t>(i) + 1] == 0x4b
9,091✔
541
            && buf[static_cast<std::size_t>(i) + 2] == 0x05
2,712✔
542
            && buf[static_cast<std::size_t>(i) + 3] == 0x06)
1,769,686!
543
        {
544
            found_header = true;
115✔
545
            header_index = i;
115✔
546
            break;
115✔
547
        }
548
    }
549

550
    if (!found_header)
115!
551
    {
552
        throw xlnt::exception("failed to find zip header");
×
553
    }
554

555
    // seek to end of central header and read
556
    source_stream_.seekg(end_position - (read_start - header_index));
115✔
557

558
    /*auto word = */ read_int<std::uint32_t>(source_stream_);
115✔
559
    auto disk_number1 = read_int<std::uint16_t>(source_stream_);
115✔
560
    auto disk_number2 = read_int<std::uint16_t>(source_stream_);
115✔
561

562
    if (disk_number1 != disk_number2 || disk_number1 != 0)
115!
563
    {
564
        throw xlnt::exception("multiple disk zip files are not supported");
×
565
    }
566

567
    auto num_files = read_int<std::uint16_t>(source_stream_); // one entry in center in this disk
115✔
568
    auto num_files_this_disk = read_int<std::uint16_t>(source_stream_); // one entry in center
115✔
569

570
    if (num_files != num_files_this_disk)
115!
571
    {
572
        throw xlnt::exception("multi disk zip files are not supported");
×
573
    }
574

575
    /*auto size_of_header = */ read_int<std::uint32_t>(source_stream_); // size of header
115✔
576
    auto header_offset = read_int<std::uint32_t>(source_stream_); // offset to header
115✔
577

578
    // go to header and read all file headers
579
    source_stream_.seekg(header_offset);
115✔
580

581
    for (std::uint16_t i = 0; i < num_files; ++i)
1,405✔
582
    {
583
        auto header = read_header(source_stream_, true);
1,290✔
584
        file_headers_[header.filename] = header;
1,290✔
585
    }
1,290✔
586

587
    return true;
115✔
588
}
115✔
589

590
std::unique_ptr<std::streambuf> izstream::open(const path &filename) const
1,303✔
591
{
592
    if (!has_file(filename))
1,303!
593
    {
594
        throw xlnt::exception("file not found");
×
595
    }
596

597
    auto header = file_headers_.at(filename.string());
1,303✔
598
    source_stream_.seekg(header.header_offset);
1,303✔
599
    auto buffer = new zip_streambuf_decompress(source_stream_, header);
1,303!
600

601
    return std::unique_ptr<zip_streambuf_decompress>(buffer);
2,606✔
602
}
1,303✔
603

604
std::string izstream::read(const path &filename) const
256✔
605
{
606
    auto buffer = open(filename);
256✔
607
    std::istream stream(buffer.get());
256✔
608
    auto bytes = to_vector(stream);
256✔
609

610
    return std::string(bytes.begin(), bytes.end());
512✔
611
}
256✔
612

613
std::vector<path> izstream::files() const
115✔
614
{
615
    std::vector<path> filenames;
115✔
616
    std::transform(file_headers_.begin(), file_headers_.end(), std::back_inserter(filenames),
115✔
617
        [](const std::pair<std::string, zheader> &h) { return path(h.first); });
1,290✔
618

619
    return filenames;
115✔
620
}
×
621

622
bool izstream::has_file(const path &filename) const
2,558✔
623
{
624
    return file_headers_.count(filename.string()) != 0;
2,558✔
625
}
626

627
} // namespace detail
628
} // namespace xlnt
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc