@@ -85,3 +85,127 @@ Rar_Reader::~Rar_Reader() {
8585}
8686
8787#endif // RARDLL
88+
89+
90+ #ifdef HAVE_LIBARCHIVE
91+
92+ const char * zip_err_struct = " Failed to create archive struct" ;
93+
94+ #ifdef HAVE_ZLIB_H
95+ static const int zerr_offset = -6 ;
96+ static blargg_err_t const zerrs[] = {
97+ " GZ: Bad version" , // Z_VERSION_ERROR (-6)
98+ " GZ: Buffer too small" , // Z_BUF_ERROR (-5)
99+ " GZ: Out of memory" , // Z_MEM_ERROR (-4)
100+ " GZ: Bad Data" , // Z_DATA_ERROR (-3)
101+ " GZ: Stream error" , // Z_STREAM_ERROR (-2)
102+ };
103+ #endif // HAVE_ZLIB_H
104+
105+ blargg_err_t Zip_Reader::open_zip ( const char * path ) {
106+ if ( !(zip = archive_read_new ()) )
107+ return zip_err_struct;
108+ if ( archive_read_support_filter_all ( zip ) != ARCHIVE_OK
109+ || archive_read_support_format_zip ( zip ) != ARCHIVE_OK
110+ || archive_read_open_filename ( zip, path, 10240 ) != ARCHIVE_OK )
111+ return archive_error_string ( zip );
112+ return nullptr ;
113+ }
114+
115+ blargg_err_t Zip_Reader::open ( const char * path )
116+ {
117+ blargg_err_t err;
118+ if ( (err = open_zip ( path )) )
119+ return err;
120+
121+ // determine space needed for the unpacked size and file count.
122+ int res;
123+ while ( (res = archive_read_next_header ( zip, &head )) == ARCHIVE_OK )
124+ {
125+ #ifdef HAVE_ZLIB_H
126+ char h[3 ];
127+ archive_read_data ( zip, &h, 3 );
128+ if ( BLARGG_2CHAR ( h[0 ], h[1 ] ) == gz_signature && h[2 ] == 8 )
129+ {
130+ // gzip puts its uncompressed file size in the footer
131+ blargg_vector<uint8_t > buf;
132+ if ( (err = buf.resize ( archive_entry_size ( head ) - 3 )) )
133+ return err;
134+ archive_read_data ( zip, buf.begin (), buf.size () );
135+ const uint8_t * b = buf.end () - 4 ;
136+ size_ += BLARGG_4CHAR (b[3 ], b[2 ], b[1 ], b[0 ]);
137+ }
138+ else
139+ #endif // HAVE_ZLIB_H
140+ {
141+ size_ += archive_entry_size ( head );
142+ }
143+ count_ += 1 ;
144+ }
145+ if ( res != ARCHIVE_EOF || archive_read_free ( zip ) != ARCHIVE_OK )
146+ return archive_error_string ( zip );
147+
148+ if ( (err = open_zip ( path )) )
149+ return err;
150+ return nullptr ;
151+ }
152+
153+ blargg_err_t Zip_Reader::next ( void * buf_ptr, arc_entry_t * entry )
154+ {
155+ int res;
156+ if ( (res = archive_read_next_header ( zip, &head )) != ARCHIVE_OK )
157+ return (res == ARCHIVE_EOF ) ? arc_eof : archive_error_string ( zip );
158+
159+ uint8_t * bp = (uint8_t *)buf_ptr;
160+ la_int64_t size = archive_entry_size ( head );
161+ la_ssize_t pos = 0 ;
162+ #ifdef HAVE_ZLIB_H
163+ pos += archive_read_data ( zip, bp, 3 );
164+ if ( BLARGG_2CHAR ( bp[0 ], bp[1 ] ) == gz_signature && bp[2 ] == 8 )
165+ {
166+ // load the gzip file into a separate buffer
167+ blargg_err_t err;
168+ blargg_vector<uint8_t > buf;
169+ if ( (err = buf.resize ( size )) )
170+ return err;
171+ memcpy ( &buf[0 ], bp, pos );
172+ archive_read_data ( zip, &buf[0 ] + pos, buf.size () - pos );
173+ const uint8_t * b = buf.end () - 4 ;
174+ size = BLARGG_4CHAR (b[3 ], b[2 ], b[1 ], b[0 ]);
175+
176+ z_stream stream;
177+ memset ( &stream, 0 , sizeof stream );
178+ stream.next_in = buf.begin ();
179+ stream.avail_in = buf.size ();
180+ stream.next_out = bp;
181+ stream.avail_out = size;
182+
183+ // 15 window bits, and the +32 tells zlib to to detect if using gzip or zlib
184+ if ( (res = inflateInit2 ( &stream, 15 + 32 )) != Z_OK
185+ || (res = inflate ( &stream, Z_FINISH )) != Z_STREAM_END )
186+ {
187+ inflateEnd ( &stream );
188+ return zerrs[res - zerr_offset];
189+ }
190+ pos = stream.total_out ;
191+ inflateEnd ( &stream );
192+ }
193+ else
194+ #endif // HAVE_ZLIB_H
195+ {
196+ pos += archive_read_data ( zip, bp + pos, size - pos );
197+ }
198+ if ( pos != size )
199+ return " ZIP: header size does not match total bytes read" ;
200+
201+ entry->name = archive_entry_pathname ( head );
202+ entry->size = size;
203+ return nullptr ;
204+ }
205+
206+ Zip_Reader::~Zip_Reader ()
207+ {
208+ archive_read_free ( zip );
209+ }
210+
211+ #endif // HAVE_LIBARCHIVE
0 commit comments