From 7dc68443d6d25b2ca522805a2c6fbe2d3483cf64 Mon Sep 17 00:00:00 2001
From: Andre Leiradella <andre@leiradella.com>
Date: Tue, 3 Nov 2015 00:54:26 -0200
Subject: [PATCH] correct evaluation of genesis md5 hashes

---
 cheevos.c | 47 +++++++++++++++++++++++++++++++++++++++--------
 1 file changed, 39 insertions(+), 8 deletions(-)

diff --git a/cheevos.c b/cheevos.c
index e1afb7f57a..72008b3ca9 100644
--- a/cheevos.c
+++ b/cheevos.c
@@ -17,22 +17,21 @@
 #include <ctype.h>
 
 #include <formats/jsonsax.h>
-#include <rhash.h>
 #include <retro_file.h>
+#include <rhash.h>
 #include <retro_log.h>
 #include <rthreads/async_job.h>
 
 #include "cheevos.h"
 #include "dynamic.h"
 #include "net_http_special.h"
-
 #include "configuration.h"
 #include "performance.h"
 #include "runloop.h"
 
 enum
 {
-   CHEEVOS_VAR_SIZE_BIT_0 = 0,
+   CHEEVOS_VAR_SIZE_BIT_0,
    CHEEVOS_VAR_SIZE_BIT_1,
    CHEEVOS_VAR_SIZE_BIT_2,
    CHEEVOS_VAR_SIZE_BIT_3,
@@ -52,7 +51,7 @@ enum
 
 enum
 {
-   CHEEVOS_VAR_TYPE_ADDRESS = 0, /* compare to the value of a live address in RAM */
+   CHEEVOS_VAR_TYPE_ADDRESS,     /* compare to the value of a live address in RAM */
    CHEEVOS_VAR_TYPE_VALUE_COMP,  /* a number. assume 32 bit */
    CHEEVOS_VAR_TYPE_DELTA_MEM,   /* the value last known at this address. */
    CHEEVOS_VAR_TYPE_DYNAMIC_VAR, /* a custom user-set variable */
@@ -62,7 +61,7 @@ enum
 
 enum
 {
-   CHEEVOS_COND_OP_EQUALS = 0,
+   CHEEVOS_COND_OP_EQUALS,
    CHEEVOS_COND_OP_LESS_THAN,
    CHEEVOS_COND_OP_LESS_THAN_OR_EQUAL,
    CHEEVOS_COND_OP_GREATER_THAN,
@@ -74,7 +73,7 @@ enum
 
 enum
 {
-   CHEEVOS_COND_TYPE_STANDARD = 0,
+   CHEEVOS_COND_TYPE_STANDARD,
    CHEEVOS_COND_TYPE_PAUSE_IF,
    CHEEVOS_COND_TYPE_RESET_IF,
 
@@ -883,6 +882,8 @@ Test all the achievements (call once per frame).
 
 static const uint8_t *get_memory(unsigned offset)
 {
+   static const uint8_t zeroes[4] = {0};
+   
    size_t size = core.retro_get_memory_size( RETRO_MEMORY_SYSTEM_RAM );
    uint8_t *memory;
 
@@ -919,7 +920,7 @@ static const uint8_t *get_memory(unsigned offset)
       return memory + offset;
    }
 
-   return NULL;
+   return zeroes;
 }
 
 static unsigned get_var_value(cheevos_var_t *var)
@@ -1501,6 +1502,7 @@ static int cheevos_deactivate_unlocks(unsigned game_id, retro_time_t *timeout)
    return -1;
 }
 
+#define CHEEVOS_SIX_MB   (6 * 1024 * 1024)
 #define CHEEVOS_EIGHT_MB (8 * 1024 * 1024)
 
 static size_t cheevos_eval_md5(const struct retro_game_info *info, MD5_CTX *ctx)
@@ -1598,12 +1600,41 @@ static unsigned cheevos_find_game_id_snes(const struct retro_game_info *info, re
    return cheevos_get_game_id(hash, &to);
 }
 
+static unsigned cheevos_find_game_id_genesis(const struct retro_game_info *info, retro_time_t timeout)
+{
+   MD5_CTX ctx;
+   uint8_t hash[16];
+   retro_time_t to;
+   size_t size;
+   
+   size = cheevos_eval_md5(info, &ctx);
+   
+   if (!size)
+   {
+      MD5_Final(hash, &ctx);
+      return 0;
+   }
+   
+   cheevos_fill_md5(size, CHEEVOS_SIX_MB, &ctx);
+   MD5_Final(hash, &ctx);
+   
+   to = timeout;
+   return cheevos_get_game_id(hash, &to);
+}
+
+static unsigned cheevos_find_game_id_nes(const struct retro_game_info *info, retro_time_t timeout)
+{
+   return 0;
+}
+
 int cheevos_load(const struct retro_game_info *info)
 {
    static const cheevos_id_finder_t finders[] =
    {
+      cheevos_find_game_id_genesis,
       cheevos_find_game_id_generic,
-      cheevos_find_game_id_snes
+      cheevos_find_game_id_snes,
+      cheevos_find_game_id_nes,
    };
    
    retro_time_t timeout = 5000000;