341
|
1 // File_Extractor 0.4.0. http://www.slack.net/~ant/
|
|
2
|
|
3 #include "Zlib_Inflater.h"
|
|
4
|
|
5 #include <assert.h>
|
|
6 #include <string.h>
|
|
7
|
|
8 /* Copyright (C) 2006 Shay Green. This module is free software; you
|
|
9 can redistribute it and/or modify it under the terms of the GNU Lesser
|
|
10 General Public License as published by the Free Software Foundation; either
|
|
11 version 2.1 of the License, or (at your option) any later version. This
|
|
12 module is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
14 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
|
|
15 details. You should have received a copy of the GNU Lesser General Public
|
|
16 License along with this module; if not, write to the Free Software Foundation,
|
|
17 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
|
|
18
|
|
19 #include "blargg_source.h"
|
|
20
|
|
21 static const char* get_zlib_err( int code )
|
|
22 {
|
|
23 assert( code != Z_OK );
|
|
24 if ( code == Z_MEM_ERROR )
|
|
25 return "Out of memory";
|
|
26
|
|
27 const char* str = zError( code );
|
|
28 if ( code == Z_DATA_ERROR )
|
|
29 str = "Zip data is corrupt";
|
|
30 if ( !str )
|
|
31 str = "Zip error";
|
|
32 return str;
|
|
33 }
|
|
34
|
|
35 void Zlib_Inflater::end()
|
|
36 {
|
|
37 if ( deflated_ )
|
|
38 {
|
|
39 deflated_ = false;
|
|
40 if ( inflateEnd( &zbuf ) )
|
|
41 check( false );
|
|
42 }
|
|
43 buf.clear();
|
|
44
|
|
45 static z_stream const empty = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
|
|
46 memcpy( &zbuf, &empty, sizeof zbuf );
|
|
47 }
|
|
48
|
|
49 Zlib_Inflater::Zlib_Inflater()
|
|
50 {
|
|
51 deflated_ = false;
|
|
52 end(); // initialize things
|
|
53 }
|
|
54
|
|
55 Zlib_Inflater::~Zlib_Inflater()
|
|
56 {
|
|
57 end();
|
|
58 }
|
|
59
|
|
60 blargg_err_t Zlib_Inflater::begin( mode_t mode, callback_t callback, void* user_data,
|
|
61 long buf_size )
|
|
62 {
|
|
63 end();
|
|
64
|
|
65 if ( buf_size && buf.resize( buf_size ) )
|
|
66 buf_size = 0; // not enough memory for requested size, so use default
|
|
67
|
|
68 if ( !buf_size )
|
|
69 RETURN_ERR( buf.resize( 16 * 1024L ) );
|
|
70
|
|
71 // Fill buffer with some data, less than normal buffer size since caller might
|
|
72 // just be examining beginning of file. 4K is a common disk block size.
|
|
73 long count = (buf_size ? buf_size : 4096);
|
|
74 RETURN_ERR( callback( user_data, buf.begin(), &count ) );
|
|
75 zbuf.avail_in = count;
|
|
76 zbuf.next_in = buf.begin();
|
|
77
|
|
78 if ( mode == mode_auto )
|
|
79 {
|
|
80 // examine buffer for gzip header
|
|
81 mode = mode_copy;
|
|
82 int const min_gzip_size = 2 + 8 + 8;
|
|
83 if ( count >= min_gzip_size && buf [0] == 0x1F && buf [1] == 0x8B )
|
|
84 mode = mode_ungz;
|
|
85 }
|
|
86
|
|
87 if ( mode != mode_copy )
|
|
88 {
|
|
89 int wb = MAX_WBITS + 16; // have zlib handle gzip header
|
|
90 if ( mode == mode_raw_deflate )
|
|
91 wb = -MAX_WBITS;
|
|
92
|
|
93 int zerr = inflateInit2( &zbuf, wb );
|
|
94 if ( zerr )
|
|
95 return get_zlib_err( zerr );
|
|
96
|
|
97 deflated_ = true;
|
|
98 }
|
|
99 return 0;
|
|
100 }
|
|
101
|
|
102
|
|
103 blargg_err_t Zlib_Inflater::read( void* out, long* count_io,
|
|
104 callback_t callback, void* user_data )
|
|
105 {
|
|
106 if ( !*count_io )
|
|
107 return 0;
|
|
108
|
|
109 if ( !deflated_ )
|
|
110 {
|
|
111 // copy buffered data
|
|
112 long first = zbuf.avail_in;
|
|
113 if ( first )
|
|
114 {
|
|
115 if ( first > *count_io )
|
|
116 first = *count_io;
|
|
117 memcpy( out, zbuf.next_in, first );
|
|
118 zbuf.next_in += first;
|
|
119 zbuf.avail_in -= first;
|
|
120 if ( !zbuf.avail_in )
|
|
121 buf.clear(); // done with buffer
|
|
122 }
|
|
123
|
|
124 // read remaining directly
|
|
125 long second = *count_io - first;
|
|
126 if ( second )
|
|
127 {
|
|
128 long actual = second;
|
|
129 RETURN_ERR( callback( user_data, (char*) out + first, &actual ) );
|
|
130 *count_io -= second - actual;
|
|
131 }
|
|
132 }
|
|
133 else
|
|
134 {
|
|
135 zbuf.next_out = (Bytef*) out;
|
|
136 zbuf.avail_out = *count_io;
|
|
137
|
|
138 while ( 1 )
|
|
139 {
|
|
140 uInt old_avail_in = zbuf.avail_in;
|
|
141 int err = inflate( &zbuf, Z_NO_FLUSH );
|
|
142 if ( err == Z_STREAM_END )
|
|
143 {
|
|
144 *count_io -= zbuf.avail_out;
|
|
145 end();
|
|
146 break; // all data deflated
|
|
147 }
|
|
148
|
|
149 if ( err == Z_BUF_ERROR && !old_avail_in )
|
|
150 err = 0; // we just need to provide more input
|
|
151
|
|
152 if ( err )
|
|
153 return get_zlib_err( err );
|
|
154
|
|
155 if ( !zbuf.avail_out )
|
|
156 break; // requested number of bytes deflated
|
|
157
|
|
158 if ( zbuf.avail_in )
|
|
159 {
|
|
160 // inflate() should never leave input if there's still space for output
|
|
161 assert( false );
|
|
162 return "Corrupt zip data";
|
|
163 }
|
|
164
|
|
165 // refill buffer
|
|
166 long count = buf.size();
|
|
167 RETURN_ERR( callback( user_data, buf.begin(), &count ) );
|
|
168 zbuf.next_in = buf.begin();
|
|
169 zbuf.avail_in = count;
|
|
170 if ( !zbuf.avail_in )
|
|
171 return "Corrupt zip data"; // stream didn't end but there's no more data
|
|
172 }
|
|
173 }
|
|
174 return 0;
|
|
175 }
|