Files
ppsspp/Core/ELF/ParamSFO.h
T
Henrik Rydgård 00939f76fc sceFont: Only require the fonts the running game's firmware could have
The disc-updater install ran when ltn0.pgf was missing, so a font set unpacked
from an old UMD looked complete forever, and a later game wanting a font its own
firmware added silently got a bundled substitute instead.

Requiring the whole registry doesn't work either: firmwares older than a font
can never satisfy it, so we'd unpack the same updater on every launch and
announce it each time. What settles it is that a game can't ask for a font that
didn't exist when it was made. Record the earliest firmware known to ship each
font in the registry, and only require the ones the running game's firmware
would have had.

The version comes from PARAM.SFO's PSP_SYSTEM_VER, with the bundled updater's
version as a fallback. That keeps the whole thing stateless - nothing recorded
that could go stale when flash0 or the ini gets moved around.

Survey of a large library, unpacking flash0:/font from each disc's updater
across firmware 1.50 to 6.60: jpn0 and ltn0..ltn15 are in every one of them, and
kr0.pgf is the only registry font that arrived later - absent in 1.50, present
from 1.52.

Uses one directory listing rather than a stat per font, since on Android's
scoped storage the individual checks are slow.
2026-09-05 09:36:26 -06:00

133 lines
3.7 KiB
C++

// Copyright (c) 2012- PPSSPP Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0 or later versions.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
#pragma once
#include <string_view>
#include <map>
#include <vector>
#include "Common/CommonTypes.h"
#include "Common/Log.h"
class Path;
class ParamSFOData {
public:
void SetValue(std::string_view key, unsigned int value, int max_size);
void SetValue(std::string_view key, std::string_view value, int max_size);
void SetValue(std::string_view key, const u8 *value, unsigned int size, int max_size);
int GetValueInt(std::string_view key) const;
std::string GetValueString(std::string_view key) const; // Common keys: "TITLE", "DISC_VERSION"
bool HasKey(std::string_view key) const;
const u8 *GetValueData(std::string_view key, unsigned int *size) const;
std::vector<std::string> GetKeys() const;
std::string GenerateFakeID(const Path &filename) const;
std::string GetDiscID();
// PSP_SYSTEM_VER, the firmware a disc says it needs, as major * 100 + minor - "2.60" gives
// 260, which sorts the way you'd want. Zero if the key is missing or unparseable; homebrew
// often leaves it out, but retail discs practically always set it.
int GetSystemVersion() const;
// The same conversion on its own, for versions that come from somewhere other than this SFO.
static int VersionToInt(std::string_view version);
// This allocates a buffer (*paramsfo) using new[], whose size is zero-filled up to a multiple of 16 bytes.
// This is required for SavedataParam::BuildHash.
void WriteSFO(u8 **paramsfo, size_t *size) const;
bool ReadSFO(const u8 *paramsfo, size_t size);
bool ReadSFO(const std::vector<u8> &paramsfo) {
if (!paramsfo.empty()) {
return ReadSFO(&paramsfo[0], paramsfo.size());
} else {
return false;
}
}
// If not found, returns a negative value.
int GetDataOffset(const u8 *paramsfo, size_t size, const char *dataName);
bool IsValid() const { return !values.empty(); }
void Clear();
enum ValueType {
VT_INT,
VT_UTF8,
VT_UTF8_SPE // raw data in u8
};
class ValueData {
public:
ValueType type = VT_INT;
int max_size = 0; // Is this meaningful for non-strings?
std::string s_value;
int i_value = 0;
std::vector<u8> u_value;
void SetData(const u8* data, int size) {
u_value = std::vector<u8>(data, data + size);
}
};
// ImDebugger access to the map.
const std::map<std::string, ValueData, std::less<>> &Values() {
return values;
}
static const char *ValueTypeToString(ValueType t) {
switch (t) {
case ParamSFOData::VT_INT: return "INT";
case ParamSFOData::VT_UTF8: return "UTF8";
case ParamSFOData::VT_UTF8_SPE: return "UTF8_SPE";
default: return "N/A";
}
}
private:
std::map<std::string, ValueData, std::less<>> values;
};
// Utilities for parsing the information.
// Guessed from GameID, not necessarily accurate
// Can't change the order of these.
enum class GameRegion {
JAPAN,
USA,
EUROPE,
HONGKONG,
ASIA,
KOREA,
COUNT,
HOMEBREW = COUNT,
UNKNOWN,
INTERNAL,
TEST,
DIAGNOSTIC,
FIRMWARE,
VSH,
};
GameRegion DetectGameRegionFromID(std::string_view id_version);
std::string_view GameRegionToString(GameRegion region); // These strings can be looked up I18NCat::GAME.