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
23Stream::Stream (void)
24{
25 return;
26}
27
28Stream::~Stream (void)
29{
30 return;
31}
32
33// Generic getline function, based on gets. Reimlpement if you can do better.
34
35char * 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
47std::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
70size_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
90fStream::fStream (FSTREAM f)
91{
92 fp = f;
93}
94
95fStream::~fStream (void)
96{
97 return;
98}
99
100int fStream::get_char (void)
101{
102 return (GETC_FSTREAM(fp));
103}
104
105char * fStream::gets (char *buf, size_t len)
106{
107 return (GETS_FSTREAM(buf, len, fp));
108}
109
110size_t fStream::read (void *buf, size_t len)
111{
112 return (READ_FSTREAM(buf, len, fp));
113}
114
115size_t fStream::write (void *buf, size_t len)
116{
117 return (WRITE_FSTREAM(buf, len, fp));
118}
119
120size_t fStream::pos (void)
121{
122 return (FIND_FSTREAM(fp));
123}
124
125size_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
134int fStream::revert (uint8 origin, int32 offset)
135{
136 return (REVERT_FSTREAM(fp, offset, origin));
137}
138
139void fStream::closeStream()
140{
141 CLOSE_FSTREAM(fp);
142 delete this;
143}
144
145// unzip Stream
146
147#ifdef UNZIP_SUPPORT
148
149unzStream::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
160unzStream::~unzStream (void)
161{
162 return;
163}
164
165size_t unzStream::buffer_remaining()
166{
167 return bytes_in_buf - pos_in_buf;
168}
169
170void 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
177int 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
194char * 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
219size_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
246size_t unzStream::write (void *buf, size_t len)
247{
248 return (0);
249}
250
251size_t unzStream::pos (void)
252{
253 return buf_pos_in_unzipped + pos_in_buf;
254}
255
256size_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
263int 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
286void unzStream::closeStream()
287{
288 unzClose(file);
289 delete this;
290}
291
292#endif
293
294// memory Stream
295
296memStream::memStream (uint8 *source, size_t sourceSize)
297{
298 mem = head = source;
299 msize = remaining = sourceSize;
300 readonly = false;
301}
302
303memStream::memStream (const uint8 *source, size_t sourceSize)
304{
305 mem = head = const_cast<uint8 *>(source);
306 msize = remaining = sourceSize;
307 readonly = true;
308}
309
310memStream::~memStream (void)
311{
312 return;
313}
314
315int memStream::get_char (void)
316{
317 if(!remaining)
318 return EOF;
319
320 remaining--;
321 return *head++;
322}
323
324char * 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
349size_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
359size_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
372size_t memStream::pos (void)
373{
374 return msize - remaining;
375}
376
377size_t memStream::size (void)
378{
379 return msize;
380}
381
382int 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
395void memStream::closeStream()
396{
397 delete [] mem;
398 delete this;
399}
400
401// dummy Stream
402
403nulStream::nulStream (void)
404{
405 bytes_written = 0;
406}
407
408nulStream::~nulStream (void)
409{
410 return;
411}
412
413int nulStream::get_char (void)
414{
415 return 0;
416}
417
418char * nulStream::gets (char *buf, size_t len)
419{
420 *buf = '\0';
421 return NULL;
422}
423
424size_t nulStream::read (void *buf, size_t len)
425{
426 return 0;
427}
428
429size_t nulStream::write (void *buf, size_t len)
430{
431 bytes_written += len;
432 return len;
433}
434
435size_t nulStream::pos (void)
436{
437 return 0;
438}
439
440size_t nulStream::size (void)
441{
442 return bytes_written;
443}
444
445int 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
452void nulStream::closeStream()
453{
454 delete this;
455}
456
457Stream *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
465Stream *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