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