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
|