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 }