| 157 | } |
| 158 | |
| 159 | static std::vector<uint8_t> ExtractExFont(Filesystem_Stream::InputStream& corefile, uint32_t position, uint32_t len) { |
| 160 | std::vector<uint8_t> exfont; |
| 161 | constexpr int header_size = 14; // Size of BITMAPFILEHEADER |
| 162 | exfont.resize(len + header_size); |
| 163 | |
| 164 | corefile.seekg(position, std::ios_base::beg); |
| 165 | corefile.read(reinterpret_cast<char*>(exfont.data()) + header_size, len); |
| 166 | if (corefile.gcount() != len) { |
| 167 | Output::Debug("EXEReader: ExFont: Error reading resource (read {}, expected {})", corefile.gcount(), len); |
| 168 | return {}; |
| 169 | } |
| 170 | |
| 171 | auto* exfont_data = reinterpret_cast<const uint8_t*>(exfont.data()) + header_size; |
| 172 | auto* e = exfont_data + len; |
| 173 | auto header = ImageBMP::ParseHeader(exfont_data, e); |
| 174 | |
| 175 | // As it turns out, EXFONTs appear to operate on all the same restrictions as an ordinary BMP. |
| 176 | // Bitmap resources lack the BITMAPFILEHEADER. This header must be generated based on the BITMAPINFOHEADER. |
| 177 | // And the header that's going to be prepended. |
| 178 | int header_len = header_size + header.size; |
| 179 | if (header.depth != 8) { |
| 180 | Output::Debug("EXEReader: ExFont: Unsupported depth {}", header.depth); |
| 181 | return {}; |
| 182 | } |
| 183 | header_len += header.num_colors * 4; |
| 184 | |
| 185 | // 0 (these are in decimal) |
| 186 | int pos = 0; |
| 187 | exfont[pos++] = 'B'; |
| 188 | exfont[pos++] = 'M'; |
| 189 | // 2 |
| 190 | uint32_t totallen = exfont.size(); |
| 191 | exfont[pos++] = (totallen) & 0xFF; |
| 192 | exfont[pos++] = (totallen >> 8) & 0xFF; |
| 193 | exfont[pos++] = (totallen >> 16) & 0xFF; |
| 194 | exfont[pos++] = (totallen >> 24) & 0xFF; |
| 195 | // 6 - Reserved data |
| 196 | exfont[pos++] = 'E'; |
| 197 | exfont[pos++] = 'x'; |
| 198 | exfont[pos++] = 'F'; |
| 199 | exfont[pos++] = 'n'; |
| 200 | // 10 |
| 201 | exfont[pos++] = (header_len) & 0xFF; |
| 202 | exfont[pos++] = (header_len >> 8) & 0xFF; |
| 203 | exfont[pos++] = (header_len >> 16) & 0xFF; |
| 204 | exfont[pos++] = (header_len >> 24) & 0xFF; |
| 205 | |
| 206 | // Check if the ExFont is the original through a fast hash function |
| 207 | auto crc = crc32(0, exfont.data() + header_size, exfont.size() - header_size); |
| 208 | if (crc != 0x86bc6c68) { |
| 209 | Output::Debug("EXEReader: Custom ExFont found"); |
| 210 | } |
| 211 | return exfont; |
| 212 | } |
| 213 | |
| 214 | static uint32_t exe_reader_roffset(uint32_t bas, uint32_t ofs) { |
| 215 | return bas + (ofs ^ 0x80000000); |