1 /* Copyright  (C) 2010-2018 The RetroArch team
2  *
3  * ---------------------------------------------------------------------------------------
4  * The following license statement only applies to this file (interface_stream.c).
5  * ---------------------------------------------------------------------------------------
6  *
7  * Permission is hereby granted, free of charge,
8  * to any person obtaining a copy of this software and associated documentation files (the "Software"),
9  * to deal in the Software without restriction, including without limitation the rights to
10  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
11  * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
16  * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
19  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21  */
22 
23 #include <stdlib.h>
24 
25 #include <streams/interface_stream.h>
26 #include <streams/file_stream.h>
27 #include <streams/memory_stream.h>
28 #ifdef HAVE_CHD
29 #include <streams/chd_stream.h>
30 #endif
31 
32 struct intfstream_internal
33 {
34    enum intfstream_type type;
35 
36    struct
37    {
38       RFILE *fp;
39    } file;
40 
41    struct
42    {
43       struct
44       {
45          uint8_t *data;
46          uint64_t size;
47       } buf;
48       memstream_t *fp;
49       bool writable;
50    } memory;
51 #ifdef HAVE_CHD
52    struct
53    {
54       int32_t track;
55       chdstream_t *fp;
56    } chd;
57 #endif
58 };
59 
intfstream_get_size(intfstream_internal_t * intf)60 int64_t intfstream_get_size(intfstream_internal_t *intf)
61 {
62    if (!intf)
63       return 0;
64 
65    switch (intf->type)
66    {
67       case INTFSTREAM_FILE:
68          return filestream_get_size(intf->file.fp);
69       case INTFSTREAM_MEMORY:
70          return intf->memory.buf.size;
71       case INTFSTREAM_CHD:
72 #ifdef HAVE_CHD
73         return chdstream_get_size(intf->chd.fp);
74 #else
75         break;
76 #endif
77    }
78 
79    return 0;
80 }
81 
intfstream_resize(intfstream_internal_t * intf,intfstream_info_t * info)82 bool intfstream_resize(intfstream_internal_t *intf, intfstream_info_t *info)
83 {
84    if (!intf || !info)
85       return false;
86 
87    switch (intf->type)
88    {
89       case INTFSTREAM_FILE:
90          break;
91       case INTFSTREAM_MEMORY:
92          intf->memory.buf.data = info->memory.buf.data;
93          intf->memory.buf.size = info->memory.buf.size;
94 
95          memstream_set_buffer(intf->memory.buf.data,
96                intf->memory.buf.size);
97          break;
98       case INTFSTREAM_CHD:
99 #ifdef HAVE_CHD
100 #endif
101          break;
102    }
103 
104    return true;
105 }
106 
intfstream_open(intfstream_internal_t * intf,const char * path,unsigned mode,unsigned hints)107 bool intfstream_open(intfstream_internal_t *intf, const char *path,
108       unsigned mode, unsigned hints)
109 {
110    if (!intf)
111       return false;
112 
113    switch (intf->type)
114    {
115       case INTFSTREAM_FILE:
116          intf->file.fp = filestream_open(path, mode, hints);
117          if (!intf->file.fp)
118             return false;
119          break;
120       case INTFSTREAM_MEMORY:
121          intf->memory.fp = memstream_open(intf->memory.writable);
122          if (!intf->memory.fp)
123             return false;
124          break;
125       case INTFSTREAM_CHD:
126 #ifdef HAVE_CHD
127          intf->chd.fp = chdstream_open(path, intf->chd.track);
128          if (!intf->chd.fp)
129             return false;
130          break;
131 #else
132          return false;
133 #endif
134    }
135 
136    return true;
137 }
138 
intfstream_flush(intfstream_internal_t * intf)139 int intfstream_flush(intfstream_internal_t *intf)
140 {
141    if (!intf)
142       return -1;
143 
144    switch (intf->type)
145    {
146       case INTFSTREAM_FILE:
147          return filestream_flush(intf->file.fp);
148       case INTFSTREAM_MEMORY:
149       case INTFSTREAM_CHD:
150          /* Should we stub this for these interfaces? */
151          break;
152    }
153 
154    return 0;
155 }
156 
intfstream_close(intfstream_internal_t * intf)157 int intfstream_close(intfstream_internal_t *intf)
158 {
159    if (!intf)
160       return -1;
161 
162    switch (intf->type)
163    {
164       case INTFSTREAM_FILE:
165          if (intf->file.fp)
166             return filestream_close(intf->file.fp);
167          return 0;
168       case INTFSTREAM_MEMORY:
169          if (intf->memory.fp)
170             memstream_close(intf->memory.fp);
171          return 0;
172       case INTFSTREAM_CHD:
173 #ifdef HAVE_CHD
174          if (intf->chd.fp)
175             chdstream_close(intf->chd.fp);
176 #endif
177          return 0;
178    }
179 
180    return -1;
181 }
182 
intfstream_init(intfstream_info_t * info)183 void *intfstream_init(intfstream_info_t *info)
184 {
185    intfstream_internal_t *intf = NULL;
186    if (!info)
187       goto error;
188 
189    intf = (intfstream_internal_t*)calloc(1, sizeof(*intf));
190 
191    if (!intf)
192       goto error;
193 
194    intf->type = info->type;
195 
196    switch (intf->type)
197    {
198       case INTFSTREAM_FILE:
199          break;
200       case INTFSTREAM_MEMORY:
201          intf->memory.writable = info->memory.writable;
202          if (!intfstream_resize(intf, info))
203             goto error;
204          break;
205       case INTFSTREAM_CHD:
206 #ifdef HAVE_CHD
207          intf->chd.track = info->chd.track;
208          break;
209 #else
210          goto error;
211 #endif
212    }
213 
214    return intf;
215 
216 error:
217    if (intf)
218       free(intf);
219    return NULL;
220 }
221 
intfstream_seek(intfstream_internal_t * intf,int64_t offset,int whence)222 int64_t intfstream_seek(intfstream_internal_t *intf, int64_t offset, int whence)
223 {
224    if (!intf)
225       return -1;
226 
227    switch (intf->type)
228    {
229       case INTFSTREAM_FILE:
230          {
231             int seek_position = 0;
232             switch (whence)
233             {
234                case SEEK_SET:
235                   seek_position = RETRO_VFS_SEEK_POSITION_START;
236                   break;
237                case SEEK_CUR:
238                   seek_position = RETRO_VFS_SEEK_POSITION_CURRENT;
239                   break;
240                case SEEK_END:
241                   seek_position = RETRO_VFS_SEEK_POSITION_END;
242                   break;
243             }
244             return (int64_t)filestream_seek(intf->file.fp, (int64_t)offset,
245                   seek_position);
246          }
247       case INTFSTREAM_MEMORY:
248          return (int64_t)memstream_seek(intf->memory.fp, offset, whence);
249       case INTFSTREAM_CHD:
250 #ifdef HAVE_CHD
251          return (int64_t)chdstream_seek(intf->chd.fp, offset, whence);
252 #else
253          break;
254 #endif
255    }
256 
257    return -1;
258 }
259 
intfstream_read(intfstream_internal_t * intf,void * s,uint64_t len)260 int64_t intfstream_read(intfstream_internal_t *intf, void *s, uint64_t len)
261 {
262    if (!intf)
263       return 0;
264 
265    switch (intf->type)
266    {
267       case INTFSTREAM_FILE:
268          return filestream_read(intf->file.fp, s, len);
269       case INTFSTREAM_MEMORY:
270          return memstream_read(intf->memory.fp, s, len);
271       case INTFSTREAM_CHD:
272 #ifdef HAVE_CHD
273          return chdstream_read(intf->chd.fp, s, len);
274 #else
275          break;
276 #endif
277    }
278 
279    return -1;
280 }
281 
intfstream_write(intfstream_internal_t * intf,const void * s,uint64_t len)282 int64_t intfstream_write(intfstream_internal_t *intf,
283       const void *s, uint64_t len)
284 {
285    if (!intf)
286       return 0;
287 
288    switch (intf->type)
289    {
290       case INTFSTREAM_FILE:
291          return filestream_write(intf->file.fp, s, len);
292       case INTFSTREAM_MEMORY:
293          return memstream_write(intf->memory.fp, s, len);
294       case INTFSTREAM_CHD:
295          return -1;
296    }
297 
298    return 0;
299 }
300 
intfstream_gets(intfstream_internal_t * intf,char * buffer,uint64_t len)301 char *intfstream_gets(intfstream_internal_t *intf,
302       char *buffer, uint64_t len)
303 {
304    if (!intf)
305       return NULL;
306 
307    switch (intf->type)
308    {
309       case INTFSTREAM_FILE:
310          return filestream_gets(intf->file.fp,
311                buffer, (size_t)len);
312       case INTFSTREAM_MEMORY:
313          return memstream_gets(intf->memory.fp,
314                buffer, (size_t)len);
315       case INTFSTREAM_CHD:
316 #ifdef HAVE_CHD
317          return chdstream_gets(intf->chd.fp, buffer, len);
318 #else
319          break;
320 #endif
321    }
322 
323    return NULL;
324 }
325 
intfstream_getc(intfstream_internal_t * intf)326 int intfstream_getc(intfstream_internal_t *intf)
327 {
328    if (!intf)
329       return -1;
330 
331    switch (intf->type)
332    {
333       case INTFSTREAM_FILE:
334          return filestream_getc(intf->file.fp);
335       case INTFSTREAM_MEMORY:
336          return memstream_getc(intf->memory.fp);
337       case INTFSTREAM_CHD:
338 #ifdef HAVE_CHD
339          return chdstream_getc(intf->chd.fp);
340 #else
341          break;
342 #endif
343    }
344 
345    return -1;
346 }
347 
intfstream_tell(intfstream_internal_t * intf)348 int64_t intfstream_tell(intfstream_internal_t *intf)
349 {
350    if (!intf)
351       return -1;
352 
353    switch (intf->type)
354    {
355       case INTFSTREAM_FILE:
356          return (int64_t)filestream_tell(intf->file.fp);
357       case INTFSTREAM_MEMORY:
358          return (int64_t)memstream_pos(intf->memory.fp);
359       case INTFSTREAM_CHD:
360 #ifdef HAVE_CHD
361          return (int64_t)chdstream_tell(intf->chd.fp);
362 #else
363          break;
364 #endif
365    }
366 
367    return -1;
368 }
369 
intfstream_rewind(intfstream_internal_t * intf)370 void intfstream_rewind(intfstream_internal_t *intf)
371 {
372    switch (intf->type)
373    {
374       case INTFSTREAM_FILE:
375          filestream_rewind(intf->file.fp);
376          break;
377       case INTFSTREAM_MEMORY:
378          memstream_rewind(intf->memory.fp);
379          break;
380       case INTFSTREAM_CHD:
381 #ifdef HAVE_CHD
382          chdstream_rewind(intf->chd.fp);
383 #endif
384          break;
385    }
386 }
387 
intfstream_putc(intfstream_internal_t * intf,int c)388 void intfstream_putc(intfstream_internal_t *intf, int c)
389 {
390    if (!intf)
391       return;
392 
393    switch (intf->type)
394    {
395       case INTFSTREAM_FILE:
396          filestream_putc(intf->file.fp, c);
397          break;
398       case INTFSTREAM_MEMORY:
399          memstream_putc(intf->memory.fp, c);
400          break;
401       case INTFSTREAM_CHD:
402          break;
403    }
404 }
405 
intfstream_open_file(const char * path,unsigned mode,unsigned hints)406 intfstream_t* intfstream_open_file(const char *path,
407       unsigned mode, unsigned hints)
408 {
409    intfstream_info_t info;
410    intfstream_t *fd = NULL;
411 
412    info.type        = INTFSTREAM_FILE;
413    fd               = (intfstream_t*)intfstream_init(&info);
414 
415    if (!fd)
416       return NULL;
417 
418    if (!intfstream_open(fd, path, mode, hints))
419       goto error;
420 
421    return fd;
422 
423 error:
424    if (fd)
425    {
426       intfstream_close(fd);
427       free(fd);
428    }
429    return NULL;
430 }
431 
intfstream_open_memory(void * data,unsigned mode,unsigned hints,uint64_t size)432 intfstream_t *intfstream_open_memory(void *data,
433       unsigned mode, unsigned hints, uint64_t size)
434 {
435    intfstream_info_t info;
436    intfstream_t *fd     = NULL;
437 
438    info.type            = INTFSTREAM_MEMORY;
439    info.memory.buf.data = (uint8_t*)data;
440    info.memory.buf.size = size;
441    info.memory.writable = false;
442 
443    fd                   = (intfstream_t*)intfstream_init(&info);
444 
445    if (!fd)
446       return NULL;
447 
448    if (!intfstream_open(fd, NULL, mode, hints))
449       goto error;
450 
451    return fd;
452 
453 error:
454    if (fd)
455    {
456       intfstream_close(fd);
457       free(fd);
458    }
459    return NULL;
460 }
461 
intfstream_open_chd_track(const char * path,unsigned mode,unsigned hints,int32_t track)462 intfstream_t *intfstream_open_chd_track(const char *path,
463       unsigned mode, unsigned hints, int32_t track)
464 {
465    intfstream_info_t info;
466    intfstream_t *fd = NULL;
467 
468    info.type        = INTFSTREAM_CHD;
469    info.chd.track   = track;
470 
471    fd               = (intfstream_t*)intfstream_init(&info);
472 
473    if (!fd)
474       return NULL;
475 
476    if (!intfstream_open(fd, path, mode, hints))
477       goto error;
478 
479    return fd;
480 
481 error:
482    if (fd)
483    {
484       intfstream_close(fd);
485       free(fd);
486    }
487    return NULL;
488 }
489