duckstation

duckstation, but archived from the revision just before upstream changed it to a proprietary software project, this version is the libre one
git clone https://git.neptards.moe/u3shit/duckstation.git
Log | Files | Refs | README | LICENSE

cd_image_bin.cpp (4307B)


      1 // SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
      2 // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
      3 
      4 #include "cd_image.h"
      5 #include "cd_subchannel_replacement.h"
      6 
      7 #include "common/error.h"
      8 #include "common/file_system.h"
      9 #include "common/path.h"
     10 
     11 namespace {
     12 
     13 class CDImageBin : public CDImage
     14 {
     15 public:
     16   CDImageBin();
     17   ~CDImageBin() override;
     18 
     19   bool Open(const char* filename, Error* error);
     20 
     21   bool ReadSubChannelQ(SubChannelQ* subq, const Index& index, LBA lba_in_index) override;
     22   bool HasNonStandardSubchannel() const override;
     23 
     24   s64 GetSizeOnDisk() const override;
     25 
     26 protected:
     27   bool ReadSectorFromIndex(void* buffer, const Index& index, LBA lba_in_index) override;
     28 
     29 private:
     30   std::FILE* m_fp = nullptr;
     31   u64 m_file_position = 0;
     32 
     33   CDSubChannelReplacement m_sbi;
     34 };
     35 
     36 } // namespace
     37 
     38 CDImageBin::CDImageBin() = default;
     39 
     40 CDImageBin::~CDImageBin()
     41 {
     42   if (m_fp)
     43     std::fclose(m_fp);
     44 }
     45 
     46 bool CDImageBin::Open(const char* filename, Error* error)
     47 {
     48   m_filename = filename;
     49   m_fp = FileSystem::OpenSharedCFile(filename, "rb", FileSystem::FileShareMode::DenyWrite, error);
     50   if (!m_fp)
     51   {
     52     Error::AddPrefixFmt(error, "Failed to open binfile '{}': ", Path::GetFileName(filename));
     53     return false;
     54   }
     55 
     56   const u32 track_sector_size = RAW_SECTOR_SIZE;
     57 
     58   // determine the length from the file
     59   std::fseek(m_fp, 0, SEEK_END);
     60   const u32 file_size = static_cast<u32>(std::ftell(m_fp));
     61   std::fseek(m_fp, 0, SEEK_SET);
     62 
     63   m_lba_count = file_size / track_sector_size;
     64 
     65   SubChannelQ::Control control = {};
     66   TrackMode mode = TrackMode::Mode2Raw;
     67   control.data = mode != TrackMode::Audio;
     68 
     69   // Two seconds default pregap.
     70   const u32 pregap_frames = 2 * FRAMES_PER_SECOND;
     71   Index pregap_index = {};
     72   pregap_index.file_sector_size = track_sector_size;
     73   pregap_index.start_lba_on_disc = 0;
     74   pregap_index.start_lba_in_track = static_cast<LBA>(-static_cast<s32>(pregap_frames));
     75   pregap_index.length = pregap_frames;
     76   pregap_index.track_number = 1;
     77   pregap_index.index_number = 0;
     78   pregap_index.mode = mode;
     79   pregap_index.submode = CDImage::SubchannelMode::None;
     80   pregap_index.control.bits = control.bits;
     81   pregap_index.is_pregap = true;
     82   m_indices.push_back(pregap_index);
     83 
     84   // Data index.
     85   Index data_index = {};
     86   data_index.file_index = 0;
     87   data_index.file_offset = 0;
     88   data_index.file_sector_size = track_sector_size;
     89   data_index.start_lba_on_disc = pregap_index.length;
     90   data_index.track_number = 1;
     91   data_index.index_number = 1;
     92   data_index.start_lba_in_track = 0;
     93   data_index.length = m_lba_count;
     94   data_index.mode = mode;
     95   data_index.submode = CDImage::SubchannelMode::None;
     96   data_index.control.bits = control.bits;
     97   m_indices.push_back(data_index);
     98 
     99   // Assume a single track.
    100   m_tracks.push_back(Track{static_cast<u32>(1), data_index.start_lba_on_disc, static_cast<u32>(0), m_lba_count, mode,
    101                            SubchannelMode::None, control});
    102 
    103   AddLeadOutIndex();
    104 
    105   m_sbi.LoadFromImagePath(filename);
    106 
    107   return Seek(1, Position{0, 0, 0});
    108 }
    109 
    110 bool CDImageBin::ReadSubChannelQ(SubChannelQ* subq, const Index& index, LBA lba_in_index)
    111 {
    112   if (m_sbi.GetReplacementSubChannelQ(index.start_lba_on_disc + lba_in_index, subq))
    113     return true;
    114 
    115   return CDImage::ReadSubChannelQ(subq, index, lba_in_index);
    116 }
    117 
    118 bool CDImageBin::HasNonStandardSubchannel() const
    119 {
    120   return (m_sbi.GetReplacementSectorCount() > 0);
    121 }
    122 
    123 bool CDImageBin::ReadSectorFromIndex(void* buffer, const Index& index, LBA lba_in_index)
    124 {
    125   const u64 file_position = index.file_offset + (static_cast<u64>(lba_in_index) * index.file_sector_size);
    126   if (m_file_position != file_position)
    127   {
    128     if (std::fseek(m_fp, static_cast<long>(file_position), SEEK_SET) != 0)
    129       return false;
    130 
    131     m_file_position = file_position;
    132   }
    133 
    134   if (std::fread(buffer, index.file_sector_size, 1, m_fp) != 1)
    135   {
    136     std::fseek(m_fp, static_cast<long>(m_file_position), SEEK_SET);
    137     return false;
    138   }
    139 
    140   m_file_position += index.file_sector_size;
    141   return true;
    142 }
    143 
    144 s64 CDImageBin::GetSizeOnDisk() const
    145 {
    146   return FileSystem::FSize64(m_fp);
    147 }
    148 
    149 std::unique_ptr<CDImage> CDImage::OpenBinImage(const char* filename, Error* error)
    150 {
    151   std::unique_ptr<CDImageBin> image = std::make_unique<CDImageBin>();
    152   if (!image->Open(filename, error))
    153     return {};
    154 
    155   return image;
    156 }