From 24bd43a53f0d16d03a6afd33e2c2e564709476f1 Mon Sep 17 00:00:00 2001
From: Brad Parker <cbparker@gmail.com>
Date: Sun, 30 Jun 2019 01:47:29 -0400
Subject: [PATCH] cdrom: improve position setting

---
 libretro-common/cdrom/cdrom.c                 |  6 +-
 libretro-common/include/cdrom/cdrom.h         |  5 +-
 .../include/vfs/vfs_implementation.h          |  1 +
 .../include/vfs/vfs_implementation_cdrom.h    |  3 +-
 libretro-common/vfs/vfs_implementation.c      |  8 +--
 .../vfs/vfs_implementation_cdrom.c            | 58 ++++++-------------
 6 files changed, 34 insertions(+), 47 deletions(-)

diff --git a/libretro-common/cdrom/cdrom.c b/libretro-common/cdrom/cdrom.c
index 8559a607b6..742e59c420 100644
--- a/libretro-common/cdrom/cdrom.c
+++ b/libretro-common/cdrom/cdrom.c
@@ -213,7 +213,9 @@ retry:
 #endif
    {
       rv = 0;
-      memcpy(buf, xfer_buf + skip, len);
+
+      if (buf)
+         memcpy(buf, xfer_buf + skip, len);
    }
    else
    {
@@ -516,6 +518,7 @@ int cdrom_write_cue(libretro_vfs_implementation_file *stream, char **out_buf, si
       unsigned char pmin = buf[4 + (i * 11) + 8];
       unsigned char psec = buf[4 + (i * 11) + 9];
       unsigned char pframe = buf[4 + (i * 11) + 10];
+      unsigned lba = msf_to_lba(pmin, psec, pframe);
 
       /*printf("i %d control %d adr %d tno %d point %d: ", i, control, adr, tno, point);*/
       /* why is control always 0? */
@@ -538,6 +541,7 @@ int cdrom_write_cue(libretro_vfs_implementation_file *stream, char **out_buf, si
          toc->track[point - 1].min = pmin;
          toc->track[point - 1].sec = psec;
          toc->track[point - 1].frame = pframe;
+         toc->track[point - 1].lba = lba;
          toc->track[point - 1].mode = mode;
          toc->track[point - 1].audio = audio;
 
diff --git a/libretro-common/include/cdrom/cdrom.h b/libretro-common/include/cdrom/cdrom.h
index df35c3c9c1..c751af5658 100644
--- a/libretro-common/include/cdrom/cdrom.h
+++ b/libretro-common/include/cdrom/cdrom.h
@@ -44,10 +44,11 @@ RETRO_BEGIN_DECLS
 
 typedef struct
 {
-   unsigned lba_start;
+   unsigned lba_start; /* start of pregap */
+   unsigned lba; /* start of data */
    unsigned track_size;
    unsigned char track_num;
-   unsigned char min;
+   unsigned char min; /* start of data */
    unsigned char sec;
    unsigned char frame;
    unsigned char mode;
diff --git a/libretro-common/include/vfs/vfs_implementation.h b/libretro-common/include/vfs/vfs_implementation.h
index 980ba5921f..9b69b7eb81 100644
--- a/libretro-common/include/vfs/vfs_implementation.h
+++ b/libretro-common/include/vfs/vfs_implementation.h
@@ -23,6 +23,7 @@
 #ifndef __LIBRETRO_SDK_VFS_IMPLEMENTATION_H
 #define __LIBRETRO_SDK_VFS_IMPLEMENTATION_H
 
+#include <stdio.h>
 #include <stdint.h>
 #include <libretro.h>
 
diff --git a/libretro-common/include/vfs/vfs_implementation_cdrom.h b/libretro-common/include/vfs/vfs_implementation_cdrom.h
index 0cd5d5fdda..9a91f26d33 100644
--- a/libretro-common/include/vfs/vfs_implementation_cdrom.h
+++ b/libretro-common/include/vfs/vfs_implementation_cdrom.h
@@ -33,12 +33,13 @@ typedef struct
 {
    char *cue_buf;
    size_t cue_len;
-   size_t byte_pos;
+   int64_t byte_pos;
    char drive;
    unsigned char cur_min;
    unsigned char cur_sec;
    unsigned char cur_frame;
    unsigned char cur_track;
+   unsigned cur_lba;
 } vfs_cdrom_t;
 
 #ifdef VFS_FRONTEND
diff --git a/libretro-common/vfs/vfs_implementation.c b/libretro-common/vfs/vfs_implementation.c
index 166aaea987..18dc470676 100644
--- a/libretro-common/vfs/vfs_implementation.c
+++ b/libretro-common/vfs/vfs_implementation.c
@@ -555,17 +555,17 @@ int retro_vfs_file_close_impl(libretro_vfs_implementation_file *stream)
       close(stream->fd);
 #endif
    }
+#ifdef HAVE_CDROM
 end:
+   if (stream->cdrom.cue_buf)
+      free(stream->cdrom.cue_buf);
+#endif
    if (stream->buf)
       free(stream->buf);
 
    if (stream->orig_path)
       free(stream->orig_path);
 
-#ifdef HAVE_CDROM
-   if (stream->cdrom.cue_buf)
-      free(stream->cdrom.cue_buf);
-#endif
    free(stream);
 
    return 0;
diff --git a/libretro-common/vfs/vfs_implementation_cdrom.c b/libretro-common/vfs/vfs_implementation_cdrom.c
index 8d36224523..40bcf3e871 100644
--- a/libretro-common/vfs/vfs_implementation_cdrom.c
+++ b/libretro-common/vfs/vfs_implementation_cdrom.c
@@ -24,6 +24,7 @@
 #include <file/file_path.h>
 #include <compat/fopen_utf8.h>
 #include <string/stdstring.h>
+#include <cdrom/cdrom.h>
 
 #ifdef _WIN32
 #include <windows.h>
@@ -62,7 +63,7 @@ int64_t retro_vfs_file_seek_cdrom(libretro_vfs_implementation_file *stream, int6
    }
    else if (string_is_equal_noncase(ext, "bin"))
    {
-      unsigned frames = (offset / 2352);
+      int lba = (offset / 2352);
       unsigned char min = 0;
       unsigned char sec = 0;
       unsigned char frame = 0;
@@ -70,33 +71,25 @@ int64_t retro_vfs_file_seek_cdrom(libretro_vfs_implementation_file *stream, int6
 
       (void)seek_type;
 
-      lba_to_msf(frames, &min, &sec, &frame);
-
       switch (whence)
       {
          case SEEK_CUR:
          {
-            min += stream->cdrom.cur_min;
-            sec += stream->cdrom.cur_sec;
-            frame += stream->cdrom.cur_frame;
+            unsigned new_lba;
 
             stream->cdrom.byte_pos += offset;
+            new_lba = vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].lba + (stream->cdrom.byte_pos / 2352);
             seek_type = "SEEK_CUR";
 
+            lba_to_msf(new_lba, &min, &sec, &frame);
+
             break;
          }
          case SEEK_END:
          {
-            unsigned char end_min = 0;
-            unsigned char end_sec = 0;
-            unsigned char end_frame = 0;
-            size_t end_lba = (vfs_cdrom_toc.track[vfs_cdrom_toc.num_tracks - 1].lba_start + vfs_cdrom_toc.track[vfs_cdrom_toc.num_tracks - 1].track_size) - 1;
+            ssize_t end_lba = (vfs_cdrom_toc.track[vfs_cdrom_toc.num_tracks - 1].lba_start + vfs_cdrom_toc.track[vfs_cdrom_toc.num_tracks - 1].track_size) - 1;
 
-            lba_to_msf(end_lba, &min, &sec, &frame);
-
-            min += end_min;
-            sec += end_sec;
-            frame += end_frame;
+            lba_to_msf(end_lba + lba, &min, &sec, &frame);
 
             stream->cdrom.byte_pos = end_lba * 2352;
             seek_type = "SEEK_END";
@@ -108,7 +101,7 @@ int64_t retro_vfs_file_seek_cdrom(libretro_vfs_implementation_file *stream, int6
          {
             seek_type = "SEEK_SET";
             stream->cdrom.byte_pos = offset;
-
+            lba_to_msf(vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].lba + (stream->cdrom.byte_pos / 2352), &min, &sec, &frame);
             break;
          }
       }
@@ -116,9 +109,10 @@ int64_t retro_vfs_file_seek_cdrom(libretro_vfs_implementation_file *stream, int6
       stream->cdrom.cur_min = min;
       stream->cdrom.cur_sec = sec;
       stream->cdrom.cur_frame = frame;
+      stream->cdrom.cur_lba = msf_to_lba(min, sec, frame);
 
 #ifdef CDROM_DEBUG
-      printf("CDROM Seek %s: Path %s Offset %" PRIu64 " is now at %" PRIu64 " (MSF %02d:%02d:%02d) (LBA %u)...\n", seek_type, stream->orig_path, offset, stream->cdrom.byte_pos, stream->cdrom.cur_min, stream->cdrom.cur_sec, stream->cdrom.cur_frame, msf_to_lba(stream->cdrom.cur_min, stream->cdrom.cur_sec, stream->cdrom.cur_frame));
+      printf("CDROM Seek %s: Path %s Offset %" PRIu64 " is now at %" PRIu64 " (MSF %02d:%02d:%02d) (LBA %u)...\n", seek_type, stream->orig_path, offset, stream->cdrom.byte_pos, stream->cdrom.cur_min, stream->cdrom.cur_sec, stream->cdrom.cur_frame, stream->cdrom.cur_lba);
       fflush(stdout);
 #endif
    }
@@ -298,12 +292,14 @@ void retro_vfs_file_open_cdrom(
       stream->cdrom.cur_min = vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].min;
       stream->cdrom.cur_sec = vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].sec;
       stream->cdrom.cur_frame = vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].frame;
+      stream->cdrom.cur_lba = msf_to_lba(stream->cdrom.cur_min, stream->cdrom.cur_sec, stream->cdrom.cur_frame);
    }
    else
    {
       stream->cdrom.cur_min = vfs_cdrom_toc.track[0].min;
       stream->cdrom.cur_sec = vfs_cdrom_toc.track[0].sec;
       stream->cdrom.cur_frame = vfs_cdrom_toc.track[0].frame;
+      stream->cdrom.cur_lba = msf_to_lba(stream->cdrom.cur_min, stream->cdrom.cur_sec, stream->cdrom.cur_frame);
    }
 }
 
@@ -342,13 +338,11 @@ int64_t retro_vfs_file_tell_cdrom(libretro_vfs_implementation_file *stream)
    }
    else if (string_is_equal_noncase(ext, "bin"))
    {
-      unsigned lba = msf_to_lba(stream->cdrom.cur_min, stream->cdrom.cur_sec, stream->cdrom.cur_frame);
-
 #ifdef CDROM_DEBUG
-      printf("CDROM (bin) Tell: Path %s Position %u\n", stream->orig_path, lba * 2352);
+      printf("CDROM (bin) Tell: Path %s Position %" PRId64 "\n", stream->orig_path, stream->cdrom.byte_pos);
       fflush(stdout);
 #endif
-      return lba * 2352;
+      return stream->cdrom.byte_pos;
    }
 
    return -1;
