zip_manager.cpp 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631
  1. // SOURCE: https://github.com/wdas/partio/blob/main/src/lib/io/ZIP.cpp
  2. /*
  3. PARTIO SOFTWARE
  4. Copyright 2010 Disney Enterprises, Inc. All rights reserved
  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. * Redistributions of source code must retain the above copyright
  9. notice, this list of conditions and the following disclaimer.
  10. * Redistributions in binary form must reproduce the above copyright
  11. notice, this list of conditions and the following disclaimer in
  12. the documentation and/or other materials provided with the
  13. distribution.
  14. * The names "Disney", "Walt Disney Pictures", "Walt Disney Animation
  15. Studios" or the names of its contributors may NOT be used to
  16. endorse or promote products derived from this software without
  17. specific prior written permission from Walt Disney Pictures.
  18. Disclaimer: THIS SOFTWARE IS PROVIDED BY WALT DISNEY PICTURES AND
  19. CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
  20. BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
  21. FOR A PARTICULAR PURPOSE, NONINFRINGEMENT AND TITLE ARE DISCLAIMED.
  22. IN NO EVENT SHALL WALT DISNEY PICTURES, THE COPYRIGHT HOLDER OR
  23. CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  24. EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  25. PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  26. PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND BASED ON ANY
  27. THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  28. (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  29. OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
  30. */
  31. extern "C"{
  32. #include <zlib.h>
  33. }
  34. #include <algorithm>
  35. #include <cassert>
  36. #include <fstream>
  37. #include <iomanip>
  38. #include <iostream>
  39. #include <stdexcept>
  40. #include <cstring>
  41. #include <string>
  42. #include "zip_manager.hpp"
  43. namespace Partio{
  44. template<class T>
  45. inline void Swap_Endianity(T& x)
  46. {
  47. assert(sizeof(T)<=8);
  48. if(sizeof(T)>1) {
  49. T old=x;
  50. for(unsigned int k=1;k<=sizeof(T);k++) ((char*)&x)[k-1]=((char*)&old)[sizeof(T)-k];
  51. }
  52. }
  53. template<class T>
  54. inline void Read_Primitive(std::istream& stream,T& x)
  55. {
  56. stream.read(&(char&)x,sizeof(T));
  57. }
  58. template<class T>
  59. inline void Write_Primitive(std::ostream& stream,const T& x)
  60. {
  61. stream.write(&(char&)x,sizeof(T));
  62. }
  63. //#####################################################################
  64. // class GZipFileHeader
  65. //#####################################################################
  66. struct GZipFileHeader
  67. {
  68. unsigned char magic0,magic1; // magic should be 0x8b,0x1f
  69. unsigned char cm; // compression method 0x8 is gzip
  70. unsigned char flags; // flags
  71. unsigned int modtime; // 4 byte modification time
  72. unsigned char flags2; // secondary flags
  73. unsigned char os; // operating system 0xff for unknown
  74. unsigned short crc16; // crc check
  75. unsigned int crc32;
  76. GZipFileHeader()
  77. :magic0(0),magic1(0),flags(0),modtime(0),flags2(0),os(0),crc16(0),crc32(0)
  78. {}
  79. bool Read(std::istream& istream)
  80. {Read_Primitive(istream,magic0);
  81. if (istream.eof() || istream.fail() || istream.bad()) {
  82. std::cerr << "Bad file attempting to read header" << std::endl;
  83. return false;
  84. }
  85. Read_Primitive(istream,magic1);
  86. if(magic0 != 0x1f || magic1 != 0x8b){//std::cerr<<"gzip: did not find gzip magic 0x1f 0x8b"<<std::endl;
  87. return false;}
  88. Read_Primitive(istream,cm);
  89. if(cm!=8){std::cerr<<"gzip: compression method not 0x8"<<std::endl;return false;}
  90. Read_Primitive(istream,flags);
  91. Read_Primitive(istream,modtime);
  92. Read_Primitive(istream,flags2);
  93. Read_Primitive(istream,os);
  94. unsigned char dummyByte;
  95. // read flags if necessary
  96. if(flags&2){
  97. unsigned short flgExtraLen;
  98. Read_Primitive(istream,flgExtraLen);
  99. for(int k=0;k<flgExtraLen;k++) Read_Primitive(istream,dummyByte);}
  100. // read filename/comment if present
  101. int stringsToRead=((flags&8)?1:0) + ((flags&4)?1:0);
  102. for(int i=0;i<stringsToRead;i++)
  103. do{Read_Primitive(istream,dummyByte);}while(dummyByte!=0 && istream);
  104. if(flags&1) Read_Primitive(istream,crc16);
  105. if(!istream) {std::cerr<<"gzip: got to end of file after only reading gzip header"<<std::endl;return false;}
  106. return true;}
  107. void Write(std::ostream& ostream)
  108. {magic0=0x1f;magic1=0x8b;cm=8;flags=0;os=0xff;
  109. Write_Primitive(ostream,magic0);Write_Primitive(ostream,magic1);
  110. Write_Primitive(ostream,cm);
  111. Write_Primitive(ostream,flags);
  112. Write_Primitive(ostream,modtime);
  113. Write_Primitive(ostream,flags2);
  114. Write_Primitive(ostream,os);}
  115. //#####################################################################
  116. };
  117. //#####################################################################
  118. // class ZipFileHeader
  119. //#####################################################################
  120. struct ZipFileHeader
  121. {
  122. unsigned short version;
  123. unsigned short flags;
  124. unsigned short compression_type;
  125. unsigned short stamp_date,stamp_time;
  126. unsigned int crc;
  127. unsigned int compressed_size,uncompressed_size;
  128. std::string filename;
  129. unsigned int header_offset; // local header offset
  130. ZipFileHeader()
  131. {}
  132. ZipFileHeader(const std::string& filename_input)
  133. :version(20),flags(0),compression_type(8),stamp_date(0),stamp_time(0),crc(0),
  134. compressed_size(0),uncompressed_size(0),filename(filename_input),header_offset(0)
  135. {}
  136. bool Read(std::istream& istream,const bool global)
  137. {unsigned int sig;
  138. unsigned short version,flags;
  139. // read and check for local/global magic
  140. if(global){
  141. Read_Primitive(istream,sig);
  142. if(sig!=0x02014b50){std::cerr<<"Did not find global header signature"<<std::endl;return false;}
  143. Read_Primitive(istream,version);}
  144. else{
  145. Read_Primitive(istream,sig);
  146. if(sig!=0x04034b50){std::cerr<<"Did not find local header signature"<<std::endl;return false;}}
  147. // Read rest of header
  148. Read_Primitive(istream,version);
  149. Read_Primitive(istream,flags);
  150. Read_Primitive(istream,compression_type);
  151. Read_Primitive(istream,stamp_date);
  152. Read_Primitive(istream,stamp_time);
  153. Read_Primitive(istream,crc);
  154. Read_Primitive(istream,compressed_size);
  155. Read_Primitive(istream,uncompressed_size);
  156. unsigned short filename_length,extra_length;
  157. Read_Primitive(istream,filename_length);
  158. Read_Primitive(istream,extra_length);
  159. unsigned short comment_length=0;
  160. if(global){
  161. Read_Primitive(istream,comment_length); // filecomment
  162. unsigned short disk_number_start,int_file_attrib;
  163. unsigned int ext_file_attrib;
  164. Read_Primitive(istream,disk_number_start); // disk# start
  165. Read_Primitive(istream,int_file_attrib); // internal file
  166. Read_Primitive(istream,ext_file_attrib); // ext final
  167. Read_Primitive(istream,header_offset);} // rel offset
  168. char* buf=new char[std::max(comment_length,std::max(filename_length,extra_length))+1];
  169. istream.read(buf,filename_length);
  170. buf[filename_length]=0;
  171. filename=std::string(buf);
  172. istream.read(buf,extra_length);
  173. if(global) istream.read(buf,comment_length);
  174. delete [] buf;
  175. return true;}
  176. void Write(std::ostream& ostream,const bool global) const
  177. {if(global){
  178. Write_Primitive(ostream,(unsigned int)0x02014b50); // header sig
  179. Write_Primitive(ostream,(unsigned short)00);} // version made by
  180. else Write_Primitive(ostream,(unsigned int)0x04034b50);
  181. Write_Primitive(ostream,version);
  182. Write_Primitive(ostream,flags);
  183. Write_Primitive(ostream,compression_type);
  184. Write_Primitive(ostream,stamp_date);
  185. Write_Primitive(ostream,stamp_time);
  186. Write_Primitive(ostream,crc);
  187. Write_Primitive(ostream,compressed_size);
  188. Write_Primitive(ostream,uncompressed_size);
  189. Write_Primitive(ostream,(unsigned short)filename.length());
  190. Write_Primitive(ostream,(unsigned short)0); // extra lengthx
  191. if(global){
  192. Write_Primitive(ostream,(unsigned short)0); // filecomment
  193. Write_Primitive(ostream,(unsigned short)0); // disk# start
  194. Write_Primitive(ostream,(unsigned short)0); // internal file
  195. Write_Primitive(ostream,(unsigned int)0); // ext final
  196. Write_Primitive(ostream,(unsigned int)header_offset);} // rel offset
  197. for(unsigned int i=0;i<filename.length();i++) Write_Primitive(ostream,filename.c_str()[i]);}
  198. //#####################################################################
  199. };
  200. //#####################################################################
  201. // class ZipStreambufDecompress
  202. //#####################################################################
  203. class ZipStreambufDecompress:public std::streambuf
  204. {
  205. static const unsigned int buffer_size=512;
  206. std::istream& istream;
  207. z_stream strm;
  208. unsigned char in[buffer_size],out[buffer_size];
  209. ZipFileHeader header;
  210. GZipFileHeader gzip_header;
  211. int total_read,total_uncompressed;
  212. bool part_of_zip_file;
  213. bool own_istream;
  214. bool valid;
  215. bool compressed_data;
  216. static const unsigned short DEFLATE=8;
  217. static const unsigned short UNCOMPRESSED=0;
  218. public:
  219. ZipStreambufDecompress(std::istream& stream,bool part_of_zip_file_input)
  220. :istream(stream),total_read(0),total_uncompressed(0),part_of_zip_file(part_of_zip_file_input),valid(true)
  221. {
  222. strm.zalloc=Z_NULL;strm.zfree=Z_NULL;strm.opaque=Z_NULL;strm.avail_in=0;strm.next_in=Z_NULL;
  223. setg((char*)in,(char*)in,(char*)in);
  224. setp(0,0);
  225. // skip the header
  226. if(part_of_zip_file){
  227. valid=header.Read(istream,false);
  228. if(header.compression_type==DEFLATE) compressed_data=true;
  229. else if(header.compression_type==UNCOMPRESSED) compressed_data=false;
  230. else{
  231. compressed_data=false;std::cerr<<"ZIP: got unrecognized compressed data (Supported deflate/uncompressed)"<<std::endl;
  232. valid=false;}}
  233. else{valid=gzip_header.Read(istream);compressed_data=true;}
  234. // initialize the inflate
  235. if(compressed_data && valid){
  236. int result=inflateInit2(&strm,-MAX_WBITS);
  237. if(result!=Z_OK){std::cerr<<"gzip: inflateInit2 did not return Z_OK"<<std::endl;valid=false;}}
  238. }
  239. virtual ~ZipStreambufDecompress()
  240. {if(compressed_data && valid) inflateEnd(&strm);
  241. if(!part_of_zip_file) delete &istream;}
  242. int process()
  243. {if(!valid) return -1;
  244. if(compressed_data){
  245. strm.avail_out=buffer_size-4;
  246. strm.next_out=(Bytef*)(out+4);
  247. while(strm.avail_out!=0){
  248. if(strm.avail_in==0){ // buffer empty, read some more from file
  249. istream.read((char*)in,part_of_zip_file?std::min((unsigned int)buffer_size,header.compressed_size-total_read):(unsigned int)buffer_size);
  250. strm.avail_in=static_cast<uInt>(istream.gcount());
  251. total_read+=strm.avail_in;
  252. strm.next_in=(Bytef*)in;}
  253. int ret=inflate(&strm,Z_NO_FLUSH); // decompress
  254. switch(ret){
  255. case Z_STREAM_ERROR:
  256. std::cerr<<"libz error Z_STREAM_ERROR"<<std::endl;
  257. valid=false;return -1;
  258. case Z_NEED_DICT:
  259. case Z_DATA_ERROR:
  260. case Z_MEM_ERROR:
  261. std::cerr<<"gzip error "<<strm.msg<<std::endl;
  262. valid=false;return -1;}
  263. if(ret==Z_STREAM_END) break;}
  264. int unzip_count=buffer_size-strm.avail_out-4;
  265. total_uncompressed+=unzip_count;
  266. return unzip_count;}
  267. else{ // uncompressed, so just read
  268. istream.read((char*)(out+4),std::min(buffer_size-4,header.uncompressed_size-total_read));
  269. int count=static_cast<int>(istream.gcount());
  270. total_read+=count;
  271. return count;}
  272. }
  273. virtual int underflow()
  274. {if(gptr() && (gptr()<egptr())) return traits_type::to_int_type(*gptr()); // if we already have data just use it
  275. int put_back_count=static_cast<int>(gptr()-eback());
  276. if(put_back_count>4) put_back_count=4;
  277. std::memmove(out+(4-put_back_count),gptr()-put_back_count,put_back_count);
  278. int num=process();
  279. setg((char*)(out+4-put_back_count),(char*)(out+4),(char*)(out+4+num));
  280. if(num<=0) return EOF;
  281. return traits_type::to_int_type(*gptr());}
  282. virtual int overflow(int)
  283. {assert(false);return EOF;}
  284. // assignment operator declared and not defined, to suppress warning 4512 for Visual Studio
  285. ZipStreambufDecompress& operator=(const ZipStreambufDecompress& _Right);
  286. //#####################################################################
  287. };
  288. //#####################################################################
  289. // class ZipStreambufCompress
  290. //#####################################################################
  291. class ZipStreambufCompress:public std::streambuf
  292. {
  293. static const int buffer_size=512;
  294. std::ostream& ostream; // owned when header==0 (when not part of zip file)
  295. z_stream strm;
  296. unsigned char in[buffer_size],out[buffer_size];
  297. ZipFileHeader* header;
  298. GZipFileHeader gzip_header;
  299. unsigned int header_offset;
  300. unsigned int uncompressed_size;
  301. unsigned int crc;
  302. bool valid;
  303. public:
  304. ZipStreambufCompress(ZipFileHeader* header,std::ostream& stream)
  305. :ostream(stream),header(header),valid(true)
  306. {
  307. strm.zalloc=Z_NULL;strm.zfree=Z_NULL;strm.opaque=Z_NULL;
  308. int ret=deflateInit2(&strm,Z_DEFAULT_COMPRESSION,Z_DEFLATED,-MAX_WBITS,8,Z_DEFAULT_STRATEGY);
  309. if(ret != Z_OK){std::cerr<<"libz: failed to deflateInit"<<std::endl;valid=false;return;}
  310. setg(0,0,0);
  311. setp((char*)in,(char*)(in+buffer_size-4)); // we want to be 4 aligned
  312. // Write appropriate header
  313. if(header){header->header_offset=static_cast<unsigned int>(stream.tellp());header->Write(ostream,false);}
  314. else{header_offset=static_cast<unsigned int>(stream.tellp());gzip_header.Write(ostream);}
  315. uncompressed_size=crc=0;
  316. }
  317. virtual ~ZipStreambufCompress()
  318. {if(valid){
  319. process(true);
  320. deflateEnd(&strm);
  321. if(header){
  322. std::streampos final_position=ostream.tellp();
  323. header->uncompressed_size=uncompressed_size;
  324. header->crc=crc;
  325. ostream.seekp(header->header_offset);
  326. header->Write(ostream,false);
  327. ostream.seekp(final_position);}
  328. else{Write_Primitive(ostream,crc);Write_Primitive(ostream,uncompressed_size);}}
  329. if(!header) delete &ostream;}
  330. protected:
  331. int process(bool flush)
  332. {if(!valid) return -1;
  333. strm.next_in=(Bytef*)pbase();
  334. strm.avail_in=static_cast<uInt>(pptr()-pbase());
  335. while(strm.avail_in!=0 || flush){
  336. strm.avail_out=buffer_size;
  337. strm.next_out=(Bytef*)out;
  338. int ret=deflate(&strm,flush?Z_FINISH:Z_NO_FLUSH);
  339. if(!(ret!=Z_BUF_ERROR && ret!=Z_STREAM_ERROR)){
  340. valid=false;
  341. std::cerr<<"gzip: gzip error "<<strm.msg<<std::endl;;
  342. return -1;}
  343. int generated_output=static_cast<int>(strm.next_out-(Bytef*)out);
  344. ostream.write((char*)out,generated_output);
  345. if(header) header->compressed_size+=generated_output;
  346. if(ret==Z_STREAM_END) break;}
  347. // update counts, crc's and buffers
  348. int consumed_input=static_cast<int>(pptr()-pbase());
  349. uncompressed_size+=consumed_input;
  350. crc=crc32(crc,(Bytef*)in,consumed_input);
  351. setp(pbase(),pbase()+buffer_size-4);return 1;}
  352. virtual int sync()
  353. {if(pptr() && pptr()>pbase()) return process(false);return 0;}
  354. virtual int underflow()
  355. {std::runtime_error("Attempt to read write only ostream");return 0;}
  356. virtual int overflow(int c=EOF)
  357. {if(c!=EOF){*pptr()=static_cast<char>(c);pbump(1);}
  358. if(process(false)==EOF) return EOF;
  359. return c;}
  360. // assignment operator declared and not defined, to suppress warning 4512 for Visual Studio
  361. ZipStreambufCompress& operator=(const ZipStreambufCompress& _Right);
  362. //#####################################################################
  363. };
  364. //#####################################################################
  365. // Class ZIP_FILE_ISTREAM
  366. //#####################################################################
  367. // Class needed because istream cannot own its streambuf
  368. class ZIP_FILE_ISTREAM:public std::istream
  369. {
  370. ZipStreambufDecompress buf;
  371. public:
  372. ZIP_FILE_ISTREAM(std::istream& istream,bool part_of_zip_file)
  373. :std::istream(&buf),buf(istream,part_of_zip_file)
  374. {}
  375. virtual ~ZIP_FILE_ISTREAM()
  376. {}
  377. //#####################################################################
  378. };
  379. //#####################################################################
  380. // Class ZIP_FILE_OSTREAM
  381. //#####################################################################
  382. // Class needed because ostream cannot own its streambuf
  383. class ZIP_FILE_OSTREAM:public std::ostream
  384. {
  385. ZipStreambufCompress buf;
  386. public:
  387. ZIP_FILE_OSTREAM(ZipFileHeader* header,std::ostream& ostream)
  388. :std::ostream(&buf),buf(header,ostream)
  389. {}
  390. virtual ~ZIP_FILE_OSTREAM()
  391. {}
  392. //#####################################################################
  393. };
  394. //#####################################################################
  395. // Function ZipFileWriter
  396. //#####################################################################
  397. ZipFileWriter::
  398. ZipFileWriter(const std::string& filename)
  399. {
  400. ostream.open(filename.c_str(),std::ios::out|std::ios::binary);
  401. if(!ostream) throw std::runtime_error("ZIP: Invalid file handle");
  402. }
  403. //#####################################################################
  404. // Function ZipFileWriter
  405. //#####################################################################
  406. ZipFileWriter::
  407. ~ZipFileWriter()
  408. {
  409. // Write all file headers
  410. std::streampos final_position=ostream.tellp();
  411. for(unsigned int i=0;i<files.size();i++){files[i]->Write(ostream,true);delete files[i];}
  412. std::streampos central_end=ostream.tellp();
  413. // Write end of central
  414. Write_Primitive(ostream,(unsigned int)0x06054b50); // end of central
  415. Write_Primitive(ostream,(unsigned short)0); // this disk number
  416. Write_Primitive(ostream,(unsigned short)0); // this disk number
  417. Write_Primitive(ostream,(unsigned short)files.size()); // one entry in center in this disk
  418. Write_Primitive(ostream,(unsigned short)files.size()); // one entry in center
  419. Write_Primitive(ostream,(unsigned int)(central_end-final_position)); // size of header
  420. Write_Primitive(ostream,(unsigned int)final_position); // offset to header
  421. Write_Primitive(ostream,(unsigned short)0); // zip comment
  422. }
  423. //#####################################################################
  424. // Function ZipFileWriter
  425. //#####################################################################
  426. std::unique_ptr<std::ostream> ZipFileWriter::
  427. Add_File(const std::string& filename,const bool)
  428. {
  429. files.push_back(new ZipFileHeader(filename));
  430. return std::make_unique<ZIP_FILE_OSTREAM>(files.back(),ostream);
  431. }
  432. //#####################################################################
  433. // Function ZipFileReader
  434. //#####################################################################
  435. ZipFileReader::
  436. ZipFileReader(const std::string& filename)
  437. {
  438. istream.open(filename.c_str(),std::ios::in|std::ios::binary);
  439. if(!istream) throw std::runtime_error("ZIP: Invalid file handle");
  440. Find_And_Read_Central_Header();
  441. }
  442. //#####################################################################
  443. // Function ZipFileReader
  444. //#####################################################################
  445. ZipFileReader::
  446. ~ZipFileReader()
  447. {
  448. std::map<std::string,ZipFileHeader*>::iterator i=filename_to_header.begin();
  449. for(;i!=filename_to_header.end();++i)
  450. delete i->second;
  451. }
  452. //#####################################################################
  453. // Function Find_And_Read_Central_Header
  454. //#####################################################################
  455. bool ZipFileReader::
  456. Find_And_Read_Central_Header()
  457. {
  458. // Find the header
  459. // NOTE: this assumes the zip file header is the last thing written to file...
  460. istream.seekg(0,std::ios_base::end);
  461. std::streampos end_position=istream.tellg();
  462. unsigned int max_comment_size=0xffff; // max size of header
  463. unsigned int read_size_before_comment=22;
  464. std::streamoff read_start=max_comment_size+read_size_before_comment;
  465. if(read_start>end_position) read_start=end_position;
  466. istream.seekg(end_position-read_start);
  467. char *buf=new char[static_cast<unsigned int>(read_start)];
  468. if(read_start<=0){std::cerr<<"ZIP: Invalid read buffer size"<<std::endl;return false;}
  469. istream.read(buf,read_start);
  470. int found=-1;
  471. for(unsigned int i=0;i<read_start-3;i++){
  472. if(buf[i]==0x50 && buf[i+1]==0x4b && buf[i+2]==0x05 && buf[i+3]==0x06){found=i;break;}}
  473. delete [] buf;
  474. if(found==-1){std::cerr<<"ZIP: Failed to find zip header"<<std::endl;return false;}
  475. // seek to end of central header and read
  476. istream.seekg(end_position-(read_start-found));
  477. unsigned int word;
  478. unsigned short disk_number1,disk_number2,num_files,num_files_this_disk;
  479. Read_Primitive(istream,word); // end of central
  480. Read_Primitive(istream,disk_number1); // this disk number
  481. Read_Primitive(istream,disk_number2); // this disk number
  482. if(disk_number1!=disk_number2 || disk_number1!=0){
  483. std::cerr<<"ZIP: multiple disk zip files are not supported"<<std::endl;return false;}
  484. Read_Primitive(istream,num_files); // one entry in center in this disk
  485. Read_Primitive(istream,num_files_this_disk); // one entry in center
  486. if(num_files != num_files_this_disk){
  487. std::cerr<<"ZIP: multi disk zip files are not supported"<<std::endl;return false;}
  488. unsigned int size_of_header,header_offset;
  489. Read_Primitive(istream,size_of_header); // size of header
  490. Read_Primitive(istream,header_offset); // offset to header
  491. // go to header and read all file headers
  492. istream.seekg(header_offset);
  493. for(int i=0;i<num_files;i++){
  494. ZipFileHeader* header=new ZipFileHeader;
  495. bool valid=header->Read(istream,true);
  496. if(valid) filename_to_header[header->filename]=header;}
  497. return true;
  498. }
  499. //#####################################################################
  500. // Function Get_File
  501. //#####################################################################
  502. std::unique_ptr<std::istream> ZipFileReader::Get_File(const std::string& filename,const bool)
  503. {
  504. std::map<std::string,ZipFileHeader*>::iterator i=filename_to_header.find(filename);
  505. if(i!=filename_to_header.end()){
  506. ZipFileHeader* header=i->second;
  507. istream.seekg((*header).header_offset);return std::make_unique<ZIP_FILE_ISTREAM>(istream,true);
  508. }
  509. return 0;
  510. }
  511. //#####################################################################
  512. // Function Get_File_List
  513. //#####################################################################
  514. void ZipFileReader::Get_File_List(std::vector<std::string>& filenames) const
  515. {
  516. filenames.clear();
  517. std::map<std::string,ZipFileHeader*>::const_iterator i=filename_to_header.begin();
  518. for(;i!=filename_to_header.end();++i)
  519. filenames.push_back(i->first);
  520. }
  521. //#####################################################################
  522. // Function Gzip_In
  523. //#####################################################################
  524. std::istream*
  525. Gzip_In(const std::string& filename,std::ios::openmode mode)
  526. {
  527. std::ifstream* infile=new std::ifstream(filename.c_str(),mode | std::ios::binary);
  528. GZipFileHeader header;
  529. bool zipped=header.Read(*infile);
  530. infile->seekg(0);
  531. if(!zipped) return infile;
  532. else return new ZIP_FILE_ISTREAM(*infile,false);
  533. }
  534. //#####################################################################
  535. // Function Gzip_Out
  536. //#####################################################################
  537. std::ostream*
  538. Gzip_Out(const std::string& filename,std::ios::openmode mode)
  539. {
  540. std::ofstream* outfile=new std::ofstream(filename.c_str(),mode);
  541. return new ZIP_FILE_OSTREAM(0,*outfile);
  542. }
  543. //#####################################################################
  544. // This is if zlib.h is not available
  545. #if 0
  546. //#####################################################################
  547. // Function Gzip_In
  548. //#####################################################################
  549. std::istream*
  550. Gzip_In(const std::string& filename,std::ios::openmode mode)
  551. {
  552. std::ifstream* infile=new std::ifstream(filename.c_str(),mode | std::ios::binary);
  553. GZipFileHeader header;
  554. bool zipped=header.Read(*infile);
  555. infile->seekg(0);
  556. if(!zipped) return infile;
  557. delete infile;
  558. std::cerr<<"Partio: encountered gz file '"<<filename<<"' but partio not compiled with zlib"<<std::endl;
  559. return 0;
  560. }
  561. //#####################################################################
  562. // Function Gzip_Out
  563. //#####################################################################
  564. std::ostream*
  565. Gzip_Out(const std::string& filename,std::ios::openmode mode)
  566. {
  567. std::cerr<<"Partio: gzipped file write requested for '"<<filename<<"' but partio not compiled with zlib"<<std::endl;
  568. return 0;
  569. }
  570. //#####################################################################
  571. #endif
  572. } // namespace Partio
  573. /* EOF */