upgrade to rcheevos 10.6 (#14911)

This commit is contained in:
Jamiras 2023-01-27 06:52:29 -07:00 committed by GitHub
parent 46cf1d795a
commit 5ecdc4c170
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 432 additions and 13 deletions

View File

@ -672,6 +672,7 @@ bool rcheevos_unload(void)
if (rcheevos_locals.loaded)
{
unsigned count = 0;
#ifdef HAVE_MENU
rcheevos_menu_reset_badges();
@ -684,6 +685,45 @@ bool rcheevos_unload(void)
}
#endif
count = rcheevos_locals.game.achievement_count;
rcheevos_locals.game.achievement_count = 0;
if (rcheevos_locals.game.achievements)
{
rcheevos_racheevo_t* achievement = rcheevos_locals.game.achievements;
rcheevos_racheevo_t* end = achievement + count;
while (achievement < end)
{
CHEEVOS_FREE(achievement->title);
CHEEVOS_FREE(achievement->description);
CHEEVOS_FREE(achievement->badge);
CHEEVOS_FREE(achievement->memaddr);
++achievement;
}
CHEEVOS_FREE(rcheevos_locals.game.achievements);
rcheevos_locals.game.achievements = NULL;
}
count = rcheevos_locals.game.leaderboard_count;
rcheevos_locals.game.leaderboard_count = 0;
if (rcheevos_locals.game.leaderboards)
{
rcheevos_ralboard_t* lboard = rcheevos_locals.game.leaderboards;
rcheevos_ralboard_t* end = lboard + count;
while (lboard < end)
{
CHEEVOS_FREE(lboard->title);
CHEEVOS_FREE(lboard->description);
CHEEVOS_FREE(lboard->mem);
++lboard;
}
CHEEVOS_FREE(rcheevos_locals.game.leaderboards);
rcheevos_locals.game.leaderboards = NULL;
}
if (rcheevos_locals.game.title)
{
CHEEVOS_FREE(rcheevos_locals.game.title);
@ -1535,6 +1575,9 @@ static void rcheevos_show_game_placard(void)
int number_of_core = 0;
int mode = RCHEEVOS_ACTIVE_SOFTCORE;
if (rcheevos_locals.game.id < 0) /* make sure there's actually a game loaded */
return;
if (rcheevos_locals.hardcore_active)
mode = RCHEEVOS_ACTIVE_HARDCORE;

View File

@ -1,3 +1,67 @@
# v10.6.0
* add RC_RUNTIME_EVENT_ACHIEVEMENT_PROGRESS_UPDATED
* use optimized comparators for most common condition logic
* fix game identification of psx ISOs that have extra slashes in their boot path
* fix game identification of ndd files
# v10.5.0
* add RC_MEMSIZE_MBF32_LE
* add RC_OPERATOR_XOR
* add RC_CONSOLE_ATARI_JAGUAR_CD and hash/memory map for Atari Jaguar CD
* add RC_CONSOLE_ARCADIA_2001 and hash/memory map for Arcadia 2001
* add RC_CONSOLE_INTERTON_VC_4000 and hash/memory map for Interton VC 4000
* add RC_CONSOLE_ELEKTOR_TV_GAMES_COMPUTER and hash/memory map for Elektor TV Games Computer
* split RC_CONSOLE_PC_ENGINE_CD off of RC_CONSOLE_PC_ENGINE
* add hash/memory map for RC_CONSOLE_NEO_GEO_CD
* add additional 256KB of RAM to memory map for RC_CONSOLE_SEGA_32X
* validation: don't report redundancy between trigger and non-trigger conditions
* validation: don't report range validation errors for float comparisons
* change default image host to media.retroachievements.org
* fix decoding of denormalized floats
* fix full line comments in the middle of Display: section causing RC_MISSING_DISPLAY_STRING
# v10.4.0
* add rc_libretro_hash_set_t with support for #SAVEDISK: m3u extension
* add rc_libretro_is_system_allowed for finer-grain control over core support
* fix measured value from hitcount not resetting while paused
* add RC_CONSOLE_WASM and hash/memory map for WASM-4
* add scratchpad memory to RC_CONSOLE_PLAYSTATION_2 memory map
* add hash/memory map for RC_CONSOLE_FAIRCHILD_CHANNEL_F
* add hash/memory map for RC_CONSOLE_COMMODORE_64
* add memory map for RC_CONSOLE_AMIGA
# v10.3.3
* add RC_CONSOLE_ARDUBOY and hash/memory map for Arduboy
* add display_name to rc_api_login_response_t
* detect logical conflicts and redundancies in validator
* fix tab sequences in JSON responses being turned into t
* fix overflow when float value has more than 9 digits after the decimal
* fix libretro memory mapping when disconnect mask breaks a region into multiple blocks
* fix non-virtualized file system call when reading some iso files
# v10.3.2
* fix RC_OPERAND_PRIOR for bit sizes other than RC_MEMSIZE_BIT_0
* add memory map and hash for Amstrad CPC
* fix an issue where fetch_game_data and fetch_user_unlocks could return RC_MISSING_VALUE instead of acknowledging a server error
# v10.3.1
* allow empty description in rc_api_init_update_leaderboard_request
* fix buffered n64 hash when no filereader is registered
* add memory map and hash for Mega Duck
# v10.3.0
* support for floating point memory sizes and logic
* add built-in macros for rich presence: @Number, @Score, @Centisecs, @Seconds, @Minutes, @ASCIIChar, @UnicodeChar
* add rapi functions for fetch_code_notes, update_code_note, upload_achievement, update_leaderboard, fetch_badge_range, and add_game_hash
* add lower_is_better and hidden flags to leaderboards in rc_api_fetch_game_data_response_t
* add achievements_remaining to rc_api_award_achievement_response_t
* add console enums for PC6000, PICO, MEGADUCK and ZEEBO
* add memory map for Dreamcast
* capture leaderboard/rich presence state in rc_runtime_progress data
* support for hashing Dreamcast bin/cues
* support for hashing buffered NDS ROMs
* fix prior for sizes smaller than a byte sometimes returning current value
# v10.2.0
* add RC_MEMSIZE_16_BITS_BE, RC_MEMSIZE_24_BITS_BE, and RC_MEMSIZE_32_BITS_BE

View File

@ -200,6 +200,9 @@ struct rc_condition_t {
/* Whether or not the condition evaluated true on the last check */
char is_true;
/* Unique identifier of optimized comparator to use */
char optimized_comparator;
};
/*****************************************************************************\

View File

@ -1,6 +1,91 @@
#include "rc_internal.h"
#include <stdlib.h>
#include <assert.h>
static int rc_test_condition_compare(unsigned value1, unsigned value2, char oper) {
switch (oper) {
case RC_OPERATOR_EQ: return value1 == value2;
case RC_OPERATOR_NE: return value1 != value2;
case RC_OPERATOR_LT: return value1 < value2;
case RC_OPERATOR_LE: return value1 <= value2;
case RC_OPERATOR_GT: return value1 > value2;
case RC_OPERATOR_GE: return value1 >= value2;
default: return 1;
}
}
static char rc_condition_determine_comparator(const rc_condition_t* self) {
switch (self->oper) {
case RC_OPERATOR_EQ:
case RC_OPERATOR_NE:
case RC_OPERATOR_LT:
case RC_OPERATOR_LE:
case RC_OPERATOR_GT:
case RC_OPERATOR_GE:
break;
default:
/* not a comparison. should not be getting compared. but if it is, legacy behavior was to return 1 */
return RC_PROCESSING_COMPARE_ALWAYS_TRUE;
}
if ((self->operand1.type == RC_OPERAND_ADDRESS || self->operand1.type == RC_OPERAND_DELTA) &&
!self->operand1.value.memref->value.is_indirect && !rc_operand_is_float(&self->operand1)) {
/* left side is an integer memory reference */
int needs_translate = (self->operand1.size != self->operand1.value.memref->value.size);
if (self->operand2.type == RC_OPERAND_CONST) {
/* right side is a constant */
if (self->operand1.type == RC_OPERAND_ADDRESS)
return needs_translate ? RC_PROCESSING_COMPARE_MEMREF_TO_CONST_TRANSFORMED : RC_PROCESSING_COMPARE_MEMREF_TO_CONST;
return needs_translate ? RC_PROCESSING_COMPARE_DELTA_TO_CONST_TRANSFORMED : RC_PROCESSING_COMPARE_DELTA_TO_CONST;
}
else if ((self->operand2.type == RC_OPERAND_ADDRESS || self->operand2.type == RC_OPERAND_DELTA) &&
!self->operand2.value.memref->value.is_indirect && !rc_operand_is_float(&self->operand2)) {
/* right side is an integer memory reference */
const int is_same_memref = (self->operand1.value.memref == self->operand2.value.memref);
needs_translate |= (self->operand2.size != self->operand2.value.memref->value.size);
if (self->operand1.type == RC_OPERAND_ADDRESS) {
if (self->operand2.type == RC_OPERAND_ADDRESS) {
if (is_same_memref && !needs_translate) {
/* comparing a memref to itself, will evaluate to a constant */
return rc_test_condition_compare(0, 0, self->oper) ? RC_PROCESSING_COMPARE_ALWAYS_TRUE : RC_PROCESSING_COMPARE_ALWAYS_FALSE;
}
return needs_translate ? RC_PROCESSING_COMPARE_MEMREF_TO_MEMREF_TRANSFORMED : RC_PROCESSING_COMPARE_MEMREF_TO_MEMREF;
}
assert(self->operand2.type == RC_OPERAND_DELTA);
if (is_same_memref) {
/* delta comparison is optimized to compare with itself (for detecting change) */
return needs_translate ? RC_PROCESSING_COMPARE_MEMREF_TO_DELTA_TRANSFORMED : RC_PROCESSING_COMPARE_MEMREF_TO_DELTA;
}
}
else {
assert(self->operand1.type == RC_OPERAND_DELTA);
if (self->operand2.type == RC_OPERAND_ADDRESS) {
if (is_same_memref) {
/* delta comparison is optimized to compare with itself (for detecting change) */
return needs_translate ? RC_PROCESSING_COMPARE_DELTA_TO_MEMREF_TRANSFORMED : RC_PROCESSING_COMPARE_DELTA_TO_MEMREF;
}
}
}
}
}
if (self->operand1.type == RC_OPERAND_CONST && self->operand2.type == RC_OPERAND_CONST) {
/* comparing constants will always generate a constant result */
return rc_test_condition_compare(self->operand1.value.num, self->operand2.value.num, self->oper) ?
RC_PROCESSING_COMPARE_ALWAYS_TRUE : RC_PROCESSING_COMPARE_ALWAYS_FALSE;
}
return RC_PROCESSING_COMPARE_DEFAULT;
}
static int rc_parse_operator(const char** memaddr) {
const char* oper = *memaddr;
@ -75,6 +160,7 @@ rc_condition_t* rc_parse_condition(const char** memaddr, rc_parse_state_t* parse
self->current_hits = 0;
self->is_true = 0;
self->pause = 0;
self->optimized_comparator = RC_PROCESSING_COMPARE_DEFAULT;
if (*aux != 0 && aux[1] == ':') {
switch (*aux) {
@ -214,6 +300,9 @@ rc_condition_t* rc_parse_condition(const char** memaddr, rc_parse_state_t* parse
self->required_hits = 0;
}
if (parse->buffer != 0)
self->optimized_comparator = rc_condition_determine_comparator(self);
*memaddr = aux;
return self;
}
@ -233,12 +322,203 @@ int rc_condition_is_combining(const rc_condition_t* self) {
}
}
static int rc_test_condition_compare_memref_to_const(rc_condition_t* self) {
const unsigned value1 = self->operand1.value.memref->value.value;
const unsigned value2 = self->operand2.value.num;
assert(self->operand1.size == self->operand1.value.memref->value.size);
return rc_test_condition_compare(value1, value2, self->oper);
}
static int rc_test_condition_compare_delta_to_const(rc_condition_t* self) {
const rc_memref_value_t* memref1 = &self->operand1.value.memref->value;
const unsigned value1 = (memref1->changed) ? memref1->prior : memref1->value;
const unsigned value2 = self->operand2.value.num;
assert(self->operand1.size == self->operand1.value.memref->value.size);
return rc_test_condition_compare(value1, value2, self->oper);
}
static int rc_test_condition_compare_memref_to_memref(rc_condition_t* self) {
const unsigned value1 = self->operand1.value.memref->value.value;
const unsigned value2 = self->operand2.value.memref->value.value;
assert(self->operand1.size == self->operand1.value.memref->value.size);
assert(self->operand2.size == self->operand2.value.memref->value.size);
return rc_test_condition_compare(value1, value2, self->oper);
}
static int rc_test_condition_compare_memref_to_delta(rc_condition_t* self) {
const rc_memref_value_t* memref = &self->operand1.value.memref->value;
assert(self->operand1.value.memref == self->operand2.value.memref);
assert(self->operand1.size == self->operand1.value.memref->value.size);
assert(self->operand2.size == self->operand2.value.memref->value.size);
if (memref->changed)
return rc_test_condition_compare(memref->value, memref->prior, self->oper);
switch (self->oper) {
case RC_OPERATOR_EQ:
case RC_OPERATOR_GE:
case RC_OPERATOR_LE:
return 1;
default:
return 0;
}
}
static int rc_test_condition_compare_delta_to_memref(rc_condition_t* self) {
const rc_memref_value_t* memref = &self->operand1.value.memref->value;
assert(self->operand1.value.memref == self->operand2.value.memref);
assert(self->operand1.size == self->operand1.value.memref->value.size);
assert(self->operand2.size == self->operand2.value.memref->value.size);
if (memref->changed)
return rc_test_condition_compare(memref->prior, memref->value, self->oper);
switch (self->oper) {
case RC_OPERATOR_EQ:
case RC_OPERATOR_GE:
case RC_OPERATOR_LE:
return 1;
default:
return 0;
}
}
static int rc_test_condition_compare_memref_to_const_transformed(rc_condition_t* self) {
rc_typed_value_t value1;
const unsigned value2 = self->operand2.value.num;
value1.type = RC_VALUE_TYPE_UNSIGNED;
value1.value.u32 = self->operand1.value.memref->value.value;
rc_transform_memref_value(&value1, self->operand1.size);
return rc_test_condition_compare(value1.value.u32, value2, self->oper);
}
static int rc_test_condition_compare_delta_to_const_transformed(rc_condition_t* self) {
rc_typed_value_t value1;
const rc_memref_value_t* memref1 = &self->operand1.value.memref->value;
const unsigned value2 = self->operand2.value.num;
value1.type = RC_VALUE_TYPE_UNSIGNED;
value1.value.u32 = (memref1->changed) ? memref1->prior : memref1->value;
rc_transform_memref_value(&value1, self->operand1.size);
return rc_test_condition_compare(value1.value.u32, value2, self->oper);
}
static int rc_test_condition_compare_memref_to_memref_transformed(rc_condition_t* self) {
rc_typed_value_t value1, value2;
value1.type = RC_VALUE_TYPE_UNSIGNED;
value1.value.u32 = self->operand1.value.memref->value.value;
rc_transform_memref_value(&value1, self->operand1.size);
value2.type = RC_VALUE_TYPE_UNSIGNED;
value2.value.u32 = self->operand2.value.memref->value.value;
rc_transform_memref_value(&value2, self->operand2.size);
return rc_test_condition_compare(value1.value.u32, value2.value.u32, self->oper);
}
static int rc_test_condition_compare_memref_to_delta_transformed(rc_condition_t* self) {
const rc_memref_value_t* memref = &self->operand1.value.memref->value;
assert(self->operand1.value.memref == self->operand2.value.memref);
if (memref->changed) {
rc_typed_value_t value1, value2;
value1.type = RC_VALUE_TYPE_UNSIGNED;
value1.value.u32 = memref->value;
rc_transform_memref_value(&value1, self->operand1.size);
value2.type = RC_VALUE_TYPE_UNSIGNED;
value2.value.u32 = memref->prior;
rc_transform_memref_value(&value2, self->operand2.size);
return rc_test_condition_compare(value1.value.u32, value2.value.u32, self->oper);
}
switch (self->oper) {
case RC_OPERATOR_EQ:
case RC_OPERATOR_GE:
case RC_OPERATOR_LE:
return 1;
default:
return 0;
}
}
static int rc_test_condition_compare_delta_to_memref_transformed(rc_condition_t* self) {
const rc_memref_value_t* memref = &self->operand1.value.memref->value;
assert(self->operand1.value.memref == self->operand2.value.memref);
if (memref->changed) {
rc_typed_value_t value1, value2;
value1.type = RC_VALUE_TYPE_UNSIGNED;
value1.value.u32 = memref->prior;
rc_transform_memref_value(&value1, self->operand1.size);
value2.type = RC_VALUE_TYPE_UNSIGNED;
value2.value.u32 = memref->value;
rc_transform_memref_value(&value2, self->operand2.size);
return rc_test_condition_compare(value1.value.u32, value2.value.u32, self->oper);
}
switch (self->oper) {
case RC_OPERATOR_EQ:
case RC_OPERATOR_GE:
case RC_OPERATOR_LE:
return 1;
default:
return 0;
}
}
int rc_test_condition(rc_condition_t* self, rc_eval_state_t* eval_state) {
rc_typed_value_t value1, value2;
rc_evaluate_operand(&value1, &self->operand1, eval_state);
if (eval_state->add_value.type != RC_VALUE_TYPE_NONE)
if (eval_state->add_value.type != RC_VALUE_TYPE_NONE) {
/* if there's an accumulator, we can't use the optimized comparators */
rc_evaluate_operand(&value1, &self->operand1, eval_state);
rc_typed_value_add(&value1, &eval_state->add_value);
} else {
/* use an optimized comparator whenever possible */
switch (self->optimized_comparator) {
case RC_PROCESSING_COMPARE_MEMREF_TO_CONST:
return rc_test_condition_compare_memref_to_const(self);
case RC_PROCESSING_COMPARE_MEMREF_TO_DELTA:
return rc_test_condition_compare_memref_to_delta(self);
case RC_PROCESSING_COMPARE_MEMREF_TO_MEMREF:
return rc_test_condition_compare_memref_to_memref(self);
case RC_PROCESSING_COMPARE_DELTA_TO_CONST:
return rc_test_condition_compare_delta_to_const(self);
case RC_PROCESSING_COMPARE_DELTA_TO_MEMREF:
return rc_test_condition_compare_delta_to_memref(self);
case RC_PROCESSING_COMPARE_MEMREF_TO_CONST_TRANSFORMED:
return rc_test_condition_compare_memref_to_const_transformed(self);
case RC_PROCESSING_COMPARE_MEMREF_TO_DELTA_TRANSFORMED:
return rc_test_condition_compare_memref_to_delta_transformed(self);
case RC_PROCESSING_COMPARE_MEMREF_TO_MEMREF_TRANSFORMED:
return rc_test_condition_compare_memref_to_memref_transformed(self);
case RC_PROCESSING_COMPARE_DELTA_TO_CONST_TRANSFORMED:
return rc_test_condition_compare_delta_to_const_transformed(self);
case RC_PROCESSING_COMPARE_DELTA_TO_MEMREF_TRANSFORMED:
return rc_test_condition_compare_delta_to_memref_transformed(self);
case RC_PROCESSING_COMPARE_ALWAYS_TRUE:
return 1;
case RC_PROCESSING_COMPARE_ALWAYS_FALSE:
return 0;
default:
rc_evaluate_operand(&value1, &self->operand1, eval_state);
break;
}
}
rc_evaluate_operand(&value2, &self->operand2, eval_state);

View File

@ -444,7 +444,7 @@ void rc_init_parse_state_memrefs(rc_parse_state_t* parse, rc_memref_t** memrefs)
*memrefs = 0;
}
static unsigned rc_get_memref_value_value(rc_memref_value_t* memref, int operand_type) {
static unsigned rc_get_memref_value_value(const rc_memref_value_t* memref, int operand_type) {
switch (operand_type)
{
/* most common case explicitly first, even though it could be handled by default case.

View File

@ -146,6 +146,22 @@ rc_condset_t* rc_parse_condset(const char** memaddr, rc_parse_state_t* parse, in
int rc_test_condset(rc_condset_t* self, rc_eval_state_t* eval_state);
void rc_reset_condset(rc_condset_t* self);
enum {
RC_PROCESSING_COMPARE_DEFAULT = 0,
RC_PROCESSING_COMPARE_MEMREF_TO_CONST,
RC_PROCESSING_COMPARE_MEMREF_TO_DELTA,
RC_PROCESSING_COMPARE_MEMREF_TO_MEMREF,
RC_PROCESSING_COMPARE_DELTA_TO_MEMREF,
RC_PROCESSING_COMPARE_DELTA_TO_CONST,
RC_PROCESSING_COMPARE_MEMREF_TO_CONST_TRANSFORMED,
RC_PROCESSING_COMPARE_MEMREF_TO_DELTA_TRANSFORMED,
RC_PROCESSING_COMPARE_MEMREF_TO_MEMREF_TRANSFORMED,
RC_PROCESSING_COMPARE_DELTA_TO_MEMREF_TRANSFORMED,
RC_PROCESSING_COMPARE_DELTA_TO_CONST_TRANSFORMED,
RC_PROCESSING_COMPARE_ALWAYS_TRUE,
RC_PROCESSING_COMPARE_ALWAYS_FALSE
};
rc_condition_t* rc_parse_condition(const char** memaddr, rc_parse_state_t* parse, int is_indirect);
int rc_test_condition(rc_condition_t* self, rc_eval_state_t* eval_state);
void rc_evaluate_condition_value(rc_typed_value_t* value, rc_condition_t* self, rc_eval_state_t* eval_state);

View File

@ -129,6 +129,12 @@ static const rc_disallowed_setting_t _rc_disallowed_snes9x_settings[] = {
{ NULL, NULL }
};
static const rc_disallowed_setting_t _rc_disallowed_vice_settings[] = {
{ "vice_autostart", "disabled" }, /* autostart dictates initial load and reset from menu */
{ "vice_reset", "!autostart" }, /* reset dictates behavior when pressing reset button (END) */
{ NULL, NULL }
};
static const rc_disallowed_setting_t _rc_disallowed_virtual_jaguar_settings[] = {
{ "virtualjaguar_pal", "enabled" },
{ NULL, NULL }
@ -152,6 +158,7 @@ static const rc_disallowed_core_settings_t rc_disallowed_core_settings[] = {
{ "QUASI88", _rc_disallowed_quasi88_settings },
{ "SMS Plus GX", _rc_disallowed_smsplus_settings },
{ "Snes9x", _rc_disallowed_snes9x_settings },
{ "VICE x64", _rc_disallowed_vice_settings },
{ "Virtual Jaguar", _rc_disallowed_virtual_jaguar_settings },
{ NULL, NULL }
};
@ -613,7 +620,7 @@ void rc_libretro_hash_set_init(struct rc_libretro_hash_set_t* hash_set,
char image_path[1024];
char* m3u_contents;
char* ptr;
size_t file_len;
int64_t file_len;
void* file_handle;
int index = 0;

View File

@ -197,14 +197,6 @@ int rc_evaluate_trigger(rc_trigger_t* self, rc_peek_t peek, void* ud, lua_State*
self->measured_value = eval_state.measured_value.value.u32;
}
/* if the state is WAITING and the trigger is ready to fire, ignore it and reset the hit counts */
/* otherwise, if the state is WAITING, proceed to activating the trigger */
if (self->state == RC_TRIGGER_STATE_WAITING && ret) {
rc_reset_trigger(self);
self->has_hits = 0;
return RC_TRIGGER_STATE_WAITING;
}
/* if any ResetIf condition was true, reset the hit counts */
if (eval_state.was_reset) {
/* if the measured value came from a hit count, reset it. do this before calling
@ -247,6 +239,13 @@ int rc_evaluate_trigger(rc_trigger_t* self, rc_peek_t peek, void* ud, lua_State*
is_primed = 0;
}
else if (ret) {
/* if the state is WAITING and the trigger is ready to fire, ignore it and reset the hit counts */
if (self->state == RC_TRIGGER_STATE_WAITING) {
rc_reset_trigger(self);
self->has_hits = 0;
return RC_TRIGGER_STATE_WAITING;
}
/* trigger was triggered */
self->state = RC_TRIGGER_STATE_TRIGGERED;
return RC_TRIGGER_STATE_TRIGGERED;

View File

@ -230,6 +230,10 @@ static uint32_t rc_cd_find_file_sector(void* track_handle, const char* path, uns
if (!track_handle)
return 0;
/* we start at the root. don't need to explicitly find it */
if (*path == '\\')
++path;
filename_length = strlen(path);
slash = strrchr(path, '\\');
if (slash)
@ -966,6 +970,9 @@ static int rc_hash_n64(char hash[33], const char* path)
rc_hash_verbose("converting n64 to z64");
is_n64 = 1;
}
else if (buffer[0] == 0xE8 || buffer[0] == 0x22) /* ndd format (don't byteswap) */
{
}
else
{
free(buffer);
@ -1469,7 +1476,7 @@ static int rc_hash_find_playstation_executable(void* track_handle, const char* b
if (strncmp(ptr, cdrom_prefix, cdrom_prefix_len) == 0)
ptr += cdrom_prefix_len;
if (*ptr == '\\')
while (*ptr == '\\')
++ptr;
start = ptr;