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_memory.cpp (4521B)


      1 // SPDX-FileCopyrightText: 2019-2023 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/assert.h"
      8 #include "common/file_system.h"
      9 #include "common/log.h"
     10 #include "common/path.h"
     11 
     12 #include <algorithm>
     13 #include <cerrno>
     14 
     15 Log_SetChannel(CDImageMemory);
     16 
     17 namespace {
     18 
     19 class CDImageMemory : public CDImage
     20 {
     21 public:
     22   CDImageMemory();
     23   ~CDImageMemory() override;
     24 
     25   bool CopyImage(CDImage* image, ProgressCallback* progress);
     26 
     27   bool ReadSubChannelQ(SubChannelQ* subq, const Index& index, LBA lba_in_index) override;
     28   bool HasNonStandardSubchannel() const override;
     29 
     30   bool IsPrecached() const override;
     31 
     32 protected:
     33   bool ReadSectorFromIndex(void* buffer, const Index& index, LBA lba_in_index) override;
     34 
     35 private:
     36   u8* m_memory = nullptr;
     37   u32 m_memory_sectors = 0;
     38   CDSubChannelReplacement m_sbi;
     39 };
     40 
     41 } // namespace
     42 
     43 CDImageMemory::CDImageMemory() = default;
     44 
     45 CDImageMemory::~CDImageMemory()
     46 {
     47   if (m_memory)
     48     std::free(m_memory);
     49 }
     50 
     51 bool CDImageMemory::CopyImage(CDImage* image, ProgressCallback* progress)
     52 {
     53   // figure out the total number of sectors (not including blank pregaps)
     54   m_memory_sectors = 0;
     55   for (u32 i = 0; i < image->GetIndexCount(); i++)
     56   {
     57     const Index& index = image->GetIndex(i);
     58     if (index.file_sector_size > 0)
     59       m_memory_sectors += image->GetIndex(i).length;
     60   }
     61 
     62   if ((static_cast<u64>(RAW_SECTOR_SIZE) * static_cast<u64>(m_memory_sectors)) >=
     63       static_cast<u64>(std::numeric_limits<size_t>::max()))
     64   {
     65     progress->ModalError("Insufficient address space");
     66     return false;
     67   }
     68 
     69   progress->FormatStatusText("Allocating memory for {} sectors...", m_memory_sectors);
     70 
     71   m_memory =
     72     static_cast<u8*>(std::malloc(static_cast<size_t>(RAW_SECTOR_SIZE) * static_cast<size_t>(m_memory_sectors)));
     73   if (!m_memory)
     74   {
     75     progress->FormatModalError("Failed to allocate memory for {} sectors", m_memory_sectors);
     76     return false;
     77   }
     78 
     79   progress->SetStatusText("Preloading CD image to RAM...");
     80   progress->SetProgressRange(m_memory_sectors);
     81   progress->SetProgressValue(0);
     82 
     83   u8* memory_ptr = m_memory;
     84   u32 sectors_read = 0;
     85   for (u32 i = 0; i < image->GetIndexCount(); i++)
     86   {
     87     const Index& index = image->GetIndex(i);
     88     if (index.file_sector_size == 0)
     89       continue;
     90 
     91     for (u32 lba = 0; lba < index.length; lba++)
     92     {
     93       if (!image->ReadSectorFromIndex(memory_ptr, index, lba))
     94       {
     95         ERROR_LOG("Failed to read LBA {} in index {}", lba, i);
     96         return false;
     97       }
     98 
     99       progress->SetProgressValue(sectors_read);
    100       memory_ptr += RAW_SECTOR_SIZE;
    101       sectors_read++;
    102     }
    103   }
    104 
    105   for (u32 i = 1; i <= image->GetTrackCount(); i++)
    106     m_tracks.push_back(image->GetTrack(i));
    107 
    108   u32 current_offset = 0;
    109   for (u32 i = 0; i < image->GetIndexCount(); i++)
    110   {
    111     Index new_index = image->GetIndex(i);
    112     new_index.file_index = 0;
    113     if (new_index.file_sector_size > 0)
    114     {
    115       new_index.file_offset = current_offset;
    116       current_offset += new_index.length;
    117     }
    118     m_indices.push_back(new_index);
    119   }
    120 
    121   Assert(current_offset == m_memory_sectors);
    122   m_filename = image->GetFileName();
    123   m_lba_count = image->GetLBACount();
    124 
    125   m_sbi.LoadFromImagePath(m_filename);
    126 
    127   return Seek(1, Position{0, 0, 0});
    128 }
    129 
    130 bool CDImageMemory::ReadSubChannelQ(SubChannelQ* subq, const Index& index, LBA lba_in_index)
    131 {
    132   if (m_sbi.GetReplacementSubChannelQ(index.start_lba_on_disc + lba_in_index, subq))
    133     return true;
    134 
    135   return CDImage::ReadSubChannelQ(subq, index, lba_in_index);
    136 }
    137 
    138 bool CDImageMemory::HasNonStandardSubchannel() const
    139 {
    140   return (m_sbi.GetReplacementSectorCount() > 0);
    141 }
    142 
    143 bool CDImageMemory::IsPrecached() const
    144 {
    145   return true;
    146 }
    147 
    148 bool CDImageMemory::ReadSectorFromIndex(void* buffer, const Index& index, LBA lba_in_index)
    149 {
    150   DebugAssert(index.file_index == 0);
    151 
    152   const u64 sector_number = index.file_offset + lba_in_index;
    153   if (sector_number >= m_memory_sectors)
    154     return false;
    155 
    156   const size_t file_offset = static_cast<size_t>(sector_number) * static_cast<size_t>(RAW_SECTOR_SIZE);
    157   std::memcpy(buffer, &m_memory[file_offset], RAW_SECTOR_SIZE);
    158   return true;
    159 }
    160 
    161 std::unique_ptr<CDImage>
    162 CDImage::CreateMemoryImage(CDImage* image, ProgressCallback* progress /* = ProgressCallback::NullProgressCallback */)
    163 {
    164   std::unique_ptr<CDImageMemory> memory_image = std::make_unique<CDImageMemory>();
    165   if (!memory_image->CopyImage(image, progress))
    166     return {};
    167 
    168   return memory_image;
    169 }