Fix Title_ID parsing/rendering to use the correct format.

This also updates the rendering of the Version Flag.

All retail Xbox Games use a title_id of this format:
XX-000

Where XX = Publisher code (MS, EA, etc) and 000 = Game Number by that
publisher.

This can be used to properly uniquely identify games, and even
cross-reference with the Redump database that uses the same Serial No.
format.

Additionally, this PR also fixes Version field rendering, to be in the
correct 1.XX format.

This is useful because the combination of Title_ID and Version No
uniquely identifies games!

Even in regional varients where the title_id doesn't change, the version
number does!

Some special XBEs (like Dashboard, updaters, XDK samples) use
non-printable characters in the title_id/serial number field, so we
fallback to Hex in this case
This commit is contained in:
Luke Usher 2018-06-14 09:44:35 +01:00
parent 4760872a03
commit 9b6fe04096
5 changed files with 36 additions and 11 deletions

View File

@ -42,6 +42,8 @@
#include <sstream> // For std::stringstream
#include <iomanip> // For std::setfill, std::uppercase, std::hex
extern std::string FormatTitleId(uint32_t title_id); // Exposed in Emu.cpp
// better time
static char *BetterTime(uint32 x_timeDate)
{
@ -315,7 +317,7 @@ std::string XbePrinter::GenCertificateHeader()
text << "Dumping XBE Certificate...\n\n";
text << "Size of Certificate : 0x" << std::setw(8) << Xbe_certificate->dwSize << "\n";
text << "TimeDate Stamp : 0x" << std::setw(8) << Xbe_certificate->dwTimeDate << " (" << BetterTime(Xbe_certificate->dwTimeDate) << ")\n";
text << "Title ID : 0x" << std::setw(8) << Xbe_certificate->dwTitleId << "\n";
text << "Title ID : " << FormatTitleId(Xbe_certificate->dwTitleId) << "\n";
text << "Title : L\"" << Xbe_to_print->m_szAsciiTitle << "\"\n";
return text.str();
}
@ -347,7 +349,7 @@ std::string XbePrinter::GenMediaInfo()
text << "Game Region : 0x" << std::setw(8) << Xbe_certificate->dwGameRegion << " (" << Xbe_to_print->GameRegionToString() << ")\n";
text << "Game Ratings : 0x" << std::setw(8) << Xbe_certificate->dwGameRatings << " (" << GameRatingToString() << ")\n";
text << "Disk Number : 0x" << std::setw(8) << Xbe_certificate->dwDiskNumber << "\n";
text << "Version : 0x" << std::setw(8) << Xbe_certificate->dwVersion << "\n";
text << "Version : 1." << std::dec << std::setw(2) << Xbe_certificate->dwVersion << "\n";
return text.str();
}

View File

@ -1318,8 +1318,6 @@ __declspec(noreturn) void CxbxKrnlInit
std::string xbeDirectory(szBuffer);
CxbxBasePathHandle = CreateFile(CxbxBasePath.c_str(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
memset(szBuffer, 0, MAX_PATH);
sprintf(szBuffer, "%08X", g_pCertificate->dwTitleId);
std::string titleId(szBuffer);
// Games may assume they are running from CdRom :
CxbxDefaultXbeDriveIndex = CxbxRegisterDeviceHostPath(DeviceCdrom0, xbeDirectory);
// Partition 0 contains configuration data, and is accessed as a native file, instead as a folder :
@ -1375,7 +1373,8 @@ __declspec(noreturn) void CxbxKrnlInit
// Dump Xbe certificate
if (g_pCertificate != NULL) {
printf("[0x%.4X] INIT: XBE TitleID : %.8X\n", GetCurrentThreadId(), g_pCertificate->dwTitleId);
printf("[0x%.4X] INIT: XBE TitleID : %s\n", GetCurrentThreadId(), FormatTitleId(g_pCertificate->dwTitleId).c_str());
printf("[0x%.4X] INIT: XBE Version : 1.%02d\n", GetCurrentThreadId(), g_pCertificate->dwVersion);
printf("[0x%.4X] INIT: XBE TitleName : %ls\n", GetCurrentThreadId(), g_pCertificate->wszTitleName);
printf("[0x%.4X] INIT: XBE Region : %s\n", GetCurrentThreadId(), CxbxKrnl_Xbe->GameRegionToString());
}

View File

@ -75,7 +75,32 @@ bool g_DirectHostBackBufferAccess = false;
LARGE_INTEGER HostSystemTimeDelta = {};
// Static Function(s)
static int ExitException(LPEXCEPTION_POINTERS e);
static int ExitException(LPEXCEPTION_POINTERS e);
std::string FormatTitleId(uint32_t title_id)
{
std::stringstream ss;
// If the Title ID prefix is a printable character, parse it
// This shows the correct game serial number for retail titles!
// EG: MS-001 for 1st tile published by MS, EA-002 for 2nd title by EA, etc
// Some special Xbes (Dashboard, XDK Samples) use non-alphanumeric serials
// We fall back to Hex for those
char pTitleId1 = (title_id >> 24) & 0xFF;
char pTitleId2 = (title_id >> 16) & 0xFF;
if (isalnum(pTitleId1) && isalnum(pTitleId2)) {
ss << pTitleId1 << pTitleId2;
} else {
// Prefix was non-printable, so we need to print a hex reprentation
ss << "0x" << std::setfill('0') << std::setw(4) << std::hex << std::uppercase << (uint16_t)((title_id & 0xFFFF0000) >> 16);
}
ss << "-";
ss << std::setfill('0') << std::setw(3) << std::dec << (title_id & 0x0000FFFF);
return ss.str();
}
// print out a warning message to the kernel debug log file
#ifdef _DEBUG_WARNINGS

View File

@ -45,7 +45,9 @@
void NTAPI EmuWarning(const char *szWarningMessage, ...);
#else
inline void NTAPI EmuWarning(const char *szWarningMessage, ...) { }
#endif
#endif
std::string FormatTitleId(uint32_t title_id);
// exception handler
extern int EmuException(LPEXCEPTION_POINTERS e);

View File

@ -574,10 +574,7 @@ void EmuHLEIntercept(Xbe::Header *pXbeHeader)
// Write the Certificate Details to the cache file
WritePrivateProfileString("Certificate", "Name", tAsciiTitle, filename.c_str());
std::stringstream titleId;
titleId << std::hex << g_pCertificate->dwTitleId;
WritePrivateProfileString("Certificate", "TitleID", titleId.str().c_str(), filename.c_str());
WritePrivateProfileString("Certificate", "TitleID", FormatTitleId(g_pCertificate->dwTitleId).c_str(), filename.c_str());
std::stringstream region;
region << std::hex << g_pCertificate->dwGameRegion;