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