/* PARTIO SOFTWARE Copyright 2010 Disney Enterprises, Inc. All rights reserved Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * The names "Disney", "Walt Disney Pictures", "Walt Disney Animation Studios" or the names of its contributors may NOT be used to endorse or promote products derived from this software without specific prior written permission from Walt Disney Pictures. Disclaimer: THIS SOFTWARE IS PROVIDED BY WALT DISNEY PICTURES AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT AND TITLE ARE DISCLAIMED. IN NO EVENT SHALL WALT DISNEY PICTURES, THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND BASED ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. */ #include #include #include #include #include #include #include #include extern C { #include } #include namespace xlnt { namespace detail { template inline T read_int(std::istream &stream) { T value; stream.read(reinterpret_cast(&value), sizeof(T)); return value; } template inline void write_int(std::ostream &stream, T value) { stream.write(reinterpret_cast(&value), sizeof(T)); } struct zip_file_header { std::uint16_t version = 20; std::uint16_t flags = 0; std::uint16_t compression_type = 8; std::uint16_t stamp_date,stamp_time = 0; std::uint32_t crc = 0; std::uint32_t compressed_size = 0; std::uint32_t uncompressed_size = 0; std::string filename; std::string comment; std::vector extra; std::uint32_t header_offset = 0; // local header offset zip_file_header() { } bool read(std::istream& istream,const bool global) { auto sig = read_int(istream); // read and check for local/global magic if(global) { if(sig!=0x02014b50) { std::cerr<<"Did not find global header signature"<(istream); } else if(sig!=0x04034b50) { std::cerr<<"Did not find local header signature"<(istream); flags = read_int(istream); compression_type = read_int(istream); stamp_date = read_int(istream); stamp_time = read_int(istream); crc = read_int(istream); compressed_size = read_int(istream); uncompressed_size = read_int(istream); auto filename_length = read_int(istream); auto extra_length = read_int(istream); std::uint16_t comment_length = 0; if(global) { comment_length = read_int(istream); /*std::uint16_t disk_number_start = */read_int(istream); /*std::uint16_t int_file_attrib = */read_int(istream); /*std::uint32_t ext_file_attrib = */read_int(istream); header_offset = read_int(istream); } filename.resize(filename_length, '\0'); istream.read(&filename[0], filename_length); extra.resize(extra_length, 0); istream.read(reinterpret_cast(extra.data()), extra_length); if (global) { comment.resize(comment_length, '\0'); istream.read(&comment[0], comment_length); } return true; } void Write(std::ostream& ostream,const bool global) const {if(global){ write_int(ostream,(unsigned int)0x02014b50); // header sig write_int(ostream,(unsigned short)00);} // version made by else write_int(ostream,(unsigned int)0x04034b50); write_int(ostream,version); write_int(ostream,flags); write_int(ostream,compression_type); write_int(ostream,stamp_date); write_int(ostream,stamp_time); write_int(ostream,crc); write_int(ostream,compressed_size); write_int(ostream,uncompressed_size); write_int(ostream,(unsigned short)filename.length()); write_int(ostream,(unsigned short)0); // extra lengthx if(global){ write_int(ostream,(unsigned short)0); // filecomment write_int(ostream,(unsigned short)0); // disk# start write_int(ostream,(unsigned short)0); // internal file write_int(ostream,(unsigned int)0); // ext final write_int(ostream,(unsigned int)header_offset);} // rel offset for(unsigned int i=0;i4) put_back_count=4; std::memmove(out+(4-put_back_count),gptr()-put_back_count,put_back_count); int num=process(); setg((char*)(out+4-put_back_count),(char*)(out+4),(char*)(out+4+num)); if(num<=0) return EOF; return traits_type::to_int_type(*gptr());} virtual int overflow(int c=EOF) {assert(false);return EOF;} }; class ZipStreambufCompress:public std::streambuf { static const int buffer_size=512; std::ostream& ostream; // owned when header==0 (when not part of zip file) z_stream strm; unsigned char in[buffer_size],out[buffer_size]; zip_file_header* header; unsigned int uncompressed_size; unsigned int crc; bool valid; public: ZipStreambufCompress(zip_file_header* central_header,std::ostream& stream) :ostream(stream),header(central_header),valid(true) { strm.zalloc=Z_NULL;strm.zfree=Z_NULL;strm.opaque=Z_NULL; int ret=deflateInit2(&strm,Z_DEFAULT_COMPRESSION,Z_DEFLATED,-MAX_WBITS,8,Z_DEFAULT_STRATEGY); if(ret != Z_OK){std::cerr<<"libz: failed to deflateInit"<header_offset=stream.tellp();header->Write(ostream,false);} uncompressed_size=crc=0; } virtual ~ZipStreambufCompress() {if(valid){ process(true); deflateEnd(&strm); if(header){ std::ios::streampos final_position=ostream.tellp(); header->uncompressed_size=uncompressed_size; header->crc=crc; ostream.seekp(header->header_offset); header->Write(ostream,false); ostream.seekp(final_position);} else{write_int(ostream,crc);write_int(ostream,uncompressed_size);}} if(!header) delete &ostream;} protected: int process(bool flush) {if(!valid) return -1; strm.next_in=(Bytef*)pbase(); strm.avail_in=pptr()-pbase(); while(strm.avail_in!=0 || flush){ strm.avail_out=buffer_size; strm.next_out=(Bytef*)out; int ret=deflate(&strm,flush?Z_FINISH:Z_NO_FLUSH); if(!(ret!=Z_BUF_ERROR && ret!=Z_STREAM_ERROR)){ valid=false; std::cerr<<"gzip: gzip error "<compressed_size+=generated_output; if(ret==Z_STREAM_END) break;} // update counts, crc's and buffers int consumed_input=pptr()-pbase(); uncompressed_size+=consumed_input; crc=crc32(crc,(Bytef*)in,consumed_input); setp(pbase(),pbase()+buffer_size-4);return 1;} virtual int sync() {if(pptr() && pptr()>pbase()) return process(false);return 0;} virtual int underflow() {std::runtime_error("Attempt to read write only ostream");return 0;} virtual int overflow(int c=EOF) {if(c!=EOF){*pptr()=c;pbump(1);} if(process(false)==EOF) return EOF; return c;} }; class ZIP_FILE_ISTREAM:public std::istream { ZipStreambufDecompress buf; public: ZIP_FILE_ISTREAM(std::istream& istream,zip_file_header header) :std::istream(&buf),buf(istream,header) { } virtual ~ZIP_FILE_ISTREAM() { } }; class ZIP_FILE_OSTREAM:public std::ostream { ZipStreambufCompress buf; public: ZIP_FILE_OSTREAM(zip_file_header* header,std::ostream& ostream) :std::ostream(&buf),buf(header,ostream) { } virtual ~ZIP_FILE_OSTREAM() { } }; ZipFileWriter::ZipFileWriter(std::ostream& stream) : target_stream_(stream) { if(!target_stream_) throw std::runtime_error("ZIP: Invalid file handle"); } ZipFileWriter::~ZipFileWriter() { // Write all file headers std::ios::streampos final_position=target_stream_.tellp(); for(unsigned int i=0;iend_position) read_start=end_position; source_stream_.seekg(end_position-read_start); std::vector buf(static_cast(read_start), '\0'); if(read_start<=0){std::cerr<<"ZIP: Invalid read buffer size"<(header_index))); /*auto word = */read_int(source_stream_); auto disk_number1 = read_int(source_stream_); auto disk_number2 = read_int(source_stream_); if(disk_number1 != disk_number2 || disk_number1 != 0) { std::cerr<<"ZIP: multiple disk zip files are not supported"<(source_stream_); // one entry in center in this disk auto num_files_this_disk = read_int(source_stream_); // one entry in center if(num_files != num_files_this_disk) { std::cerr<<"ZIP: multi disk zip files are not supported"<(source_stream_); // size of header auto header_offset = read_int(source_stream_); // offset to header // go to header and read all file headers source_stream_.seekg(header_offset); for (std::uint16_t i = 0; i < num_files; ++i) { zip_file_header header; if (header.read(source_stream_, true)) { file_headers_[header.filename] = header; } } return true; } std::istream &ZipFileReader::open(const std::string &filename) { if (!has_file(filename)) { throw "not found"; } auto header = file_headers_.at(filename); source_stream_.seekg(header.header_offset); read_stream_.reset(new ZIP_FILE_ISTREAM(source_stream_, header)); return *read_stream_; } std::vector ZipFileReader::files() const { std::vector filenames; std::transform(file_headers_.begin(), file_headers_.end(), std::back_inserter(filenames), [](const std::pair &h) { return h.first; }); return filenames; } bool ZipFileReader::has_file(const std::string &filename) const { return file_headers_.count(filename) != 0; } } // namespace detail } // namespace xlnt