@@ -384,26 +378,15 @@ int64_t retro_vfs_file_read_cdrom(libretro_vfs_implementation_file *stream,
    }
    else if (string_is_equal_noncase(ext, "bin"))
    {
-      unsigned frames = len / 2352;
-      unsigned i;
       size_t skip = stream->cdrom.byte_pos % 2352;
       unsigned char min = 0;
       unsigned char sec = 0;
       unsigned char frame = 0;
-      unsigned lba_cur = 0;
-      unsigned lba_start = 0;
 
-      lba_cur = msf_to_lba(stream->cdrom.cur_min, stream->cdrom.cur_sec, stream->cdrom.cur_frame);
-
-      if (vfs_cdrom_toc.num_tracks > 1 && stream->cdrom.cur_track)
-         lba_start = msf_to_lba(vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].min, vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].sec, vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].frame);
-      else
-         lba_start = msf_to_lba(vfs_cdrom_toc.track[0].min, vfs_cdrom_toc.track[0].sec, vfs_cdrom_toc.track[0].frame);
-
-      lba_to_msf(lba_start + lba_cur, &min, &sec, &frame);
+      lba_to_msf(stream->cdrom.cur_lba, &min, &sec, &frame);
 
 #ifdef CDROM_DEBUG
-      printf("CDROM Read: Reading %" PRIu64 " bytes from %s starting at byte offset %" PRIu64 " (MSF %02d:%02d:%02d) (LBA %u) skip %" PRIu64 "...\n", len, stream->orig_path, stream->cdrom.byte_pos, min, sec, frame, msf_to_lba(min, sec, frame), skip);
+      printf("CDROM Read: Reading %" PRIu64 " bytes from %s starting at byte offset %" PRIu64 " (MSF %02d:%02d:%02d) (LBA %u) skip %" PRIu64 "...\n", len, stream->orig_path, stream->cdrom.byte_pos, min, sec, frame, stream->cdrom.cur_lba, skip);
       fflush(stdout);
 #endif
 
@@ -419,11 +402,8 @@ int64_t retro_vfs_file_read_cdrom(libretro_vfs_implementation_file *stream,
       }
 
       stream->cdrom.byte_pos += len;
-
-      for (i = 0; i < frames; i++)
-      {
-         increment_msf(&stream->cdrom.cur_min, &stream->cdrom.cur_sec, &stream->cdrom.cur_frame);
-      }
+      stream->cdrom.cur_lba = vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].lba + (stream->cdrom.byte_pos / 2352);
+      lba_to_msf(stream->cdrom.cur_lba, &stream->cdrom.cur_min, &stream->cdrom.cur_sec, &stream->cdrom.cur_frame);
 
 #ifdef CDROM_DEBUG
       printf("CDROM read %" PRIu64 " bytes, position is now: %" PRIu64 " (MSF %02d:%02d:%02d) (LBA %u)\n", len, stream->cdrom.byte_pos, stream->cdrom.cur_min, stream->cdrom.cur_sec, stream->cdrom.cur_frame, msf_to_lba(stream->cdrom.cur_min, stream->cdrom.cur_sec, stream->cdrom.cur_frame));