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