mirror of
https://github.com/libretro/RetroArch.git
synced 2026-11-07 08:36:02 -10:00
cheevos: hash CISO GameCube/Wii images
rc_hash reads a .ciso file through formats/ciso as the disc image it stands for, the way RVZ and WIA files are read, so a CISO identifies as its ISO does. The file reader lives in cheevos/cheevos_ciso.c: it reads on the descriptor path, straight into the buffer rc_hash gives, and seeks only when the file is not already where a read starts. The reader is now built with cheevos as well as with the database. ciso_hash_test hashes a GameCube disc as an ISO and as a CISO with blocks left out, and checks the two hashes match.
This commit is contained in:
1 parent
aa3228069f
commit
f3774dba7c
8 files changed
+482
-3
No files matched your search
@@ -3020,6 +3020,25 @@ jobs:
|
||||
make clean TARGET=progress_bounds_test.exe
|
||||
echo "[pass] progress_bounds_test (ASan + UBSan, and a mingw-w64 build)"
|
||||
|
||||
- name: Build and run ciso_hash_test (ASan + UBSan)
|
||||
shell: bash
|
||||
working-directory: samples/cheevos/ciso_hash
|
||||
run: |
|
||||
set -eu
|
||||
# rc_hash reads a CISO through cheevos/cheevos_ciso.c as the
|
||||
# disc image it stands for: a GameCube disc with blocks left
|
||||
# out of the CISO must hash the same as its ISO, and the
|
||||
# console check must tell GameCube, Wii and not-CISO apart.
|
||||
make clean && make SANITIZER=address,undefined
|
||||
ciso_dir="$(mktemp -d)"
|
||||
ASAN_OPTIONS=detect_leaks=1 timeout 60 ./ciso_hash_test "$ciso_dir"
|
||||
rm -rf "${ciso_dir:?}"
|
||||
make clean
|
||||
make CC=x86_64-w64-mingw32-gcc TARGET=ciso_hash_test.exe
|
||||
test -f ciso_hash_test.exe
|
||||
make clean TARGET=ciso_hash_test.exe
|
||||
echo "[pass] ciso_hash_test (ASan + UBSan, and a mingw-w64 build)"
|
||||
|
||||
- name: Build and run psp1_gfx_contracts_test (ASan + UBSan)
|
||||
shell: bash
|
||||
working-directory: samples/gfx/psp1_gfx_contracts
|
||||
|
||||
@@ -2862,6 +2862,13 @@ ifeq ($(HAVE_NETWORKING), 1)
|
||||
endif
|
||||
endif
|
||||
|
||||
# CISO disc images for RetroAchievements; the scanner builds the
|
||||
# reader with the database
|
||||
OBJ += cheevos/cheevos_ciso.o
|
||||
ifneq ($(HAVE_LIBRETRODB), 1)
|
||||
OBJ += $(LIBRETRO_COMM_DIR)/formats/ciso/ciso.o
|
||||
endif
|
||||
|
||||
# The hashes' AES (3DS titles) is the crypto library's wherever
|
||||
# crypto.o is built, rcheevos' own elsewhere.
|
||||
ifneq ($(filter 1,$(HAVE_CRYPTO) $(HAVE_CHEEVOS_RVZ)),)
|
||||
|
||||
+9
-3
@@ -59,6 +59,7 @@
|
||||
#endif
|
||||
|
||||
#include "cheevos.h"
|
||||
#include "cheevos_ciso.h"
|
||||
#include "cheevos_client.h"
|
||||
#include "cheevos_menu.h"
|
||||
#include "cheevos_locals.h"
|
||||
@@ -2147,8 +2148,8 @@ bool rcheevos_load(const void *data)
|
||||
|
||||
#ifdef CHEEVOS_RVZ_READER
|
||||
/* The file reader is kept from one load to the next, so it is
|
||||
* set for every load: the RVZ one for a file it reads, the
|
||||
* default for anything else. */
|
||||
* set for every load: the RVZ or CISO one for a file it reads,
|
||||
* the default for anything else. */
|
||||
const char* ext = path_get_extension(info->path);
|
||||
if ( (string_is_equal_noncase(ext, "rvz") || string_is_equal_noncase(ext, "wia"))
|
||||
&& (console_id = rcheevos_rvz_get_console_id(info->path))
|
||||
@@ -2164,8 +2165,13 @@ bool rcheevos_load(const void *data)
|
||||
rc_hash_init_custom_filereader(&filereader);
|
||||
}
|
||||
else
|
||||
rc_hash_init_custom_filereader(NULL);
|
||||
#endif
|
||||
if ( string_is_equal_noncase(path_get_extension(info->path), "ciso")
|
||||
&& (console_id = rcheevos_ciso_get_console_id(info->path))
|
||||
!= RC_CONSOLE_UNKNOWN)
|
||||
rcheevos_ciso_filereader_init();
|
||||
else
|
||||
rc_hash_init_custom_filereader(NULL);
|
||||
|
||||
{
|
||||
#ifdef HAVE_THREADS
|
||||
|
||||
@@ -0,0 +1,173 @@
|
||||
/* RetroArch - A frontend for libretro.
|
||||
* Copyright (C) 2026 - The RetroArch team
|
||||
*
|
||||
* RetroArch 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 Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* RetroArch 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 for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with RetroArch.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* rc_hash reads a CISO file through these as the disc image it stands
|
||||
* for. formats/ciso does no file I/O: what it asks for is read here,
|
||||
* on the descriptor path, straight to where it asks - which is always
|
||||
* the buffer rc_hash gave. */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <boolean.h>
|
||||
#include <formats/ciso.h>
|
||||
#include <streams/file_stream.h>
|
||||
|
||||
#include "../deps/rcheevos/include/rc_consoles.h"
|
||||
#include "../deps/rcheevos/include/rc_hash.h"
|
||||
|
||||
#include "cheevos_ciso.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int64_t pos; /* in the disc image */
|
||||
uint64_t file_pos; /* where the file stands; seeks to it are skipped */
|
||||
ciso_t *ciso;
|
||||
RFILE *file;
|
||||
} rcheevos_ciso_t;
|
||||
|
||||
/* Runs an operation's step until it is done, reading what it asks */
|
||||
static int rcheevos_ciso_pump(rcheevos_ciso_t *handle, bool opening)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
ciso_request_t req;
|
||||
int64_t got = 0;
|
||||
int err = opening
|
||||
? ciso_open_step(handle->ciso, &req)
|
||||
: ciso_read_step(handle->ciso, &req);
|
||||
|
||||
if (err != CISO_PENDING)
|
||||
return err;
|
||||
if ( handle->file_pos == req.offset
|
||||
|| filestream_seek(handle->file, (int64_t)req.offset,
|
||||
RETRO_VFS_SEEK_POSITION_START) == 0)
|
||||
got = filestream_read(handle->file, req.dst, (int64_t)req.length);
|
||||
/* unknown after a failed read: seek next time */
|
||||
handle->file_pos = got > 0 ? req.offset + (uint64_t)got : ~(uint64_t)0;
|
||||
ciso_feed(handle->ciso, got > 0 ? (size_t)got : 0);
|
||||
}
|
||||
}
|
||||
|
||||
static void RC_CCONV rcheevos_ciso_close(void *file_handle)
|
||||
{
|
||||
rcheevos_ciso_t *handle = (rcheevos_ciso_t*)file_handle;
|
||||
|
||||
if (handle)
|
||||
{
|
||||
ciso_free(handle->ciso);
|
||||
if (handle->file)
|
||||
filestream_close(handle->file);
|
||||
free(handle);
|
||||
}
|
||||
}
|
||||
|
||||
static void* RC_CCONV rcheevos_ciso_open(const char *path)
|
||||
{
|
||||
rcheevos_ciso_t *handle = (rcheevos_ciso_t*)malloc(sizeof(*handle));
|
||||
|
||||
if (!handle)
|
||||
return NULL;
|
||||
handle->pos = 0;
|
||||
handle->file_pos = 0;
|
||||
handle->ciso = NULL;
|
||||
/* the descriptor path: no stdio buffer between the file and the
|
||||
* buffers rc_hash reads into */
|
||||
if ( !(handle->file = filestream_open(path, RETRO_VFS_FILE_ACCESS_READ,
|
||||
RETRO_VFS_FILE_ACCESS_HINT_SEQUENTIAL_BULK))
|
||||
|| !(handle->ciso = ciso_new())
|
||||
|| rcheevos_ciso_pump(handle, true) != CISO_OK)
|
||||
{
|
||||
rcheevos_ciso_close(handle);
|
||||
return NULL;
|
||||
}
|
||||
return handle;
|
||||
}
|
||||
|
||||
static void RC_CCONV rcheevos_ciso_seek(void *file_handle, int64_t offset,
|
||||
int origin)
|
||||
{
|
||||
rcheevos_ciso_t *handle = (rcheevos_ciso_t*)file_handle;
|
||||
|
||||
switch (origin)
|
||||
{
|
||||
case SEEK_SET:
|
||||
handle->pos = offset;
|
||||
break;
|
||||
case SEEK_CUR:
|
||||
handle->pos += offset;
|
||||
break;
|
||||
case SEEK_END:
|
||||
handle->pos = (int64_t)ciso_disc_size(handle->ciso) + offset;
|
||||
break;
|
||||
}
|
||||
if (handle->pos < 0)
|
||||
handle->pos = 0;
|
||||
}
|
||||
|
||||
static int64_t RC_CCONV rcheevos_ciso_tell(void *file_handle)
|
||||
{
|
||||
return ((rcheevos_ciso_t*)file_handle)->pos;
|
||||
}
|
||||
|
||||
static size_t RC_CCONV rcheevos_ciso_read(void *file_handle, void *buffer,
|
||||
size_t requested_bytes)
|
||||
{
|
||||
rcheevos_ciso_t *handle = (rcheevos_ciso_t*)file_handle;
|
||||
size_t got;
|
||||
|
||||
if (ciso_read_begin(handle->ciso, (uint64_t)handle->pos,
|
||||
buffer, requested_bytes) != CISO_OK)
|
||||
return 0;
|
||||
rcheevos_ciso_pump(handle, false);
|
||||
/* what came before a failure is still read */
|
||||
got = ciso_read_progress(handle->ciso);
|
||||
handle->pos += (int64_t)got;
|
||||
return got;
|
||||
}
|
||||
|
||||
uint32_t rcheevos_ciso_get_console_id(const char *path)
|
||||
{
|
||||
uint8_t magic[8];
|
||||
uint32_t console_id = RC_CONSOLE_UNKNOWN;
|
||||
rcheevos_ciso_t *handle = (rcheevos_ciso_t*)rcheevos_ciso_open(path);
|
||||
|
||||
if (!handle)
|
||||
return console_id;
|
||||
rcheevos_ciso_seek(handle, 0x18, SEEK_SET);
|
||||
if (rcheevos_ciso_read(handle, magic, sizeof(magic)) == sizeof(magic))
|
||||
{
|
||||
if ( magic[0] == 0x5D && magic[1] == 0x1C
|
||||
&& magic[2] == 0x9E && magic[3] == 0xA3)
|
||||
console_id = RC_CONSOLE_WII;
|
||||
else if (magic[4] == 0xC2 && magic[5] == 0x33
|
||||
&& magic[6] == 0x9F && magic[7] == 0x3D)
|
||||
console_id = RC_CONSOLE_GAMECUBE;
|
||||
}
|
||||
rcheevos_ciso_close(handle);
|
||||
return console_id;
|
||||
}
|
||||
|
||||
void rcheevos_ciso_filereader_init(void)
|
||||
{
|
||||
struct rc_hash_filereader filereader;
|
||||
|
||||
filereader.open = rcheevos_ciso_open;
|
||||
filereader.seek = rcheevos_ciso_seek;
|
||||
filereader.tell = rcheevos_ciso_tell;
|
||||
filereader.read = rcheevos_ciso_read;
|
||||
filereader.close = rcheevos_ciso_close;
|
||||
rc_hash_init_custom_filereader(&filereader);
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/* RetroArch - A frontend for libretro.
|
||||
* Copyright (C) 2026 - The RetroArch team
|
||||
*
|
||||
* RetroArch 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 Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* RetroArch 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 for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with RetroArch.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __RARCH_CHEEVOS_CISO_H
|
||||
#define __RARCH_CHEEVOS_CISO_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <retro_common_api.h>
|
||||
|
||||
RETRO_BEGIN_DECLS
|
||||
|
||||
/* RC_CONSOLE_GAMECUBE or RC_CONSOLE_WII for a CISO file of either's
|
||||
* disc, RC_CONSOLE_UNKNOWN for anything else */
|
||||
uint32_t rcheevos_ciso_get_console_id(const char *path);
|
||||
|
||||
/* Has rc_hash read files as CISO disc images */
|
||||
void rcheevos_ciso_filereader_init(void);
|
||||
|
||||
RETRO_END_DECLS
|
||||
|
||||
#endif
|
||||
@@ -234,6 +234,7 @@ ACHIEVEMENTS
|
||||
#include "../cheevos/cheevos_client.c"
|
||||
#include "../cheevos/cheevos_menu.c"
|
||||
#include "../cheevos/cheevos_badge.c"
|
||||
#include "../cheevos/cheevos_ciso.c"
|
||||
|
||||
#if defined(HAVE_CHEEVOS_RVZ) && defined(HAVE_RZSTD)
|
||||
#include "../libretro-common/formats/rvz/rvz.c"
|
||||
@@ -1850,6 +1851,8 @@ DATA RUNLOOP
|
||||
#include "../tasks/task_database.c"
|
||||
#ifdef HAVE_LIBRETRODB
|
||||
#include "../tasks/task_database_cue.c"
|
||||
#endif
|
||||
#if defined(HAVE_LIBRETRODB) || defined(HAVE_CHEEVOS)
|
||||
#include "../libretro-common/formats/ciso/ciso.c"
|
||||
#endif
|
||||
#if defined(HAVE_NETWORKING) && defined(HAVE_MENU)
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
TARGET := ciso_hash_test
|
||||
|
||||
# rc_hash over a CISO through cheevos/cheevos_ciso.c, against the same
|
||||
# disc as an ISO.
|
||||
# make && make check
|
||||
REPO_ROOT := ../../..
|
||||
RC := $(REPO_ROOT)/deps/rcheevos
|
||||
LRC := $(REPO_ROOT)/libretro-common
|
||||
|
||||
CFLAGS += -Wall -std=gnu99 -g1 -O1 -I$(RC)/include -I$(LRC)/include \
|
||||
-DRC_CLIENT_SUPPORTS_HASH -DRC_NO_THREADS
|
||||
|
||||
ifneq ($(SANITIZER),)
|
||||
CFLAGS += -fsanitize=$(SANITIZER) -fno-omit-frame-pointer
|
||||
LDFLAGS += -fsanitize=$(SANITIZER)
|
||||
endif
|
||||
ifneq ($(findstring undefined,$(SANITIZER)),)
|
||||
CFLAGS += -fno-sanitize-recover=undefined
|
||||
LDFLAGS += -fno-sanitize-recover=undefined
|
||||
endif
|
||||
|
||||
SOURCES := ciso_hash_test.c \
|
||||
$(REPO_ROOT)/cheevos/cheevos_ciso.c \
|
||||
$(LRC)/formats/ciso/ciso.c \
|
||||
$(RC)/src/rhash/hash.c \
|
||||
$(RC)/src/rhash/hash_disc.c \
|
||||
$(RC)/src/rhash/hash_encrypted.c \
|
||||
$(RC)/src/rhash/hash_rom.c \
|
||||
$(RC)/src/rhash/hash_zip.c \
|
||||
$(RC)/src/rhash/cdreader.c \
|
||||
$(RC)/src/rhash/aes.c \
|
||||
$(RC)/src/rc_util.c \
|
||||
$(RC)/src/rc_compat.c \
|
||||
$(LRC)/utils/md5.c \
|
||||
$(LRC)/streams/file_stream.c \
|
||||
$(LRC)/vfs/vfs_implementation.c \
|
||||
$(LRC)/file/file_path.c \
|
||||
$(LRC)/file/file_path_io.c \
|
||||
$(LRC)/string/stdstring.c \
|
||||
$(LRC)/string/rstrtod.c \
|
||||
$(LRC)/encodings/encoding_utf.c \
|
||||
$(LRC)/compat/compat_strl.c \
|
||||
$(LRC)/compat/compat_posix_string.c \
|
||||
$(LRC)/compat/fopen_utf8.c \
|
||||
$(LRC)/features/features_cpu.c \
|
||||
$(LRC)/time/rtime.c
|
||||
|
||||
all: $(TARGET)
|
||||
|
||||
$(TARGET): $(SOURCES)
|
||||
$(CC) $(CFLAGS) -o $@ $(SOURCES) $(LDFLAGS) -lm
|
||||
|
||||
check: $(TARGET)
|
||||
./$(TARGET)
|
||||
|
||||
clean:
|
||||
rm -f $(TARGET) $(TARGET).exe
|
||||
|
||||
.PHONY: all check clean
|
||||
@@ -0,0 +1,178 @@
|
||||
/* ciso_hash_test: rc_hash reads a CISO file through
|
||||
* cheevos/cheevos_ciso.c as the disc image it stands for, so a
|
||||
* GameCube disc hashes the same as a CISO and as an ISO.
|
||||
*
|
||||
* The disc made up here has its headers, apploader and main.dol
|
||||
* where rc_hash looks for them, segments that cross block edges, and
|
||||
* runs of blocks left out of the CISO between them. A Wii header and
|
||||
* a file that is not CISO are told apart by the console check.
|
||||
*
|
||||
* Usage: ciso_hash_test [dir], the files written there (default .). */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <boolean.h>
|
||||
#include <file/file_path.h>
|
||||
#include <streams/file_stream.h>
|
||||
|
||||
#include "../../../deps/rcheevos/include/rc_consoles.h"
|
||||
#include "../../../deps/rcheevos/include/rc_hash.h"
|
||||
#include "../../../cheevos/cheevos_ciso.h"
|
||||
|
||||
#define BLOCK 0x8000
|
||||
#define BLOCKS 16
|
||||
#define HEAD 0x8000
|
||||
|
||||
static int failures = 0;
|
||||
static uint32_t rng_state = 0x9E3779B9u;
|
||||
|
||||
static uint32_t rnd(void)
|
||||
{
|
||||
rng_state ^= rng_state << 13;
|
||||
rng_state ^= rng_state >> 17;
|
||||
rng_state ^= rng_state << 5;
|
||||
return rng_state;
|
||||
}
|
||||
|
||||
static void check(int ok, const char *what)
|
||||
{
|
||||
printf("%s %s\n", ok ? "ok " : "FAIL", what);
|
||||
if (!ok)
|
||||
failures++;
|
||||
}
|
||||
|
||||
static void put32(uint8_t *p, uint32_t v)
|
||||
{
|
||||
p[0] = (uint8_t)(v >> 24);
|
||||
p[1] = (uint8_t)(v >> 16);
|
||||
p[2] = (uint8_t)(v >> 8);
|
||||
p[3] = (uint8_t)v;
|
||||
}
|
||||
|
||||
static int write_file(const char *path, const uint8_t *d, size_t n)
|
||||
{
|
||||
FILE *f = fopen(path, "wb");
|
||||
int ok;
|
||||
if (!f)
|
||||
return 0;
|
||||
ok = fwrite(d, 1, n, f) == n;
|
||||
return fclose(f) == 0 && ok;
|
||||
}
|
||||
|
||||
/* The disc as an ISO and as a CISO of the blocks in @used */
|
||||
static int write_disc(const char *iso, const char *ciso,
|
||||
const uint8_t *used, const uint8_t *id, const uint8_t *magic,
|
||||
unsigned magic_at)
|
||||
{
|
||||
uint8_t *disc = (uint8_t*)calloc(1, (size_t)BLOCKS * BLOCK);
|
||||
uint8_t *file = (uint8_t*)calloc(1, HEAD + (size_t)BLOCKS * BLOCK);
|
||||
size_t at = HEAD;
|
||||
size_t i;
|
||||
int ok;
|
||||
|
||||
if (!disc || !file)
|
||||
{
|
||||
free(disc);
|
||||
free(file);
|
||||
return 0;
|
||||
}
|
||||
for (i = 0; i < (size_t)BLOCKS * BLOCK; i++)
|
||||
if (used[i / BLOCK])
|
||||
disc[i] = (uint8_t)rnd();
|
||||
|
||||
memcpy(disc, id, 6);
|
||||
memcpy(disc + magic_at, magic, 4);
|
||||
/* apploader: 0x1000 octets of body, no trailer */
|
||||
put32(disc + 0x2440 + 0x14, 0x1000);
|
||||
put32(disc + 0x2440 + 0x18, 0);
|
||||
/* main.dol at block 8: a code segment over blocks 9 and 10, a data
|
||||
* segment from block 14 into 15 */
|
||||
put32(disc + 0x420, 0x40000);
|
||||
memset(disc + 0x40000, 0, 0xD8);
|
||||
put32(disc + 0x40000 + 0x00, 0x48000);
|
||||
put32(disc + 0x40000 + 0x90, 0x9000);
|
||||
put32(disc + 0x40000 + 7 * 4, 0x70000);
|
||||
put32(disc + 0x40000 + 0x90 + 7 * 4, 0x8100);
|
||||
|
||||
memcpy(file, "CISO", 4);
|
||||
file[5] = (uint8_t)(BLOCK >> 8);
|
||||
for (i = 0; i < BLOCKS; i++)
|
||||
{
|
||||
file[8 + i] = used[i];
|
||||
if (!used[i])
|
||||
continue;
|
||||
memcpy(file + at, disc + i * BLOCK, BLOCK);
|
||||
at += BLOCK;
|
||||
}
|
||||
|
||||
ok = write_file(iso, disc, (size_t)BLOCKS * BLOCK)
|
||||
&& write_file(ciso, file, at);
|
||||
free(disc);
|
||||
free(file);
|
||||
return ok;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
static const uint8_t used[BLOCKS] =
|
||||
{ 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1 };
|
||||
static const uint8_t gc_magic[4] = { 0xC2, 0x33, 0x9F, 0x3D };
|
||||
static const uint8_t wii_magic[4] = { 0x5D, 0x1C, 0x9E, 0xA3 };
|
||||
const char *dir = argc > 1 ? argv[1] : ".";
|
||||
char iso[1024], ciso[1024], wii_iso[1024], wii_ciso[1024];
|
||||
char h_iso[33], h_ciso[33], h_raw[33];
|
||||
int ok_iso, ok_ciso, ok_raw;
|
||||
|
||||
fill_pathname_join_special(iso, dir, "ciso_hash_gc.iso", sizeof(iso));
|
||||
fill_pathname_join_special(ciso, dir, "ciso_hash_gc.ciso", sizeof(ciso));
|
||||
fill_pathname_join_special(wii_iso, dir, "ciso_hash_wii.iso", sizeof(wii_iso));
|
||||
fill_pathname_join_special(wii_ciso, dir, "ciso_hash_wii.ciso", sizeof(wii_ciso));
|
||||
|
||||
if ( !write_disc(iso, ciso, used, (const uint8_t*)"GALE01",
|
||||
gc_magic, 0x1c)
|
||||
|| !write_disc(wii_iso, wii_ciso, used, (const uint8_t*)"RMCE01",
|
||||
wii_magic, 0x18))
|
||||
{
|
||||
printf("FAIL could not write the images in %s\n", dir);
|
||||
return 1;
|
||||
}
|
||||
|
||||
check(rcheevos_ciso_get_console_id(ciso) == RC_CONSOLE_GAMECUBE,
|
||||
"GameCube CISO identified");
|
||||
check(rcheevos_ciso_get_console_id(wii_ciso) == RC_CONSOLE_WII,
|
||||
"Wii CISO identified");
|
||||
check(rcheevos_ciso_get_console_id(iso) == RC_CONSOLE_UNKNOWN,
|
||||
"an ISO is not taken as CISO");
|
||||
|
||||
memset(h_iso, 0, sizeof(h_iso));
|
||||
memset(h_ciso, 0, sizeof(h_ciso));
|
||||
memset(h_raw, 0, sizeof(h_raw));
|
||||
|
||||
rc_hash_init_custom_filereader(NULL);
|
||||
ok_iso = rc_hash_generate_from_file(h_iso, RC_CONSOLE_GAMECUBE, iso);
|
||||
ok_raw = rc_hash_generate_from_file(h_raw, RC_CONSOLE_GAMECUBE, ciso);
|
||||
rcheevos_ciso_filereader_init();
|
||||
ok_ciso = rc_hash_generate_from_file(h_ciso, RC_CONSOLE_GAMECUBE, ciso);
|
||||
rc_hash_init_custom_filereader(NULL);
|
||||
|
||||
printf(" iso %s\n ciso %s\n", h_iso, h_ciso);
|
||||
check(ok_iso, "ISO hashes");
|
||||
check(!ok_raw, "CISO read as it is stored does not hash");
|
||||
check(ok_ciso && !strcmp(h_iso, h_ciso),
|
||||
"CISO hashes as its disc image");
|
||||
|
||||
filestream_delete(iso);
|
||||
filestream_delete(ciso);
|
||||
filestream_delete(wii_iso);
|
||||
filestream_delete(wii_ciso);
|
||||
|
||||
if (failures)
|
||||
{
|
||||
printf("%d failure(s)\n", failures);
|
||||
return 1;
|
||||
}
|
||||
printf("ciso_hash_test: all passed\n");
|
||||
return 0;
|
||||
}
|
||||
Reference in new issue
Block a user