libretro: adjust psxclock description
[pcsx_rearmed.git] / deps / libretro-common / streams / interface_stream.c
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
36 struct 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
69 int64_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
97 bool 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
125 bool 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
166 int 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
185 int 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
217 void *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
264 error:
265    if (intf)
266       free(intf);
267    return NULL;
268 }
269
270 int64_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
312 int64_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
340 int64_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
365 int 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
399 int64_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
419 char *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
450 int 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
478 int64_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
506 int 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
534 void 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
557 void 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
581 uint32_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
594 uint32_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
607 uint32_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
620 bool 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
644 bool 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
670 intfstream_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
687 error:
688    if (fd)
689    {
690       intfstream_close(fd);
691       free(fd);
692    }
693    return NULL;
694 }
695
696 intfstream_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
716 error:
717    if (fd)
718    {
719       intfstream_close(fd);
720       free(fd);
721    }
722    return NULL;
723 }
724
725 intfstream_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
745 error:
746    if (fd)
747    {
748       intfstream_close(fd);
749       free(fd);
750    }
751    return NULL;
752 }
753
754 intfstream_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
773 error:
774    if (fd)
775    {
776       intfstream_close(fd);
777       free(fd);
778    }
779    return NULL;
780 }
781
782 intfstream_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
799 error:
800    if (fd)
801    {
802       intfstream_close(fd);
803       free(fd);
804    }
805    return NULL;
806 }