Cheat System: Rearchitect the system for loading cheat database files in preparation for adding new features to the database file presentation. Also do a bunch of code cleanup and fix multiple bugs.
- The file description is no longer limited to 16 characters. - Folder notes are now included in the description strings of exported cheat items. These can be important for cheats that include operating instructions in their associated folder notes. - Fix a bug where reading the last game entry of the database file would fail. - Fix a potential bug where reading a game entry from an encrypted database file would fail if the initial entry data resides very close to a 512-byte boundary. - Fix a bug where deleting a CHEATSEXPORT object without calling CHEATSEXPORT.close() would result in its associated file remaining open. - Fix a bug where deleting a CHEATSEXPORT object without calling CHEATSEXPORT.close() would result in CHEATSEXPORT.cheats leaking memory.
This commit is contained in:
parent
50f02ae172
commit
0c90e8f4e3
File diff suppressed because it is too large
Load Diff
|
@ -24,10 +24,8 @@
|
|||
|
||||
#define CHEAT_VERSION_MAJOR 2
|
||||
#define CHEAT_VERSION_MINOR 0
|
||||
#define MAX_CHEAT_LIST 100
|
||||
#define MAX_XX_CODE 1024
|
||||
#define CHEAT_FILE_MIN_FGETS_BUFFER 32768
|
||||
#define CHEAT_DB_GAME_TITLE_SIZE 256
|
||||
|
||||
#define CHEAT_TYPE_EMPTY 0xFF
|
||||
#define CHEAT_TYPE_INTERNAL 0
|
||||
|
@ -39,7 +37,7 @@ struct CHEATS_LIST
|
|||
CHEATS_LIST()
|
||||
{
|
||||
memset(this,0,sizeof(*this));
|
||||
type = 0xFF;
|
||||
type = CHEAT_TYPE_EMPTY;
|
||||
}
|
||||
u8 type;
|
||||
u8 enabled;
|
||||
|
@ -48,7 +46,18 @@ struct CHEATS_LIST
|
|||
// 1 - can decrease
|
||||
// 2 - can increase
|
||||
u32 code[MAX_XX_CODE][2];
|
||||
char description[1024];
|
||||
|
||||
union
|
||||
{
|
||||
char description[1024];
|
||||
|
||||
struct
|
||||
{
|
||||
char descriptionMajor[512];
|
||||
char descriptionMinor[512];
|
||||
};
|
||||
};
|
||||
|
||||
u32 num;
|
||||
u8 size;
|
||||
};
|
||||
|
@ -151,71 +160,153 @@ public:
|
|||
void getListReset();
|
||||
};
|
||||
|
||||
#define CHEATDB_OFFSET_FILE_DESCRIPTION 0x00000010
|
||||
#define CHEATDB_FILEOFFSET_FIRST_FAT_ENTRY 0x00000100
|
||||
|
||||
enum CHEATS_DB_TYPE
|
||||
{
|
||||
CHEATS_DB_R4 = 0
|
||||
};
|
||||
|
||||
// This struct maps to the FAT entries in the R4 cheat database file.
|
||||
#pragma pack(push)
|
||||
#pragma pack(1)
|
||||
typedef struct FAT_R4
|
||||
{
|
||||
u8 serial[4];
|
||||
u32 CRC;
|
||||
u8 serial[4];
|
||||
u32 CRC;
|
||||
u64 addr;
|
||||
} FAT_R4;
|
||||
#pragma pack(pop)
|
||||
|
||||
// Wrapper for a single entry in a memory block that contains data read from a cheat database file.
|
||||
// This struct also maintains the hierarchical relationships between entries.
|
||||
struct CheatDBEntry
|
||||
{
|
||||
u8 *base; // Pointer to the entry's base location in memory.
|
||||
char *name; // Pointer to the entry's name string.
|
||||
char *note; // Pointer to the entry's note string.
|
||||
u32 *codeLength; // Pointer to the entry's 32-bit code length in bytes. This value is NULL if the entry is a directory.
|
||||
u32 *codeData; // Pointer to the entry's code data, provided in pairs of 32-bit values. This value is NULL if the entry is a directory.
|
||||
|
||||
CheatDBEntry *parent;
|
||||
std::vector<CheatDBEntry> child;
|
||||
};
|
||||
typedef struct CheatDBEntry CheatDBEntry;
|
||||
|
||||
class CheatDBGame
|
||||
{
|
||||
protected:
|
||||
u32 _baseOffset; // This offset is relative to the file head.
|
||||
u32 _firstEntryOffset; // This offset is relative to the file head.
|
||||
u32 _encryptOffset; // This offset is relative to the memory address of this->_entryDataRawPtr.
|
||||
|
||||
u32 _dataSize;
|
||||
u32 _crc;
|
||||
u32 _entryCount;
|
||||
|
||||
std::string _title;
|
||||
char _serial[4 + 1];
|
||||
|
||||
u8 *_entryDataRawPtr;
|
||||
u8 *_entryData;
|
||||
CheatDBEntry _entryRoot;
|
||||
u32 _cheatItemCount;
|
||||
|
||||
void _UpdateDirectoryParents(CheatDBEntry &directory);
|
||||
bool _CreateCheatItemFromCheatEntry(const CheatDBEntry &inEntry, const bool isHierarchical, CHEATS_LIST &outCheatItem);
|
||||
size_t _DirectoryAddCheatsFlat(const CheatDBEntry &directory, const bool isHierarchical, size_t cheatIndex, CHEATS_LIST *outCheatsList);
|
||||
|
||||
public:
|
||||
CheatDBGame();
|
||||
CheatDBGame(const u32 encryptOffset, const FAT_R4 &fat, const u32 dataSize);
|
||||
CheatDBGame(FILE *fp, const bool isEncrypted, const u32 encryptOffset, const FAT_R4 &fat, const u32 dataSize, u8 (&workingBuffer)[1024]);
|
||||
~CheatDBGame();
|
||||
|
||||
void SetInitialProperties(const u32 dataSize, const u32 encryptOffset, const FAT_R4 &fat);
|
||||
void LoadPropertiesFromFile(FILE *fp, const bool isEncrypted, u8 (&workingBuffer)[1024]);
|
||||
|
||||
u32 GetBaseOffset() const;
|
||||
u32 GetFirstEntryOffset() const;
|
||||
u32 GetEncryptOffset() const;
|
||||
u32 GetDataSize() const;
|
||||
u32 GetCRC() const;
|
||||
u32 GetEntryCount() const;
|
||||
u32 GetCheatItemCount() const;
|
||||
const char* GetTitle() const;
|
||||
const char* GetSerial() const;
|
||||
|
||||
const CheatDBEntry& GetEntryRoot() const;
|
||||
const u8* GetEntryRawData() const;
|
||||
bool IsEntryDataLoaded() const;
|
||||
|
||||
u8* LoadEntryData(FILE *fp, const bool isEncrypted);
|
||||
size_t ParseEntriesToCheatsListFlat(CHEATS_LIST *outCheatsList);
|
||||
};
|
||||
|
||||
typedef std::vector<CheatDBGame> CheatDBGameList;
|
||||
|
||||
class CheatDBFile
|
||||
{
|
||||
protected:
|
||||
std::string _path;
|
||||
std::string _description;
|
||||
|
||||
CHEATS_DB_TYPE _type;
|
||||
bool _isEncrypted;
|
||||
size_t _size;
|
||||
|
||||
FILE *_fp;
|
||||
|
||||
CheatDBGame _ReadGame(const u32 encryptOffset, const FAT_R4 &fat, const u32 gameDataSize, u8 (&workingBuffer)[1024]);
|
||||
|
||||
public:
|
||||
CheatDBFile();
|
||||
~CheatDBFile();
|
||||
|
||||
static void R4Decrypt(u8 *buf, const size_t len, u64 n);
|
||||
static bool ReadToBuffer(FILE *fp, const size_t fileOffset, const bool isEncrypted, const size_t encryptOffset, const size_t requestedSize, u8 *outBuffer);
|
||||
|
||||
FILE* GetFilePtr() const;
|
||||
bool IsEncrypted() const;
|
||||
const char* GetDescription() const;
|
||||
|
||||
int OpenFile(const char *filePath);
|
||||
void CloseFile();
|
||||
|
||||
u32 LoadGameList(const char *gameCode, const u32 gameDatabaseCRC, CheatDBGameList &outList);
|
||||
};
|
||||
|
||||
class CHEATSEXPORT
|
||||
{
|
||||
private:
|
||||
CHEATS_DB_TYPE type;
|
||||
bool encrypted;
|
||||
FILE *fp;
|
||||
size_t fsize;
|
||||
u64 dataSize;
|
||||
u64 encOffset;
|
||||
FAT_R4 fat;
|
||||
bool search();
|
||||
bool getCodes();
|
||||
void R4decrypt(u8 *buf, const size_t len, u64 n);
|
||||
CheatDBFile _dbFile;
|
||||
CheatDBGame *_selectedDbGame;
|
||||
CHEATS_LIST *_cheats;
|
||||
|
||||
u32 numCheats;
|
||||
CHEATS_LIST *cheats;
|
||||
|
||||
u8 error; // 0 - no errors
|
||||
// 1 - open failed/file not found
|
||||
// 2 - file format is wrong (no valid header ID)
|
||||
// 3 - cheat not found in database
|
||||
// 4 - export error from database
|
||||
u8 _error; // 0 - no errors
|
||||
// 1 - open failed/file not found
|
||||
// 2 - file format is wrong (no valid header ID)
|
||||
// 3 - cheat not found in database
|
||||
// 4 - export error from database
|
||||
|
||||
public:
|
||||
CHEATSEXPORT() :
|
||||
fp(NULL),
|
||||
fsize(0),
|
||||
dataSize(0),
|
||||
encOffset(0),
|
||||
type(CHEATS_DB_R4),
|
||||
encrypted(false),
|
||||
numCheats(0),
|
||||
cheats(0),
|
||||
CRC(0),
|
||||
error(0)
|
||||
{
|
||||
memset(&fat, 0, sizeof(fat));
|
||||
memset(gametitle, 0, sizeof(gametitle));
|
||||
memset(date, 0, sizeof(date));
|
||||
}
|
||||
|
||||
u8 gametitle[CHEAT_DB_GAME_TITLE_SIZE];
|
||||
u8 date[17];
|
||||
u32 CRC;
|
||||
bool load(char *path);
|
||||
void close();
|
||||
CHEATS_LIST *getCheats();
|
||||
u32 getCheatsNum();
|
||||
u8 getErrorCode() { return error; }
|
||||
CHEATSEXPORT();
|
||||
~CHEATSEXPORT();
|
||||
|
||||
bool load(const char *path);
|
||||
void close();
|
||||
|
||||
CHEATS_LIST *getCheats() const;
|
||||
size_t getCheatsNum() const;
|
||||
const char* getGameTitle() const;
|
||||
const char* getDescription() const;
|
||||
u8 getErrorCode() const;
|
||||
};
|
||||
|
||||
CheatDBGame* GetCheatDBGameEntryFromList(const CheatDBGameList &gameList, const char *gameCode, const u32 gameDatabaseCRC);
|
||||
void CheatItemGenerateDescriptionHierarchical(const char *itemName, const char *itemNote, CHEATS_LIST &outCheatItem);
|
||||
void CheatItemGenerateDescriptionFlat(const char *folderName, const char *folderNote, const char *itemName, const char *itemNote, CHEATS_LIST &outCheatItem);
|
||||
|
||||
extern CHEATS *cheats;
|
||||
extern CHEATSEARCH *cheatSearch;
|
||||
|
|
|
@ -95,7 +95,8 @@ protected:
|
|||
bool _willAddFromDB;
|
||||
|
||||
CheatType _cheatType;
|
||||
std::string _descriptionString;
|
||||
std::string _descriptionMajorString;
|
||||
std::string _descriptionMinorString;
|
||||
|
||||
// Internal cheat type parameters
|
||||
CheatFreezeType _freezeType;
|
||||
|
@ -132,8 +133,8 @@ public:
|
|||
void SetType(CheatType requestedType);
|
||||
bool IsSupportedType() const;
|
||||
|
||||
const char* GetDescription() const;
|
||||
void SetDescription(const char *descriptionString);
|
||||
const char* GetMajorDescription() const;
|
||||
void SetMajorDescription(const char *descriptionString);
|
||||
|
||||
CheatFreezeType GetFreezeType() const;
|
||||
void SetFreezeType(CheatFreezeType theFreezeType);
|
||||
|
@ -224,7 +225,7 @@ class ClientCheatDatabase
|
|||
protected:
|
||||
ClientCheatList *_list;
|
||||
std::string _title;
|
||||
std::string _date;
|
||||
std::string _description;
|
||||
std::string _lastFilePath;
|
||||
|
||||
public:
|
||||
|
@ -235,7 +236,7 @@ public:
|
|||
ClientCheatList* LoadFromFile(const char *dbFilePath);
|
||||
|
||||
const char* GetTitle() const;
|
||||
const char* GetDate() const;
|
||||
const char* GetDescription() const;
|
||||
};
|
||||
|
||||
class ClientCheatManager
|
||||
|
@ -289,7 +290,7 @@ public:
|
|||
ClientCheatList* GetDatabaseList() const;
|
||||
ClientCheatList* DatabaseListLoadFromFile(const char *dbFilePath);
|
||||
const char* GetDatabaseTitle() const;
|
||||
const char* GetDatabaseDate() const;
|
||||
const char* GetDatabaseDescription() const;
|
||||
|
||||
bool SearchDidStart() const;
|
||||
void SearchReset();
|
||||
|
|
|
@ -178,7 +178,8 @@ ClientCheatItem::ClientCheatItem()
|
|||
_willAddFromDB = false;
|
||||
|
||||
_cheatType = CheatType_Internal;
|
||||
_descriptionString = "No description.";
|
||||
_descriptionMajorString = "No description.";
|
||||
_descriptionMinorString = "";
|
||||
_freezeType = CheatFreezeType_Normal;
|
||||
_address = 0x02000000;
|
||||
strncpy(_addressString, "0x02000000", sizeof(_addressString));
|
||||
|
@ -202,7 +203,8 @@ void ClientCheatItem::Init(const CHEATS_LIST &inCheatItem)
|
|||
this->_isEnabled = (inCheatItem.enabled) ? true : false;
|
||||
|
||||
this->_cheatType = (CheatType)inCheatItem.type;
|
||||
this->_descriptionString = inCheatItem.description;
|
||||
this->_descriptionMajorString = inCheatItem.description;
|
||||
this->_descriptionMinorString = "";
|
||||
|
||||
this->_freezeType = (CheatFreezeType)inCheatItem.freezeType;
|
||||
this->_valueLength = inCheatItem.size + 1; // CHEATS_LIST.size value range is [1...4], but starts counting from 0.
|
||||
|
@ -238,7 +240,7 @@ void ClientCheatItem::Init(const CHEATS_LIST &inCheatItem)
|
|||
void ClientCheatItem::Init(const ClientCheatItem &inCheatItem)
|
||||
{
|
||||
this->SetEnabled(inCheatItem.IsEnabled());
|
||||
this->SetDescription(inCheatItem.GetDescription());
|
||||
this->SetMajorDescription(inCheatItem.GetMajorDescription());
|
||||
this->SetType(inCheatItem.GetType());
|
||||
this->SetFreezeType(inCheatItem.GetFreezeType());
|
||||
|
||||
|
@ -322,20 +324,20 @@ bool ClientCheatItem::IsSupportedType() const
|
|||
return (this->_cheatType != CheatType_CodeBreaker);
|
||||
}
|
||||
|
||||
const char* ClientCheatItem::GetDescription() const
|
||||
const char* ClientCheatItem::GetMajorDescription() const
|
||||
{
|
||||
return this->_descriptionString.c_str();
|
||||
return this->_descriptionMajorString.c_str();
|
||||
}
|
||||
|
||||
void ClientCheatItem::SetDescription(const char *descriptionString)
|
||||
void ClientCheatItem::SetMajorDescription(const char *descriptionString)
|
||||
{
|
||||
if (descriptionString == NULL)
|
||||
{
|
||||
this->_descriptionString = "";
|
||||
this->_descriptionMajorString = "";
|
||||
}
|
||||
else
|
||||
{
|
||||
this->_descriptionString = descriptionString;
|
||||
this->_descriptionMajorString = descriptionString;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -608,7 +610,7 @@ void ClientCheatItem::ClientToDesmumeCheatItem(CHEATS_LIST *outCheatItem) const
|
|||
|
||||
outCheatItem->type = this->_cheatType;
|
||||
outCheatItem->enabled = (this->_isEnabled) ? 1 : 0;
|
||||
strncpy(outCheatItem->description, this->_descriptionString.c_str(), sizeof(outCheatItem->description));
|
||||
strncpy(outCheatItem->description, this->_descriptionMajorString.c_str(), sizeof(outCheatItem->description));
|
||||
|
||||
switch (this->_cheatType)
|
||||
{
|
||||
|
@ -1062,7 +1064,7 @@ ClientCheatDatabase::ClientCheatDatabase()
|
|||
{
|
||||
_list = new ClientCheatList;
|
||||
_title.resize(0);
|
||||
_date.resize(0);
|
||||
_description.resize(0);
|
||||
_lastFilePath.resize(0);
|
||||
}
|
||||
|
||||
|
@ -1090,8 +1092,8 @@ ClientCheatList* ClientCheatDatabase::LoadFromFile(const char *dbFilePath)
|
|||
if (didFileLoad)
|
||||
{
|
||||
this->_list->RemoveAll();
|
||||
this->_title = (const char *)exporter->gametitle;
|
||||
this->_date = (const char *)exporter->date;
|
||||
this->_title = exporter->getGameTitle();
|
||||
this->_description = exporter->getDescription();
|
||||
this->_lastFilePath = dbFilePath;
|
||||
|
||||
const size_t itemCount = exporter->getCheatsNum();
|
||||
|
@ -1127,9 +1129,9 @@ const char* ClientCheatDatabase::GetTitle() const
|
|||
return this->_title.c_str();
|
||||
}
|
||||
|
||||
const char* ClientCheatDatabase::GetDate() const
|
||||
const char* ClientCheatDatabase::GetDescription() const
|
||||
{
|
||||
return this->_date.c_str();
|
||||
return this->_description.c_str();
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
|
@ -1242,11 +1244,11 @@ ClientCheatItem* ClientCheatManager::NewItem()
|
|||
char newDesc[16];
|
||||
snprintf(newDesc, sizeof(newDesc), "Untitled %ld", (unsigned long)this->_untitledCount);
|
||||
|
||||
newItem->SetDescription(newDesc);
|
||||
newItem->SetMajorDescription(newDesc);
|
||||
}
|
||||
else
|
||||
{
|
||||
newItem->SetDescription("Untitled");
|
||||
newItem->SetMajorDescription("Untitled");
|
||||
}
|
||||
|
||||
if (newItem->IsEnabled())
|
||||
|
@ -1407,9 +1409,9 @@ const char* ClientCheatManager::GetDatabaseTitle() const
|
|||
return this->_currentDatabase->GetTitle();
|
||||
}
|
||||
|
||||
const char* ClientCheatManager::GetDatabaseDate() const
|
||||
const char* ClientCheatManager::GetDatabaseDescription() const
|
||||
{
|
||||
return this->_currentDatabase->GetDate();
|
||||
return this->_currentDatabase->GetDescription();
|
||||
}
|
||||
|
||||
bool ClientCheatManager::SearchDidStart() const
|
||||
|
@ -1623,18 +1625,18 @@ static NSImage *iconCodeBreaker = nil;
|
|||
|
||||
- (NSString *) description
|
||||
{
|
||||
return [NSString stringWithCString:_internalData->GetDescription() encoding:NSUTF8StringEncoding];
|
||||
return [NSString stringWithCString:_internalData->GetMajorDescription() encoding:NSUTF8StringEncoding];
|
||||
}
|
||||
|
||||
- (void) setDescription:(NSString *)desc
|
||||
{
|
||||
if (desc == nil)
|
||||
{
|
||||
_internalData->SetDescription(NULL);
|
||||
_internalData->SetMajorDescription(NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
_internalData->SetDescription([desc cStringUsingEncoding:NSUTF8StringEncoding]);
|
||||
_internalData->SetMajorDescription([desc cStringUsingEncoding:NSUTF8StringEncoding]);
|
||||
}
|
||||
|
||||
if ((workingCopy != nil) && !_disableWorkingCopyUpdate)
|
||||
|
@ -1645,7 +1647,7 @@ static NSImage *iconCodeBreaker = nil;
|
|||
|
||||
- (char *) descriptionCString
|
||||
{
|
||||
return (char *)_internalData->GetDescription();
|
||||
return (char *)_internalData->GetMajorDescription();
|
||||
}
|
||||
|
||||
- (NSInteger) cheatType
|
||||
|
@ -2072,7 +2074,7 @@ static NSImage *iconCodeBreaker = nil;
|
|||
|
||||
- (NSString *) databaseDate
|
||||
{
|
||||
return [NSString stringWithCString:_internalCheatManager->GetDatabaseDate() encoding:NSUTF8StringEncoding];
|
||||
return [NSString stringWithCString:_internalCheatManager->GetDatabaseDescription() encoding:NSUTF8StringEncoding];
|
||||
}
|
||||
|
||||
- (NSUInteger) itemTotalCount
|
||||
|
|
|
@ -1199,7 +1199,7 @@ void UpdateDisplayPropertiesFromStates(uint64_t displayModeStates, ClientDisplay
|
|||
ClientCheatItem *newCheatItem = new ClientCheatItem;
|
||||
newCheatItem->SetType(CheatType_ActionReplay); // Default to Action Replay for now
|
||||
newCheatItem->SetFreezeType(CheatFreezeType_Normal);
|
||||
newCheatItem->SetDescription(NULL); // OpenEmu takes care of this
|
||||
newCheatItem->SetMajorDescription(NULL); // OpenEmu takes care of this
|
||||
newCheatItem->SetRawCodeString([code cStringUsingEncoding:NSUTF8StringEncoding], true);
|
||||
newCheatItem->SetEnabled((enabled) ? true : false);
|
||||
|
||||
|
|
|
@ -1534,13 +1534,13 @@ INT_PTR CALLBACK CheatsExportProc(HWND dialog, UINT msg,WPARAM wparam,LPARAM lpa
|
|||
{
|
||||
case WM_INITDIALOG:
|
||||
{
|
||||
SetWindowText(GetDlgItem(dialog, IDC_CDATE), (LPCSTR)cheatsExport->date);
|
||||
if (cheatsExport->gametitle && strlen((char*)cheatsExport->gametitle) > 0)
|
||||
SetWindowText(GetDlgItem(dialog, IDC_CDATE), (LPCSTR)cheatsExport->getDescription());
|
||||
if ( strlen(cheatsExport->getGameTitle()) > 0 )
|
||||
{
|
||||
char buf[512] = {0};
|
||||
GetWindowText(dialog, &buf[0], sizeof(buf));
|
||||
strcat(buf, ": ");
|
||||
strcat(buf, (char*)cheatsExport->gametitle);
|
||||
strcat(buf, cheatsExport->getGameTitle());
|
||||
SetWindowText(dialog, (LPCSTR)buf);
|
||||
}
|
||||
LV_COLUMN lvColumn;
|
||||
|
|
Loading…
Reference in New Issue