1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
|
// Copyright 2016 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include "core/hle/service/apt/bcfnt/bcfnt.h"
#include "core/hle/service/service.h"
namespace Service::APT::BCFNT {
void RelocateSharedFont(std::shared_ptr<Kernel::SharedMemory> shared_font, VAddr new_address) {
static const u32 SharedFontStartOffset = 0x80;
const u8* cfnt_ptr = shared_font->GetPointer(SharedFontStartOffset);
CFNT cfnt;
std::memcpy(&cfnt, cfnt_ptr, sizeof(cfnt));
u32 assumed_cmap_offset = 0;
u32 assumed_cwdh_offset = 0;
u32 assumed_tglp_offset = 0;
u32 first_cmap_offset = 0;
u32 first_cwdh_offset = 0;
u32 first_tglp_offset = 0;
// First discover the location of sections so that the rebase offset can be auto-detected
u32 current_offset = SharedFontStartOffset + cfnt.header_size;
for (unsigned block = 0; block < cfnt.num_blocks; ++block) {
const u8* data = shared_font->GetPointer(current_offset);
SectionHeader section_header;
std::memcpy(§ion_header, data, sizeof(section_header));
if (first_cmap_offset == 0 && std::memcmp(section_header.magic, "CMAP", 4) == 0) {
first_cmap_offset = current_offset;
} else if (first_cwdh_offset == 0 && std::memcmp(section_header.magic, "CWDH", 4) == 0) {
first_cwdh_offset = current_offset;
} else if (first_tglp_offset == 0 && std::memcmp(section_header.magic, "TGLP", 4) == 0) {
first_tglp_offset = current_offset;
} else if (std::memcmp(section_header.magic, "FINF", 4) == 0) {
BCFNT::FINF finf;
std::memcpy(&finf, data, sizeof(finf));
assumed_cmap_offset = finf.cmap_offset - sizeof(SectionHeader);
assumed_cwdh_offset = finf.cwdh_offset - sizeof(SectionHeader);
assumed_tglp_offset = finf.tglp_offset - sizeof(SectionHeader);
}
current_offset += section_header.section_size;
}
u32 previous_base = assumed_cmap_offset - first_cmap_offset;
ASSERT(previous_base == assumed_cwdh_offset - first_cwdh_offset);
ASSERT(previous_base == assumed_tglp_offset - first_tglp_offset);
u32 offset = new_address - previous_base;
// Reset pointer back to start of sections and do the actual rebase
current_offset = SharedFontStartOffset + cfnt.header_size;
for (unsigned block = 0; block < cfnt.num_blocks; ++block) {
u8* data = shared_font->GetPointer(current_offset);
SectionHeader section_header;
std::memcpy(§ion_header, data, sizeof(section_header));
if (std::memcmp(section_header.magic, "FINF", 4) == 0) {
BCFNT::FINF finf;
std::memcpy(&finf, data, sizeof(finf));
// Relocate the offsets in the FINF section
finf.cmap_offset += offset;
finf.cwdh_offset += offset;
finf.tglp_offset += offset;
std::memcpy(data, &finf, sizeof(finf));
} else if (std::memcmp(section_header.magic, "CMAP", 4) == 0) {
BCFNT::CMAP cmap;
std::memcpy(&cmap, data, sizeof(cmap));
// Relocate the offsets in the CMAP section
if (cmap.next_cmap_offset != 0)
cmap.next_cmap_offset += offset;
std::memcpy(data, &cmap, sizeof(cmap));
} else if (std::memcmp(section_header.magic, "CWDH", 4) == 0) {
BCFNT::CWDH cwdh;
std::memcpy(&cwdh, data, sizeof(cwdh));
// Relocate the offsets in the CWDH section
if (cwdh.next_cwdh_offset != 0)
cwdh.next_cwdh_offset += offset;
std::memcpy(data, &cwdh, sizeof(cwdh));
} else if (std::memcmp(section_header.magic, "TGLP", 4) == 0) {
BCFNT::TGLP tglp;
std::memcpy(&tglp, data, sizeof(tglp));
// Relocate the offsets in the TGLP section
tglp.sheet_data_offset += offset;
std::memcpy(data, &tglp, sizeof(tglp));
}
current_offset += section_header.section_size;
}
}
} // namespace Service::APT::BCFNT
|