Mercurial > audlegacy-plugins
comparison src/console/Zlib_Inflater.cxx @ 341:986f098da058 trunk
[svn] - merge in blargg's changes
author | nenolod |
---|---|
date | Thu, 07 Dec 2006 15:20:41 -0800 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
340:9e5a7158fa80 | 341:986f098da058 |
---|---|
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 } |