Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
stenzek
GitHub Repository: stenzek/duckstation
Path: blob/master/src/util/cd_image_memory.cpp
7342 views
1
// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <[email protected]>
2
// SPDX-License-Identifier: CC-BY-NC-ND-4.0
3
4
#include "cd_image.h"
5
6
#include "common/assert.h"
7
#include "common/error.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_CHANNEL(CDImage);
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, Error* error);
26
27
bool IsPrecached() const override;
28
29
protected:
30
bool ReadSectorFromIndex(void* buffer, const Index& index, LBA lba_in_index) override;
31
32
private:
33
u8* m_memory = nullptr;
34
u32 m_memory_sectors = 0;
35
};
36
37
} // namespace
38
39
CDImageMemory::CDImageMemory() = default;
40
41
CDImageMemory::~CDImageMemory()
42
{
43
if (m_memory)
44
std::free(m_memory);
45
}
46
47
bool CDImageMemory::CopyImage(CDImage* image, ProgressCallback* progress, Error* error)
48
{
49
// figure out the total number of sectors (not including blank pregaps)
50
m_memory_sectors = 0;
51
for (u32 i = 0; i < image->GetIndexCount(); i++)
52
{
53
const Index& index = image->GetIndex(i);
54
if (index.file_sector_size > 0)
55
m_memory_sectors += image->GetIndex(i).length;
56
}
57
58
if (m_memory_sectors == 0 || (static_cast<u64>(RAW_SECTOR_SIZE) * static_cast<u64>(m_memory_sectors)) >=
59
static_cast<u64>(std::numeric_limits<size_t>::max()))
60
{
61
Error::SetStringView(error, "Insufficient address space");
62
return false;
63
}
64
65
progress->FormatStatusText("Allocating memory for {} sectors...", m_memory_sectors);
66
67
m_memory =
68
static_cast<u8*>(std::malloc(static_cast<size_t>(RAW_SECTOR_SIZE) * static_cast<size_t>(m_memory_sectors)));
69
if (!m_memory)
70
{
71
Error::SetStringFmt(error, "Failed to allocate memory for {} sectors", m_memory_sectors);
72
return false;
73
}
74
75
progress->SetTitle("Preloading CD image to RAM...");
76
progress->SetProgressRange(m_memory_sectors);
77
progress->SetProgressValue(0);
78
79
u8* memory_ptr = m_memory;
80
u32 sectors_read = 0;
81
for (u32 i = 0; i < image->GetIndexCount(); i++)
82
{
83
const Index& index = image->GetIndex(i);
84
if (index.file_sector_size == 0)
85
continue;
86
87
for (u32 lba = 0; lba < index.length; lba++)
88
{
89
if (!image->ReadSectorFromIndex(memory_ptr, index, lba))
90
{
91
ERROR_LOG("Failed to read LBA {} in index {}", lba, i);
92
return false;
93
}
94
95
progress->SetProgressValue(sectors_read);
96
memory_ptr += RAW_SECTOR_SIZE;
97
sectors_read++;
98
}
99
}
100
101
for (u32 i = 1; i <= image->GetTrackCount(); i++)
102
m_tracks.push_back(image->GetTrack(i));
103
104
u32 current_offset = 0;
105
for (u32 i = 0; i < image->GetIndexCount(); i++)
106
{
107
Index new_index = image->GetIndex(i);
108
new_index.file_index = 0;
109
if (new_index.file_sector_size > 0)
110
{
111
new_index.file_offset = current_offset;
112
current_offset += new_index.length;
113
}
114
m_indices.push_back(new_index);
115
}
116
117
Assert(current_offset == m_memory_sectors);
118
m_filename = image->GetPath();
119
m_lba_count = image->GetLBACount();
120
121
return Seek(1, Position{0, 0, 0});
122
}
123
124
bool CDImageMemory::IsPrecached() const
125
{
126
return true;
127
}
128
129
bool CDImageMemory::ReadSectorFromIndex(void* buffer, const Index& index, LBA lba_in_index)
130
{
131
DebugAssert(index.file_index == 0);
132
133
const u64 sector_number = index.file_offset + lba_in_index;
134
if (sector_number >= m_memory_sectors)
135
return false;
136
137
const size_t file_offset = static_cast<size_t>(sector_number) * static_cast<size_t>(RAW_SECTOR_SIZE);
138
std::memcpy(buffer, &m_memory[file_offset], RAW_SECTOR_SIZE);
139
return true;
140
}
141
142
std::unique_ptr<CDImage> CDImage::CreateMemoryImage(CDImage* image, ProgressCallback* progress, Error* error)
143
{
144
std::unique_ptr<CDImageMemory> memory_image = std::make_unique<CDImageMemory>();
145
if (!memory_image->CopyImage(image, progress, error))
146
return {};
147
148
return memory_image;
149
}
150
151