1 // Copyright 2019 Dolphin Emulator Project
2 // Licensed under GPLv2+
3 // Refer to the license.txt file included.
4
5 #include "Core/HW/GCMemcard/GCIFile.h"
6
7 #include <cinttypes>
8
9 #include "Common/ChunkFile.h"
10 #include "Common/CommonTypes.h"
11 #include "Common/File.h"
12 #include "Common/Logging/Log.h"
13
14 namespace Memcard
15 {
LoadHeader()16 bool GCIFile::LoadHeader()
17 {
18 if (m_filename.empty())
19 return false;
20
21 File::IOFile save_file(m_filename, "rb");
22 if (!save_file)
23 return false;
24
25 INFO_LOG(EXPANSIONINTERFACE, "Reading header from disk for %s", m_filename.c_str());
26 if (!save_file.ReadBytes(&m_gci_header, sizeof(m_gci_header)))
27 {
28 ERROR_LOG(EXPANSIONINTERFACE, "Failed to read header for %s", m_filename.c_str());
29 return false;
30 }
31
32 return true;
33 }
34
LoadSaveBlocks()35 bool GCIFile::LoadSaveBlocks()
36 {
37 if (m_save_data.empty())
38 {
39 if (m_filename.empty())
40 return false;
41
42 File::IOFile save_file(m_filename, "rb");
43 if (!save_file)
44 return false;
45
46 INFO_LOG(EXPANSIONINTERFACE, "Reading savedata from disk for %s", m_filename.c_str());
47 u16 num_blocks = m_gci_header.m_block_count;
48
49 const u32 size = num_blocks * BLOCK_SIZE;
50 u64 file_size = save_file.GetSize();
51 if (file_size != size + DENTRY_SIZE)
52 {
53 ERROR_LOG(EXPANSIONINTERFACE,
54 "%s\nwas not loaded because it is an invalid GCI.\n File size (0x%" PRIx64
55 ") does not match the size recorded in the header (0x%x)",
56 m_filename.c_str(), file_size, size + DENTRY_SIZE);
57 return false;
58 }
59
60 m_save_data.resize(num_blocks);
61 save_file.Seek(DENTRY_SIZE, SEEK_SET);
62 if (!save_file.ReadBytes(m_save_data.data(), size))
63 {
64 ERROR_LOG(EXPANSIONINTERFACE, "Failed to read data from GCI file %s", m_filename.c_str());
65 m_save_data.clear();
66 return false;
67 }
68 }
69 return true;
70 }
71
HasCopyProtection() const72 bool GCIFile::HasCopyProtection() const
73 {
74 if ((strcmp(reinterpret_cast<const char*>(m_gci_header.m_filename.data()), "PSO_SYSTEM") == 0) ||
75 (strcmp(reinterpret_cast<const char*>(m_gci_header.m_filename.data()), "PSO3_SYSTEM") == 0) ||
76 (strcmp(reinterpret_cast<const char*>(m_gci_header.m_filename.data()), "f_zero.dat") == 0))
77 return true;
78 return false;
79 }
80
UsesBlock(u16 block_num)81 int GCIFile::UsesBlock(u16 block_num)
82 {
83 for (u16 i = 0; i < m_used_blocks.size(); ++i)
84 {
85 if (m_used_blocks[i] == block_num)
86 return i;
87 }
88 return -1;
89 }
90
DoState(PointerWrap & p)91 void GCIFile::DoState(PointerWrap& p)
92 {
93 p.DoPOD<DEntry>(m_gci_header);
94 p.Do(m_dirty);
95 p.Do(m_filename);
96 int num_blocks = (int)m_save_data.size();
97 p.Do(num_blocks);
98 m_save_data.resize(num_blocks);
99 for (auto itr = m_save_data.begin(); itr != m_save_data.end(); ++itr)
100 {
101 p.DoPOD<GCMBlock>(*itr);
102 }
103 p.Do(m_used_blocks);
104 }
105 } // namespace Memcard
106