341
|
1 // File_Extractor 0.4.0. http://www.slack.net/~ant/
|
|
2
|
|
3 #include "Gzip_Reader.h"
|
|
4
|
|
5 #include "blargg_endian.h"
|
|
6
|
|
7 /* Copyright (C) 2006 Shay Green. This module is free software; you
|
|
8 can redistribute it and/or modify it under the terms of the GNU Lesser
|
|
9 General Public License as published by the Free Software Foundation; either
|
|
10 version 2.1 of the License, or (at your option) any later version. This
|
|
11 module is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
13 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
|
|
14 details. You should have received a copy of the GNU Lesser General Public
|
|
15 License along with this module; if not, write to the Free Software Foundation,
|
|
16 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
|
|
17
|
|
18 #include "blargg_source.h"
|
|
19
|
|
20 void Gzip_Reader::close()
|
|
21 {
|
|
22 in = 0;
|
|
23 tell_ = 0;
|
|
24 size_ = 0;
|
|
25 inflater.end();
|
|
26 }
|
|
27
|
|
28 Gzip_Reader::Gzip_Reader() { close(); }
|
|
29
|
|
30 Gzip_Reader::~Gzip_Reader() { }
|
|
31
|
|
32 static blargg_err_t gzip_reader_read( void* file, void* out, long* count )
|
|
33 {
|
|
34 *count = ((File_Reader*) file)->read_avail( out, *count );
|
|
35 return (*count < 0 ? "Read error" : 0);
|
|
36 }
|
|
37
|
|
38 blargg_err_t Gzip_Reader::open( File_Reader* new_in )
|
|
39 {
|
|
40 close();
|
|
41
|
|
42 RETURN_ERR( inflater.begin( inflater.mode_auto, gzip_reader_read, new_in ) );
|
|
43
|
|
44 size_ = -1; // defer seeking to end of file until size is actually needed
|
|
45 in = new_in;
|
|
46 return 0;
|
|
47 }
|
|
48
|
|
49 blargg_err_t Gzip_Reader::calc_size()
|
|
50 {
|
|
51 long size = in->size();
|
|
52 if ( inflater.deflated() )
|
|
53 {
|
|
54 byte trailer [4];
|
|
55 long pos = in->tell();
|
|
56 RETURN_ERR( in->seek( size - sizeof trailer ) );
|
|
57 RETURN_ERR( in->read( trailer, sizeof trailer ) );
|
|
58 RETURN_ERR( in->seek( pos ) );
|
|
59 size = get_le32( trailer );
|
|
60 }
|
|
61 size_ = size;
|
|
62 return 0;
|
|
63 }
|
|
64
|
|
65 long Gzip_Reader::remain() const
|
|
66 {
|
|
67 if ( size_ < 0 )
|
|
68 {
|
|
69 if ( !in )
|
|
70 return 0;
|
|
71
|
|
72 // need to cast away constness to change cached value
|
|
73 if ( ((Gzip_Reader*) this)->calc_size() )
|
|
74 return -1;
|
|
75 }
|
|
76 return size_ - tell_;
|
|
77 }
|
|
78
|
|
79 blargg_err_t Gzip_Reader::read_( void* out, long* count )
|
|
80 {
|
|
81 blargg_err_t err = inflater.read( out, count, gzip_reader_read, in );
|
|
82 tell_ += *count;
|
|
83 if ( size_ >= 0 && tell_ > size_ )
|
|
84 {
|
|
85 tell_ = size_;
|
|
86 return "Corrupt gzip file";
|
|
87 }
|
|
88 return err;
|
|
89 }
|
|
90
|
|
91 blargg_err_t Gzip_Reader::read( void* out, long count )
|
|
92 {
|
|
93 if ( in )
|
|
94 {
|
|
95 long actual = count;
|
|
96 RETURN_ERR( read_( out, &actual ) );
|
|
97 if ( actual == count )
|
|
98 return 0;
|
|
99 }
|
|
100 return eof_error;
|
|
101 }
|
|
102
|
|
103 long Gzip_Reader::read_avail( void* out, long count )
|
|
104 {
|
|
105 if ( !in || read_( out, &count ) )
|
|
106 count = -1;
|
|
107 return count;
|
|
108 }
|