1 | /*****************************************************************************\ |
2 | Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. |
3 | This file is licensed under the Snes9x License. |
4 | For further information, consult the LICENSE file in the root directory. |
5 | \*****************************************************************************/ |
6 | |
7 | // Abstract the details of reading from zip files versus FILE *'s. |
8 | |
9 | #include <string> |
10 | #ifdef UNZIP_SUPPORT |
11 | # ifdef SYSTEM_ZIP |
12 | # include <minizip/unzip.h> |
13 | # else |
14 | # include "unzip.h" |
15 | # endif |
16 | #endif |
17 | #include "snes9x.h" |
18 | #include "stream.h" |
19 | |
20 | |
21 | // Generic constructor/destructor |
22 | |
23 | Stream::Stream (void) |
24 | { |
25 | return; |
26 | } |
27 | |
28 | Stream::~Stream (void) |
29 | { |
30 | return; |
31 | } |
32 | |
33 | // Generic getline function, based on gets. Reimlpement if you can do better. |
34 | |
35 | char * Stream::getline (void) |
36 | { |
37 | bool eof; |
38 | std::string ret; |
39 | |
40 | ret = getline(eof); |
41 | if (ret.size() == 0 && eof) |
42 | return (NULL); |
43 | |
44 | return (strdup(ret.c_str())); |
45 | } |
46 | |
47 | std::string Stream::getline (bool &eof) |
48 | { |
49 | char buf[1024]; |
50 | std::string ret; |
51 | |
52 | eof = false; |
53 | ret.clear(); |
54 | |
55 | do |
56 | { |
57 | if (gets(buf, sizeof(buf)) == NULL) |
58 | { |
59 | eof = true; |
60 | break; |
61 | } |
62 | |
63 | ret.append(buf); |
64 | } |
65 | while (*ret.rbegin() != '\n'); |
66 | |
67 | return (ret); |
68 | } |
69 | |
70 | size_t Stream::pos_from_origin_offset(uint8 origin, int32 offset) |
71 | { |
72 | size_t position = 0; |
73 | switch (origin) |
74 | { |
75 | case SEEK_SET: |
76 | position = offset; |
77 | break; |
78 | case SEEK_END: |
79 | position = size() + offset; |
80 | break; |
81 | case SEEK_CUR: |
82 | position = pos() + offset; |
83 | break; |
84 | } |
85 | return position; |
86 | } |
87 | |
88 | // snes9x.h FSTREAM Stream |
89 | |
90 | fStream::fStream (FSTREAM f) |
91 | { |
92 | fp = f; |
93 | } |
94 | |
95 | fStream::~fStream (void) |
96 | { |
97 | return; |
98 | } |
99 | |
100 | int fStream::get_char (void) |
101 | { |
102 | return (GETC_FSTREAM(fp)); |
103 | } |
104 | |
105 | char * fStream::gets (char *buf, size_t len) |
106 | { |
107 | return (GETS_FSTREAM(buf, len, fp)); |
108 | } |
109 | |
110 | size_t fStream::read (void *buf, size_t len) |
111 | { |
112 | return (READ_FSTREAM(buf, len, fp)); |
113 | } |
114 | |
115 | size_t fStream::write (void *buf, size_t len) |
116 | { |
117 | return (WRITE_FSTREAM(buf, len, fp)); |
118 | } |
119 | |
120 | size_t fStream::pos (void) |
121 | { |
122 | return (FIND_FSTREAM(fp)); |
123 | } |
124 | |
125 | size_t fStream::size (void) |
126 | { |
127 | size_t sz; |
128 | REVERT_FSTREAM(fp,0L,SEEK_END); |
129 | sz = FIND_FSTREAM(fp); |
130 | REVERT_FSTREAM(fp,0L,SEEK_SET); |
131 | return sz; |
132 | } |
133 | |
134 | int fStream::revert (uint8 origin, int32 offset) |
135 | { |
136 | return (REVERT_FSTREAM(fp, offset, origin)); |
137 | } |
138 | |
139 | void fStream::closeStream() |
140 | { |
141 | CLOSE_FSTREAM(fp); |
142 | delete this; |
143 | } |
144 | |
145 | // unzip Stream |
146 | |
147 | #ifdef UNZIP_SUPPORT |
148 | |
149 | unzStream::unzStream (unzFile &v) |
150 | { |
151 | file = v; |
152 | pos_in_buf = 0; |
153 | buf_pos_in_unzipped = unztell(file); |
154 | bytes_in_buf = 0; |
155 | |
156 | // remember start pos for seeks |
157 | unzGetFilePos(file, &unz_file_start_pos); |
158 | } |
159 | |
160 | unzStream::~unzStream (void) |
161 | { |
162 | return; |
163 | } |
164 | |
165 | size_t unzStream::buffer_remaining() |
166 | { |
167 | return bytes_in_buf - pos_in_buf; |
168 | } |
169 | |
170 | void unzStream::fill_buffer() |
171 | { |
172 | buf_pos_in_unzipped = unztell(file); |
173 | bytes_in_buf = unzReadCurrentFile(file, buffer, unz_BUFFSIZ); |
174 | pos_in_buf = 0; |
175 | } |
176 | |
177 | int unzStream::get_char (void) |
178 | { |
179 | unsigned char c; |
180 | |
181 | if (buffer_remaining() <= 0) |
182 | { |
183 | fill_buffer(); |
184 | if (bytes_in_buf <= 0) |
185 | return (EOF); |
186 | } |
187 | |
188 | c = *(buffer + pos_in_buf); |
189 | pos_in_buf++; |
190 | |
191 | return ((int) c); |
192 | } |
193 | |
194 | char * unzStream::gets (char *buf, size_t len) |
195 | { |
196 | size_t i; |
197 | int c; |
198 | |
199 | for (i = 0; i < len - 1; i++) |
200 | { |
201 | c = get_char(); |
202 | if (c == EOF) |
203 | { |
204 | if (i == 0) |
205 | return (NULL); |
206 | break; |
207 | } |
208 | |
209 | buf[i] = (char) c; |
210 | if (buf[i] == '\n') |
211 | break; |
212 | } |
213 | |
214 | buf[i] = '\0'; |
215 | |
216 | return (buf); |
217 | } |
218 | |
219 | size_t unzStream::read (void *buf, size_t len) |
220 | { |
221 | if (len == 0) |
222 | return (len); |
223 | |
224 | size_t to_read = len; |
225 | uint8 *read_to = (uint8 * )buf; |
226 | do |
227 | { |
228 | size_t in_buffer = buffer_remaining(); |
229 | if (to_read <= in_buffer) |
230 | { |
231 | memcpy(read_to, buffer + pos_in_buf, to_read); |
232 | pos_in_buf += to_read; |
233 | to_read = 0; |
234 | break; |
235 | } |
236 | |
237 | memcpy(read_to, buffer + pos_in_buf, in_buffer); |
238 | to_read -= in_buffer; |
239 | fill_buffer(); |
240 | } while (bytes_in_buf); |
241 | |
242 | return (len - to_read); |
243 | } |
244 | |
245 | // not supported |
246 | size_t unzStream::write (void *buf, size_t len) |
247 | { |
248 | return (0); |
249 | } |
250 | |
251 | size_t unzStream::pos (void) |
252 | { |
253 | return buf_pos_in_unzipped + pos_in_buf; |
254 | } |
255 | |
256 | size_t unzStream::size (void) |
257 | { |
258 | unz_file_info info; |
259 | unzGetCurrentFileInfo(file,&info,NULL,0,NULL,0,NULL,0); |
260 | return info.uncompressed_size; |
261 | } |
262 | |
263 | int unzStream::revert (uint8 origin, int32 offset) |
264 | { |
265 | size_t target_pos = pos_from_origin_offset(origin, offset); |
266 | |
267 | // new pos inside buffered data |
268 | if (target_pos >= buf_pos_in_unzipped && target_pos < buf_pos_in_unzipped + bytes_in_buf) |
269 | { |
270 | pos_in_buf = target_pos - buf_pos_in_unzipped; |
271 | } |
272 | else // outside of buffer, reset file and read until pos |
273 | { |
274 | unzGoToFilePos(file, &unz_file_start_pos); |
275 | unzOpenCurrentFile(file); // necessary to reopen after seek |
276 | int times_to_read = target_pos / unz_BUFFSIZ + 1; |
277 | for( int i = 0; i < times_to_read; i++) |
278 | { |
279 | fill_buffer(); |
280 | } |
281 | pos_in_buf = target_pos % unz_BUFFSIZ; |
282 | } |
283 | return 0; |
284 | } |
285 | |
286 | void unzStream::closeStream() |
287 | { |
288 | unzClose(file); |
289 | delete this; |
290 | } |
291 | |
292 | #endif |
293 | |
294 | // memory Stream |
295 | |
296 | memStream::memStream (uint8 *source, size_t sourceSize) |
297 | { |
298 | mem = head = source; |
299 | msize = remaining = sourceSize; |
300 | readonly = false; |
301 | } |
302 | |
303 | memStream::memStream (const uint8 *source, size_t sourceSize) |
304 | { |
305 | mem = head = const_cast<uint8 *>(source); |
306 | msize = remaining = sourceSize; |
307 | readonly = true; |
308 | } |
309 | |
310 | memStream::~memStream (void) |
311 | { |
312 | return; |
313 | } |
314 | |
315 | int memStream::get_char (void) |
316 | { |
317 | if(!remaining) |
318 | return EOF; |
319 | |
320 | remaining--; |
321 | return *head++; |
322 | } |
323 | |
324 | char * memStream::gets (char *buf, size_t len) |
325 | { |
326 | size_t i; |
327 | int c; |
328 | |
329 | for (i = 0; i < len - 1; i++) |
330 | { |
331 | c = get_char(); |
332 | if (c == EOF) |
333 | { |
334 | if (i == 0) |
335 | return (NULL); |
336 | break; |
337 | } |
338 | |
339 | buf[i] = (char) c; |
340 | if (buf[i] == '\n') |
341 | break; |
342 | } |
343 | |
344 | buf[i] = '\0'; |
345 | |
346 | return (buf); |
347 | } |
348 | |
349 | size_t memStream::read (void *buf, size_t len) |
350 | { |
351 | size_t bytes = len < remaining ? len : remaining; |
352 | memcpy(buf,head,bytes); |
353 | head += bytes; |
354 | remaining -= bytes; |
355 | |
356 | return bytes; |
357 | } |
358 | |
359 | size_t memStream::write (void *buf, size_t len) |
360 | { |
361 | if(readonly) |
362 | return 0; |
363 | |
364 | size_t bytes = len < remaining ? len : remaining; |
365 | memcpy(head,buf,bytes); |
366 | head += bytes; |
367 | remaining -= bytes; |
368 | |
369 | return bytes; |
370 | } |
371 | |
372 | size_t memStream::pos (void) |
373 | { |
374 | return msize - remaining; |
375 | } |
376 | |
377 | size_t memStream::size (void) |
378 | { |
379 | return msize; |
380 | } |
381 | |
382 | int memStream::revert (uint8 origin, int32 offset) |
383 | { |
384 | size_t pos = pos_from_origin_offset(origin, offset); |
385 | |
386 | if(pos > msize) |
387 | return -1; |
388 | |
389 | head = mem + pos; |
390 | remaining = msize - pos; |
391 | |
392 | return 0; |
393 | } |
394 | |
395 | void memStream::closeStream() |
396 | { |
397 | delete [] mem; |
398 | delete this; |
399 | } |
400 | |
401 | // dummy Stream |
402 | |
403 | nulStream::nulStream (void) |
404 | { |
405 | bytes_written = 0; |
406 | } |
407 | |
408 | nulStream::~nulStream (void) |
409 | { |
410 | return; |
411 | } |
412 | |
413 | int nulStream::get_char (void) |
414 | { |
415 | return 0; |
416 | } |
417 | |
418 | char * nulStream::gets (char *buf, size_t len) |
419 | { |
420 | *buf = '\0'; |
421 | return NULL; |
422 | } |
423 | |
424 | size_t nulStream::read (void *buf, size_t len) |
425 | { |
426 | return 0; |
427 | } |
428 | |
429 | size_t nulStream::write (void *buf, size_t len) |
430 | { |
431 | bytes_written += len; |
432 | return len; |
433 | } |
434 | |
435 | size_t nulStream::pos (void) |
436 | { |
437 | return 0; |
438 | } |
439 | |
440 | size_t nulStream::size (void) |
441 | { |
442 | return bytes_written; |
443 | } |
444 | |
445 | int nulStream::revert (uint8 origin, int32 offset) |
446 | { |
447 | size_t target_pos = pos_from_origin_offset(origin, offset); |
448 | bytes_written = target_pos; |
449 | return 0; |
450 | } |
451 | |
452 | void nulStream::closeStream() |
453 | { |
454 | delete this; |
455 | } |
456 | |
457 | Stream *openStreamFromFSTREAM(const char* filename, const char* mode) |
458 | { |
459 | FSTREAM f = OPEN_FSTREAM(filename,mode); |
460 | if(!f) |
461 | return NULL; |
462 | return new fStream(f); |
463 | } |
464 | |
465 | Stream *reopenStreamFromFd(int fd, const char* mode) |
466 | { |
467 | FSTREAM f = REOPEN_FSTREAM(fd,mode); |
468 | if(!f) |
469 | return NULL; |
470 | return new fStream(f); |
471 | } |
472 | |