libretro: adjust psxclock description
[pcsx_rearmed.git] / deps / libretro-common / streams / interface_stream.c
CommitLineData
3719602c
PC
1/* Copyright (C) 2010-2020 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#if defined(HAVE_ZLIB)
32#include <streams/rzip_stream.h>
33#endif
34#include <encodings/crc32.h>
35
36struct intfstream_internal
37{
38 struct
39 {
40 RFILE *fp;
41 } file;
42
43 struct
44 {
45 memstream_t *fp;
46 struct
47 {
48 uint8_t *data;
49 uint64_t size;
50 } buf;
51 bool writable;
52 } memory;
53#ifdef HAVE_CHD
54 struct
55 {
56 chdstream_t *fp;
57 int32_t track;
58 } chd;
59#endif
60#if defined(HAVE_ZLIB)
61 struct
62 {
63 rzipstream_t *fp;
64 } rzip;
65#endif
66 enum intfstream_type type;
67};
68
69int64_t intfstream_get_size(intfstream_internal_t *intf)
70{
71 if (!intf)
72 return 0;
73
74 switch (intf->type)
75 {
76 case INTFSTREAM_FILE:
77 return filestream_get_size(intf->file.fp);
78 case INTFSTREAM_MEMORY:
79 return intf->memory.buf.size;
80 case INTFSTREAM_CHD:
81#ifdef HAVE_CHD
82 return chdstream_get_size(intf->chd.fp);
83#else
84 break;
85#endif
86 case INTFSTREAM_RZIP:
87#if defined(HAVE_ZLIB)
88 return rzipstream_get_size(intf->rzip.fp);
89#else
90 break;
91#endif
92 }
93
94 return 0;
95}
96
97bool intfstream_resize(intfstream_internal_t *intf, intfstream_info_t *info)
98{
99 if (!intf || !info)
100 return false;
101
102 switch (intf->type)
103 {
104 case INTFSTREAM_FILE:
105 break;
106 case INTFSTREAM_MEMORY:
107 intf->memory.buf.data = info->memory.buf.data;
108 intf->memory.buf.size = info->memory.buf.size;
109
110 memstream_set_buffer(intf->memory.buf.data,
111 intf->memory.buf.size);
112 break;
113 case INTFSTREAM_CHD:
114#ifdef HAVE_CHD
115#endif
116 break;
117 case INTFSTREAM_RZIP:
118 /* Unsupported */
119 return false;
120 }
121
122 return true;
123}
124
125bool intfstream_open(intfstream_internal_t *intf, const char *path,
126 unsigned mode, unsigned hints)
127{
128 if (!intf)
129 return false;
130
131 switch (intf->type)
132 {
133 case INTFSTREAM_FILE:
134 intf->file.fp = filestream_open(path, mode, hints);
135 if (!intf->file.fp)
136 return false;
137 break;
138 case INTFSTREAM_MEMORY:
139 intf->memory.fp = memstream_open(intf->memory.writable);
140 if (!intf->memory.fp)
141 return false;
142 break;
143 case INTFSTREAM_CHD:
144#ifdef HAVE_CHD
145 intf->chd.fp = chdstream_open(path, intf->chd.track);
146 if (!intf->chd.fp)
147 return false;
148 break;
149#else
150 return false;
151#endif
152 case INTFSTREAM_RZIP:
153#if defined(HAVE_ZLIB)
154 intf->rzip.fp = rzipstream_open(path, mode);
155 if (!intf->rzip.fp)
156 return false;
157 break;
158#else
159 return false;
160#endif
161 }
162
163 return true;
164}
165
166int intfstream_flush(intfstream_internal_t *intf)
167{
168 if (!intf)
169 return -1;
170
171 switch (intf->type)
172 {
173 case INTFSTREAM_FILE:
174 return filestream_flush(intf->file.fp);
175 case INTFSTREAM_MEMORY:
176 case INTFSTREAM_CHD:
177 case INTFSTREAM_RZIP:
178 /* Should we stub this for these interfaces? */
179 break;
180 }
181
182 return 0;
183}
184
185int intfstream_close(intfstream_internal_t *intf)
186{
187 if (!intf)
188 return -1;
189
190 switch (intf->type)
191 {
192 case INTFSTREAM_FILE:
193 if (intf->file.fp)
194 return filestream_close(intf->file.fp);
195 return 0;
196 case INTFSTREAM_MEMORY:
197 if (intf->memory.fp)
198 memstream_close(intf->memory.fp);
199 return 0;
200 case INTFSTREAM_CHD:
201#ifdef HAVE_CHD
202 if (intf->chd.fp)
203 chdstream_close(intf->chd.fp);
204#endif
205 return 0;
206 case INTFSTREAM_RZIP:
207#if defined(HAVE_ZLIB)
208 if (intf->rzip.fp)
209 return rzipstream_close(intf->rzip.fp);
210#endif
211 return 0;
212 }
213
214 return -1;
215}
216
217void *intfstream_init(intfstream_info_t *info)
218{
219 intfstream_internal_t *intf = NULL;
220 if (!info)
221 goto error;
222
223 intf = (intfstream_internal_t*)malloc(sizeof(*intf));
224
225 if (!intf)
226 goto error;
227
228 intf->type = info->type;
229 intf->file.fp = NULL;
230 intf->memory.buf.data = NULL;
231 intf->memory.buf.size = 0;
232 intf->memory.fp = NULL;
233 intf->memory.writable = false;
234#ifdef HAVE_CHD
235 intf->chd.track = 0;
236 intf->chd.fp = NULL;
237#endif
238#ifdef HAVE_ZLIB
239 intf->rzip.fp = NULL;
240#endif
241
242 switch (intf->type)
243 {
244 case INTFSTREAM_FILE:
245 break;
246 case INTFSTREAM_MEMORY:
247 intf->memory.writable = info->memory.writable;
248 if (!intfstream_resize(intf, info))
249 goto error;
250 break;
251 case INTFSTREAM_CHD:
252#ifdef HAVE_CHD
253 intf->chd.track = info->chd.track;
254 break;
255#else
256 goto error;
257#endif
258 case INTFSTREAM_RZIP:
259 break;
260 }
261
262 return intf;
263
264error:
265 if (intf)
266 free(intf);
267 return NULL;
268}
269
270int64_t intfstream_seek(
271 intfstream_internal_t *intf, int64_t offset, int whence)
272{
273 if (!intf)
274 return -1;
275
276 switch (intf->type)
277 {
278 case INTFSTREAM_FILE:
279 {
280 int seek_position = 0;
281 switch (whence)
282 {
283 case SEEK_SET:
284 seek_position = RETRO_VFS_SEEK_POSITION_START;
285 break;
286 case SEEK_CUR:
287 seek_position = RETRO_VFS_SEEK_POSITION_CURRENT;
288 break;
289 case SEEK_END:
290 seek_position = RETRO_VFS_SEEK_POSITION_END;
291 break;
292 }
293 return (int64_t)filestream_seek(intf->file.fp, (int64_t)offset,
294 seek_position);
295 }
296 case INTFSTREAM_MEMORY:
297 return (int64_t)memstream_seek(intf->memory.fp, offset, whence);
298 case INTFSTREAM_CHD:
299#ifdef HAVE_CHD
300 return (int64_t)chdstream_seek(intf->chd.fp, offset, whence);
301#else
302 break;
303#endif
304 case INTFSTREAM_RZIP:
305 /* Unsupported */
306 break;
307 }
308
309 return -1;
310}
311
312int64_t intfstream_read(intfstream_internal_t *intf, void *s, uint64_t len)
313{
314 if (!intf)
315 return 0;
316
317 switch (intf->type)
318 {
319 case INTFSTREAM_FILE:
320 return filestream_read(intf->file.fp, s, len);
321 case INTFSTREAM_MEMORY:
322 return memstream_read(intf->memory.fp, s, len);
323 case INTFSTREAM_CHD:
324#ifdef HAVE_CHD
325 return chdstream_read(intf->chd.fp, s, len);
326#else
327 break;
328#endif
329 case INTFSTREAM_RZIP:
330#if defined(HAVE_ZLIB)
331 return rzipstream_read(intf->rzip.fp, s, len);
332#else
333 break;
334#endif
335 }
336
337 return -1;
338}
339
340int64_t intfstream_write(intfstream_internal_t *intf,
341 const void *s, uint64_t len)
342{
343 if (!intf)
344 return 0;
345
346 switch (intf->type)
347 {
348 case INTFSTREAM_FILE:
349 return filestream_write(intf->file.fp, s, len);
350 case INTFSTREAM_MEMORY:
351 return memstream_write(intf->memory.fp, s, len);
352 case INTFSTREAM_CHD:
353 return -1;
354 case INTFSTREAM_RZIP:
355#if defined(HAVE_ZLIB)
356 return rzipstream_write(intf->rzip.fp, s, len);
357#else
358 return -1;
359#endif
360 }
361
362 return 0;
363}
364
365int intfstream_printf(intfstream_internal_t *intf,
366 const char* format, ...)
367{
368 va_list vl;
369 int result;
370
371 if (!intf)
372 return 0;
373
374 switch (intf->type)
375 {
376 case INTFSTREAM_FILE:
377 va_start(vl, format);
378 result = filestream_vprintf(intf->file.fp, format, vl);
379 va_end(vl);
380 return result;
381 case INTFSTREAM_MEMORY:
382 return -1;
383 case INTFSTREAM_CHD:
384 return -1;
385 case INTFSTREAM_RZIP:
386#if defined(HAVE_ZLIB)
387 va_start(vl, format);
388 result = rzipstream_vprintf(intf->rzip.fp, format, vl);
389 va_end(vl);
390 return result;
391#else
392 return -1;
393#endif
394 }
395
396 return 0;
397}
398
399int64_t intfstream_get_ptr(intfstream_internal_t* intf)
400{
401 if (!intf)
402 return 0;
403
404 switch (intf->type)
405 {
406 case INTFSTREAM_FILE:
407 return -1;
408 case INTFSTREAM_MEMORY:
409 return memstream_get_ptr(intf->memory.fp);
410 case INTFSTREAM_CHD:
411 return -1;
412 case INTFSTREAM_RZIP:
413 return -1;
414 }
415
416 return 0;
417}
418
419char *intfstream_gets(intfstream_internal_t *intf,
420 char *buffer, uint64_t len)
421{
422 if (!intf)
423 return NULL;
424
425 switch (intf->type)
426 {
427 case INTFSTREAM_FILE:
428 return filestream_gets(intf->file.fp,
429 buffer, (size_t)len);
430 case INTFSTREAM_MEMORY:
431 return memstream_gets(intf->memory.fp,
432 buffer, (size_t)len);
433 case INTFSTREAM_CHD:
434#ifdef HAVE_CHD
435 return chdstream_gets(intf->chd.fp, buffer, len);
436#else
437 break;
438#endif
439 case INTFSTREAM_RZIP:
440#if defined(HAVE_ZLIB)
441 return rzipstream_gets(intf->rzip.fp, buffer, (size_t)len);
442#else
443 break;
444#endif
445 }
446
447 return NULL;
448}
449
450int intfstream_getc(intfstream_internal_t *intf)
451{
452 if (!intf)
453 return -1;
454
455 switch (intf->type)
456 {
457 case INTFSTREAM_FILE:
458 return filestream_getc(intf->file.fp);
459 case INTFSTREAM_MEMORY:
460 return memstream_getc(intf->memory.fp);
461 case INTFSTREAM_CHD:
462#ifdef HAVE_CHD
463 return chdstream_getc(intf->chd.fp);
464#else
465 break;
466#endif
467 case INTFSTREAM_RZIP:
468#if defined(HAVE_ZLIB)
469 return rzipstream_getc(intf->rzip.fp);
470#else
471 break;
472#endif
473 }
474
475 return -1;
476}
477
478int64_t intfstream_tell(intfstream_internal_t *intf)
479{
480 if (!intf)
481 return -1;
482
483 switch (intf->type)
484 {
485 case INTFSTREAM_FILE:
486 return (int64_t)filestream_tell(intf->file.fp);
487 case INTFSTREAM_MEMORY:
488 return (int64_t)memstream_pos(intf->memory.fp);
489 case INTFSTREAM_CHD:
490#ifdef HAVE_CHD
491 return (int64_t)chdstream_tell(intf->chd.fp);
492#else
493 break;
494#endif
495 case INTFSTREAM_RZIP:
496#if defined(HAVE_ZLIB)
497 return (int64_t)rzipstream_tell(intf->rzip.fp);
498#else
499 break;
500#endif
501 }
502
503 return -1;
504}
505
506int intfstream_eof(intfstream_internal_t *intf)
507{
508 if (!intf)
509 return -1;
510
511 switch (intf->type)
512 {
513 case INTFSTREAM_FILE:
514 return filestream_eof(intf->file.fp);
515 case INTFSTREAM_MEMORY:
516 /* TODO: Add this functionality to
517 * memory_stream interface */
518 break;
519 case INTFSTREAM_CHD:
520 /* TODO: Add this functionality to
521 * chd_stream interface */
522 break;
523 case INTFSTREAM_RZIP:
524#if defined(HAVE_ZLIB)
525 return rzipstream_eof(intf->rzip.fp);
526#else
527 break;
528#endif
529 }
530
531 return -1;
532}
533
534void intfstream_rewind(intfstream_internal_t *intf)
535{
536 switch (intf->type)
537 {
538 case INTFSTREAM_FILE:
539 filestream_rewind(intf->file.fp);
540 break;
541 case INTFSTREAM_MEMORY:
542 memstream_rewind(intf->memory.fp);
543 break;
544 case INTFSTREAM_CHD:
545#ifdef HAVE_CHD
546 chdstream_rewind(intf->chd.fp);
547#endif
548 break;
549 case INTFSTREAM_RZIP:
550#if defined(HAVE_ZLIB)
551 rzipstream_rewind(intf->rzip.fp);
552#endif
553 break;
554 }
555}
556
557void intfstream_putc(intfstream_internal_t *intf, int c)
558{
559 if (!intf)
560 return;
561
562 switch (intf->type)
563 {
564 case INTFSTREAM_FILE:
565 filestream_putc(intf->file.fp, c);
566 break;
567 case INTFSTREAM_MEMORY:
568 memstream_putc(intf->memory.fp, c);
569 break;
570 case INTFSTREAM_CHD:
571 break;
572 case INTFSTREAM_RZIP:
573#if defined(HAVE_ZLIB)
574 rzipstream_putc(intf->rzip.fp, c);
575#else
576 break;
577#endif
578 }
579}
580
581uint32_t intfstream_get_offset_to_start(intfstream_internal_t *intf)
582{
583 if (intf)
584 {
585#ifdef HAVE_CHD
586 if (intf->type == INTFSTREAM_CHD)
587 return chdstream_get_track_start(intf->chd.fp);
588#endif
589 }
590
591 return 0;
592}
593
594uint32_t intfstream_get_frame_size(intfstream_internal_t *intf)
595{
596 if (intf)
597 {
598#ifdef HAVE_CHD
599 if (intf->type == INTFSTREAM_CHD)
600 return chdstream_get_frame_size(intf->chd.fp);
601#endif
602 }
603
604 return 0;
605}
606
607uint32_t intfstream_get_first_sector(intfstream_internal_t* intf)
608{
609 if (intf)
610 {
611#ifdef HAVE_CHD
612 if (intf->type == INTFSTREAM_CHD)
613 return chdstream_get_first_track_sector(intf->chd.fp);
614#endif
615 }
616
617 return 0;
618}
619
620bool intfstream_is_compressed(intfstream_internal_t *intf)
621{
622 if (!intf)
623 return false;
624
625 switch (intf->type)
626 {
627 case INTFSTREAM_FILE:
628 return false;
629 case INTFSTREAM_MEMORY:
630 return false;
631 case INTFSTREAM_CHD:
632 return true;
633 case INTFSTREAM_RZIP:
634#if defined(HAVE_ZLIB)
635 return rzipstream_is_compressed(intf->rzip.fp);
636#else
637 break;
638#endif
639 }
640
641 return false;
642}
643
644bool intfstream_get_crc(intfstream_internal_t *intf, uint32_t *crc)
645{
646 int64_t data_read = 0;
647 uint32_t accumulator = 0;
648 uint8_t buffer[4096];
649
650 if (!intf || !crc)
651 return false;
652
653 /* Ensure we start at the beginning of the file */
654 intfstream_rewind(intf);
655
656 while ((data_read = intfstream_read(intf, buffer, sizeof(buffer))) > 0)
657 accumulator = encoding_crc32(accumulator, buffer, (size_t)data_read);
658
659 if (data_read < 0)
660 return false;
661
662 *crc = accumulator;
663
664 /* Reset file to the beginning */
665 intfstream_rewind(intf);
666
667 return true;
668}
669
670intfstream_t* intfstream_open_file(const char *path,
671 unsigned mode, unsigned hints)
672{
673 intfstream_info_t info;
674 intfstream_t *fd = NULL;
675
676 info.type = INTFSTREAM_FILE;
677 fd = (intfstream_t*)intfstream_init(&info);
678
679 if (!fd)
680 return NULL;
681
682 if (!intfstream_open(fd, path, mode, hints))
683 goto error;
684
685 return fd;
686
687error:
688 if (fd)
689 {
690 intfstream_close(fd);
691 free(fd);
692 }
693 return NULL;
694}
695
696intfstream_t *intfstream_open_memory(void *data,
697 unsigned mode, unsigned hints, uint64_t size)
698{
699 intfstream_info_t info;
700 intfstream_t *fd = NULL;
701
702 info.type = INTFSTREAM_MEMORY;
703 info.memory.buf.data = (uint8_t*)data;
704 info.memory.buf.size = size;
705 info.memory.writable = false;
706
707 fd = (intfstream_t*)intfstream_init(&info);
708 if (!fd)
709 return NULL;
710
711 if (!intfstream_open(fd, NULL, mode, hints))
712 goto error;
713
714 return fd;
715
716error:
717 if (fd)
718 {
719 intfstream_close(fd);
720 free(fd);
721 }
722 return NULL;
723}
724
725intfstream_t *intfstream_open_writable_memory(void *data,
726 unsigned mode, unsigned hints, uint64_t size)
727{
728 intfstream_info_t info;
729 intfstream_t *fd = NULL;
730
731 info.type = INTFSTREAM_MEMORY;
732 info.memory.buf.data = (uint8_t*)data;
733 info.memory.buf.size = size;
734 info.memory.writable = true;
735
736 fd = (intfstream_t*)intfstream_init(&info);
737 if (!fd)
738 return NULL;
739
740 if (!intfstream_open(fd, NULL, mode, hints))
741 goto error;
742
743 return fd;
744
745error:
746 if (fd)
747 {
748 intfstream_close(fd);
749 free(fd);
750 }
751 return NULL;
752}
753
754intfstream_t *intfstream_open_chd_track(const char *path,
755 unsigned mode, unsigned hints, int32_t track)
756{
757 intfstream_info_t info;
758 intfstream_t *fd = NULL;
759
760 info.type = INTFSTREAM_CHD;
761 info.chd.track = track;
762
763 fd = (intfstream_t*)intfstream_init(&info);
764
765 if (!fd)
766 return NULL;
767
768 if (!intfstream_open(fd, path, mode, hints))
769 goto error;
770
771 return fd;
772
773error:
774 if (fd)
775 {
776 intfstream_close(fd);
777 free(fd);
778 }
779 return NULL;
780}
781
782intfstream_t* intfstream_open_rzip_file(const char *path,
783 unsigned mode)
784{
785 intfstream_info_t info;
786 intfstream_t *fd = NULL;
787
788 info.type = INTFSTREAM_RZIP;
789 fd = (intfstream_t*)intfstream_init(&info);
790
791 if (!fd)
792 return NULL;
793
794 if (!intfstream_open(fd, path, mode, RETRO_VFS_FILE_ACCESS_HINT_NONE))
795 goto error;
796
797 return fd;
798
799error:
800 if (fd)
801 {
802 intfstream_close(fd);
803 free(fd);
804 }
805 return NULL;
806}