1 // -*- mode: c++; c-set-style: "stroustrup"; tab-width: 4; -*-
2 //
3 // CFile.c
4 //
5 // Copyright (C) 2004 Koji Nakamaru
6 //
7 // This program is free software; you can redistribute it and/or modify
8 // it under the terms of the GNU General Public License as published by
9 // the Free Software Foundation; either version 2, or (at your option)
10 // any later version.
11 //
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU General Public License for more details.
16 //
17 // You should have received a copy of the GNU General Public License
18 // along with this program; if not, write to the Free Software Foundation,
19 // Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 //
21
22 #include "common.h"
23 #include <bzlib.h>
24 #include <lzma.h>
25 #include <zlib.h>
26 #include "CFile.h"
27
28 // public functions
29
CFile()30 CFile::CFile()
31 : _type(kFileNone),
32 _fp(NULL),
33 _stream(NULL),
34 _pos(0)
35 {
36 memset(_name, 0, sizeof(_name));
37 }
38
~CFile()39 CFile::~CFile()
40 {
41 }
42
open(char * name)43 bool CFile::open(
44 char *name)
45 {
46 if (name == NULL) {
47 _fp = stdin;
48 _type = kFileStdIn;
49 } else {
50 FILE *fp;
51 if ((fp = fopen(name, "r")) == NULL) {
52 return false;
53 }
54 int c0 = fgetc(fp);
55 int c1 = fgetc(fp);
56 int c2 = fgetc(fp);
57 int c3 = fgetc(fp);
58 int c4 = fgetc(fp);
59 int c5 = fgetc(fp);
60 fclose(fp);
61 if (c0 == 'B' && c1 == 'Z') {
62 _type = kFileBZ;
63 if ((_fp = (void *)BZ2_bzopen(name, "rb")) == NULL) {
64 goto err;
65 }
66 } else if (c0 == 037 && c1 == 0213) {
67 _type = kFileGZ;
68 if ((_fp = (void *)gzopen(name, "rb")) == NULL) {
69 goto err;
70 }
71 } else if (c0 == 0xFD && c1 == '7' && c2 == 'z' && c3 == 'X' && c4 == 'Z' && c5 == 0x00) {
72 _type = kFileXZ;
73 if ((_fp = (void *)fopen(name, "r")) == NULL) {
74 goto err;
75 }
76 _stream = new char[sizeof(lzma_stream)];
77 memset(_stream, 0, sizeof(lzma_stream));
78 if (lzma_stream_decoder((lzma_stream *)_stream, lzma_easy_decoder_memusage(9), 0) != LZMA_OK) {
79 goto err;
80 }
81 } else {
82 _type = kFileUZ;
83 if ((_fp = (void *)fopen(name, "r")) == NULL) {
84 goto err;
85 }
86 }
87 strcpy(_name, name);
88 }
89 _pos = 0;
90 return true;
91 err:
92 close();
93 return false;
94 }
95
close()96 void CFile::close()
97 {
98 _pos = 0;
99 if (_stream) {
100 lzma_end((lzma_stream *)_stream);
101 delete[] _stream;
102 _stream = NULL;
103 }
104 if (_fp) {
105 switch (_type) {
106 case kFileBZ:
107 BZ2_bzclose((BZFILE *)_fp);
108 break;
109 case kFileGZ:
110 gzclose((gzFile)_fp);
111 break;
112 case kFileXZ:
113 case kFileUZ:
114 fclose((FILE *)_fp);
115 break;
116 default:
117 break;
118 }
119 _fp = NULL;
120 }
121 }
122
stat(struct stat * stbuf)123 bool CFile::stat(
124 struct stat *stbuf)
125 {
126 switch (_type) {
127 case kFileBZ:
128 case kFileGZ:
129 case kFileXZ:
130 case kFileUZ:
131 return ::stat(_name, stbuf) == 0;
132 default:
133 return false;
134 }
135 }
136
gets(char * buf,size_t len)137 char *CFile::gets(
138 char *buf,
139 size_t len)
140 {
141 memset(buf, 0, len--);
142 char *bp = buf;
143 int c;
144 while ((c = getc()) != EOF && bp - buf < (int)len) {
145 *bp++ = c;
146 if (c == '\n') {
147 return buf;
148 }
149 }
150 return (bp > buf) ? buf : NULL;
151 }
152
getc()153 int CFile::getc()
154 {
155 unsigned char buf[1];
156 if (read(buf, 1) == 0) {
157 return EOF;
158 }
159 return buf[0];
160 }
161
read(void * buf,size_t len)162 size_t CFile::read(
163 void *buf,
164 size_t len)
165 {
166 int count = 0;
167 switch (_type) {
168 case kFileBZ:
169 count = BZ2_bzread((BZFILE *)_fp, buf, len);
170 break;
171 case kFileGZ:
172 count = gzread((gzFile)_fp, buf, len);
173 break;
174 case kFileXZ:
175 {
176 lzma_stream *stream = (lzma_stream *)_stream;
177 stream->next_out = (uint8_t *)buf;
178 stream->avail_out = len;
179 while (stream->avail_out > 0) {
180 if (stream->avail_in == 0) {
181 stream->next_in = (uint8_t *)_buf;
182 stream->avail_in = fread(_buf, 1, 1, (FILE *)_fp);
183 }
184 lzma_ret ret = lzma_code(stream, LZMA_RUN);
185 if (ret == LZMA_STREAM_END || ret != LZMA_OK) {
186 break;
187 }
188 }
189 count = len - stream->avail_out;
190 }
191 break;
192 case kFileStdIn:
193 case kFileUZ:
194 count = fread(buf, 1, len, (FILE *)_fp);
195 break;
196 default:
197 return 0;
198 };
199 _pos += count;
200 return count;
201 }
202
seek(size_t pos)203 bool CFile::seek(
204 size_t pos)
205 {
206 switch (_type) {
207 case kFileBZ:
208 case kFileGZ:
209 case kFileXZ:
210 close();
211 if (! open(_name)) {
212 return false;
213 }
214 break;
215 case kFileStdIn:
216 return false;
217 case kFileUZ:
218 default:
219 break;
220 }
221 switch (_type) {
222 case kFileBZ:
223 case kFileGZ:
224 case kFileXZ:
225 while (_pos < pos) {
226 char buf[BUFSIZ];
227 size_t off = pos - _pos;
228 if (read(buf, (off > BUFSIZ) ? BUFSIZ : off) == 0) {
229 return false;
230 }
231 }
232 break;
233 case kFileUZ:
234 if (fseek((FILE *)_fp, pos, SEEK_SET) != 0) {
235 return false;
236 }
237 break;
238 default:
239 break;
240 }
241 return false;
242 }
243
tell()244 size_t CFile::tell()
245 {
246 return _pos;
247 }
248
249 // protected functions
250 // private functions
251 // local functions
252