2015-09-16 20:39:47 +00:00
|
|
|
/* RetroArch - A frontend for libretro.
|
2017-01-22 12:40:32 +00:00
|
|
|
* Copyright (C) 2011-2017 - Daniel De Matteis
|
|
|
|
* Copyright (C) 2014-2017 - Jean-André Santoni
|
2019-02-22 21:31:54 +00:00
|
|
|
* Copyright (C) 2016-2019 - Brad Parker
|
2015-09-16 20:39:47 +00:00
|
|
|
*
|
|
|
|
* 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/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <errno.h>
|
2015-09-25 23:44:47 +00:00
|
|
|
#include <ctype.h>
|
2017-04-23 10:17:51 +00:00
|
|
|
#include <string.h>
|
2015-09-16 20:39:47 +00:00
|
|
|
|
2016-09-11 14:31:23 +00:00
|
|
|
#include <retro_miscellaneous.h>
|
2020-04-21 02:16:55 +00:00
|
|
|
#include <retro_endianness.h>
|
2015-09-16 20:39:47 +00:00
|
|
|
#include <compat/strcasestr.h>
|
|
|
|
#include <compat/strl.h>
|
2016-02-07 00:50:08 +00:00
|
|
|
#include <file/file_path.h>
|
2015-09-16 20:39:47 +00:00
|
|
|
#include <retro_endianness.h>
|
2016-03-20 15:29:14 +00:00
|
|
|
#include <streams/file_stream.h>
|
2017-09-17 05:31:58 +00:00
|
|
|
#include <streams/interface_stream.h>
|
2016-01-20 03:07:24 +00:00
|
|
|
#include <string/stdstring.h>
|
2021-12-30 13:43:02 +00:00
|
|
|
#include "../retroarch.h"
|
2015-09-16 20:39:47 +00:00
|
|
|
|
2016-09-11 14:24:02 +00:00
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
#include "../config.h"
|
|
|
|
#endif
|
2015-09-16 20:39:47 +00:00
|
|
|
|
|
|
|
#include "../database_info.h"
|
|
|
|
|
2016-09-11 14:24:02 +00:00
|
|
|
#include "tasks_internal.h"
|
|
|
|
|
2016-03-20 16:28:24 +00:00
|
|
|
#include "../list_special.h"
|
2015-09-16 20:39:47 +00:00
|
|
|
#include "../msg_hash.h"
|
2015-11-23 11:03:38 +00:00
|
|
|
#include "../verbosity.h"
|
2015-09-16 20:39:47 +00:00
|
|
|
|
2016-09-01 03:53:28 +00:00
|
|
|
#define MAGIC_LEN 17
|
2016-01-28 08:33:09 +00:00
|
|
|
#define MAX_TOKEN_LEN 255
|
2015-09-16 20:39:47 +00:00
|
|
|
|
2016-02-04 09:30:12 +00:00
|
|
|
#ifdef MSB_FIRST
|
|
|
|
#define MODETEST_VAL 0x00ffffff
|
|
|
|
#else
|
|
|
|
#define MODETEST_VAL 0xffffff00
|
|
|
|
#endif
|
|
|
|
|
2020-08-14 16:51:50 +00:00
|
|
|
/* TODO/FIXME - reorder this according to CODING-GUIDELINES
|
|
|
|
* and make sure LUT table below conforms */
|
2015-09-16 20:39:47 +00:00
|
|
|
struct magic_entry
|
|
|
|
{
|
2017-03-07 00:16:26 +00:00
|
|
|
int32_t offset;
|
|
|
|
const char *system_name;
|
|
|
|
const char *magic;
|
2021-12-30 13:43:02 +00:00
|
|
|
int length_magic;
|
2015-09-16 20:39:47 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static struct magic_entry MAGIC_NUMBERS[] = {
|
2021-12-30 13:43:02 +00:00
|
|
|
{ 0x000010, "Sega - Mega-CD - Sega CD", "\x53\x45\x47\x41\x44\x49\x53\x43\x53\x59\x53\x54\x45\x4d", 14},
|
|
|
|
{ 0x000010, "Sega - Saturn", "\x53\x45\x47\x41\x20\x53\x45\x47\x41\x53\x41\x54\x55\x52\x4e", 15},
|
|
|
|
{ 0x000010, "Sega - Dreamcast", "\x53\x45\x47\x41\x20\x53\x45\x47\x41\x4b\x41\x54\x41\x4e\x41", 15},
|
|
|
|
{ 0x000018, "Nintendo - Wii", "\x5d\x1c\x9e\xa3", 4},
|
2022-04-03 02:08:30 +00:00
|
|
|
{ 0x000218, "Nintendo - Wii", "\x5d\x1c\x9e\xa3", 4},
|
2021-12-30 13:43:02 +00:00
|
|
|
{ 0x00001c, "Nintendo - GameCube", "\xc2\x33\x9f\x3d", 4},
|
|
|
|
{ 0x008008, "Sony - PlayStation Portable", "\x50\x53\x50\x20\x47\x41\x4d\x45", 8},
|
|
|
|
{ 0x008008, "Sony - PlayStation", "\x50\x4c\x41\x59\x53\x54\x41\x54\x49\x4f\x4e", 11},
|
|
|
|
{ 0x009320, "Sony - PlayStation", "\x50\x4c\x41\x59\x53\x54\x41\x54\x49\x4f\x4e", 11},
|
|
|
|
{ 0, NULL, NULL, 0}
|
2015-09-16 20:39:47 +00:00
|
|
|
};
|
|
|
|
|
2021-12-30 13:43:02 +00:00
|
|
|
/**
|
|
|
|
* Given a filename and position, find the associated disc number.
|
|
|
|
*/
|
|
|
|
int cue_find_disc_number(const char* str1, int index)
|
|
|
|
{
|
|
|
|
char disc;
|
|
|
|
int disc_number = 0;
|
|
|
|
|
|
|
|
disc = str1[index + 6];
|
|
|
|
|
|
|
|
switch(disc)
|
|
|
|
{
|
|
|
|
case 'a':
|
|
|
|
case 'A':
|
|
|
|
disc_number = 1;
|
|
|
|
break;
|
|
|
|
case 'b':
|
|
|
|
case 'B':
|
|
|
|
disc_number = 2;
|
|
|
|
break;
|
|
|
|
case 'c':
|
|
|
|
case 'C':
|
|
|
|
disc_number = 3;
|
|
|
|
break;
|
|
|
|
case 'd':
|
|
|
|
case 'D':
|
|
|
|
disc_number = 4;
|
|
|
|
break;
|
|
|
|
case 'e':
|
|
|
|
case 'E':
|
|
|
|
disc_number = 5;
|
|
|
|
break;
|
|
|
|
case 'f':
|
|
|
|
case 'F':
|
|
|
|
disc_number = 6;
|
|
|
|
break;
|
|
|
|
case 'g':
|
|
|
|
case 'G':
|
|
|
|
disc_number = 7;
|
|
|
|
break;
|
|
|
|
case 'h':
|
|
|
|
case 'H':
|
|
|
|
disc_number = 8;
|
|
|
|
break;
|
|
|
|
case 'i':
|
|
|
|
case 'I':
|
|
|
|
disc_number = 9;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
disc_number = disc - '0';
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (disc_number >= 1)
|
|
|
|
return disc_number;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Given a title and filename, append the appropriate disc number to it.
|
|
|
|
*/
|
|
|
|
void cue_append_multi_disc_suffix(char * str1, const char *filename)
|
|
|
|
{
|
|
|
|
char *dest = str1;
|
|
|
|
int result = 0;
|
|
|
|
int disc_number = 0;
|
|
|
|
|
|
|
|
/** check multi-disc and insert suffix **/
|
|
|
|
result = string_find_index_substring_string(filename, "(Disc ");
|
|
|
|
if (result < 0)
|
|
|
|
result = string_find_index_substring_string(filename, "(disc ");
|
|
|
|
if (result < 0)
|
|
|
|
result = string_find_index_substring_string(filename, "(Disk ");
|
|
|
|
if (result < 0)
|
|
|
|
result = string_find_index_substring_string(filename, "(disk ");
|
|
|
|
if (result >= 0)
|
|
|
|
{
|
|
|
|
disc_number = cue_find_disc_number(filename, result);
|
|
|
|
if (disc_number > 0)
|
|
|
|
sprintf(dest+strlen(dest), "-%i", disc_number - 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-12 22:18:11 +00:00
|
|
|
static int64_t get_token(intfstream_t *fd, char *token, uint64_t max_len)
|
2015-09-16 20:39:47 +00:00
|
|
|
{
|
|
|
|
char *c = token;
|
2018-04-12 22:18:11 +00:00
|
|
|
int64_t len = 0;
|
2015-09-16 20:39:47 +00:00
|
|
|
int in_string = 0;
|
|
|
|
|
2020-01-30 15:15:52 +00:00
|
|
|
for (;;)
|
2015-09-16 20:39:47 +00:00
|
|
|
{
|
2018-04-12 22:18:11 +00:00
|
|
|
int64_t rv = (int64_t)intfstream_read(fd, c, 1);
|
2015-09-16 20:39:47 +00:00
|
|
|
if (rv == 0)
|
|
|
|
return 0;
|
2015-09-18 02:03:11 +00:00
|
|
|
|
|
|
|
if (rv < 1)
|
2015-09-16 20:39:47 +00:00
|
|
|
{
|
|
|
|
switch (errno)
|
|
|
|
{
|
|
|
|
case EINTR:
|
|
|
|
case EAGAIN:
|
|
|
|
continue;
|
|
|
|
default:
|
|
|
|
return -errno;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (*c)
|
|
|
|
{
|
|
|
|
case ' ':
|
|
|
|
case '\t':
|
|
|
|
case '\r':
|
|
|
|
case '\n':
|
|
|
|
if (c == token)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (!in_string)
|
|
|
|
{
|
|
|
|
*c = '\0';
|
|
|
|
return len;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case '\"':
|
|
|
|
if (c == token)
|
|
|
|
{
|
|
|
|
in_string = 1;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
*c = '\0';
|
|
|
|
return len;
|
|
|
|
}
|
|
|
|
|
|
|
|
len++;
|
|
|
|
c++;
|
2018-04-12 22:18:11 +00:00
|
|
|
if (len == (int64_t)max_len)
|
2015-09-16 20:39:47 +00:00
|
|
|
{
|
|
|
|
*c = '\0';
|
|
|
|
return len;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-30 13:43:02 +00:00
|
|
|
int detect_ps1_game(intfstream_t *fd, char *game_id, const char *filename)
|
2015-09-25 22:05:15 +00:00
|
|
|
{
|
2021-12-30 13:43:02 +00:00
|
|
|
#define DISC_DATA_SIZE_PS1 60000
|
|
|
|
int pos;
|
|
|
|
char raw_game_id[50];
|
|
|
|
char disc_data[DISC_DATA_SIZE_PS1];
|
|
|
|
char hyphen = '-';
|
|
|
|
|
|
|
|
/* Load data into buffer and use pointers */
|
|
|
|
if (intfstream_seek(fd, 0, SEEK_SET) < 0)
|
|
|
|
return false;
|
2015-09-25 22:05:15 +00:00
|
|
|
|
2021-12-30 13:43:02 +00:00
|
|
|
if (intfstream_read(fd, disc_data, DISC_DATA_SIZE_PS1) <= 0)
|
|
|
|
return false;
|
2017-09-26 01:51:50 +00:00
|
|
|
|
2021-12-30 13:43:02 +00:00
|
|
|
disc_data[DISC_DATA_SIZE_PS1 - 1] = '\0';
|
2015-09-25 22:05:15 +00:00
|
|
|
|
2021-12-30 13:43:02 +00:00
|
|
|
for (pos = 0; pos < DISC_DATA_SIZE_PS1; pos++)
|
2015-09-25 22:05:15 +00:00
|
|
|
{
|
2021-12-30 13:43:02 +00:00
|
|
|
strncpy(raw_game_id, &disc_data[pos], 12);
|
2022-07-30 16:31:05 +00:00
|
|
|
raw_game_id[12] = '\0';
|
|
|
|
if ( string_is_equal_fast(raw_game_id, "S", STRLEN_CONST("S"))
|
|
|
|
|| string_is_equal_fast(raw_game_id, "E", STRLEN_CONST("E")))
|
2015-09-25 22:05:15 +00:00
|
|
|
{
|
2021-12-30 13:43:02 +00:00
|
|
|
if (
|
2022-07-30 16:31:05 +00:00
|
|
|
( string_is_equal_fast(raw_game_id, "SCUS_", STRLEN_CONST("SCUS_")))
|
|
|
|
|| (string_is_equal_fast(raw_game_id, "SLUS_", STRLEN_CONST("SLUS_")))
|
|
|
|
|| (string_is_equal_fast(raw_game_id, "SLES_", STRLEN_CONST("SLES_")))
|
|
|
|
|| (string_is_equal_fast(raw_game_id, "SCED_", STRLEN_CONST("SCED_")))
|
|
|
|
|| (string_is_equal_fast(raw_game_id, "SLPS_", STRLEN_CONST("SLPS_")))
|
|
|
|
|| (string_is_equal_fast(raw_game_id, "SLPM_", STRLEN_CONST("SLPM_")))
|
|
|
|
|| (string_is_equal_fast(raw_game_id, "SCPS_", STRLEN_CONST("SCPS_")))
|
|
|
|
|| (string_is_equal_fast(raw_game_id, "SLED_", STRLEN_CONST("SLED_")))
|
|
|
|
|| (string_is_equal_fast(raw_game_id, "SIPS_", STRLEN_CONST("SIPS_")))
|
|
|
|
|| (string_is_equal_fast(raw_game_id, "ESPM_", STRLEN_CONST("ESPM_")))
|
|
|
|
|| (string_is_equal_fast(raw_game_id, "SCES_", STRLEN_CONST("SCES_")))
|
2021-12-30 13:43:02 +00:00
|
|
|
)
|
|
|
|
{
|
|
|
|
raw_game_id[4] = hyphen;
|
2022-07-30 16:31:05 +00:00
|
|
|
if (string_is_equal_fast(&raw_game_id[8], ".", STRLEN_CONST(".")))
|
2021-12-30 13:43:02 +00:00
|
|
|
{
|
|
|
|
raw_game_id[8] = raw_game_id[9];
|
|
|
|
raw_game_id[9] = raw_game_id[10];
|
|
|
|
}
|
2022-07-30 16:22:04 +00:00
|
|
|
/* A few games have their serial in the form of xx.xxx */
|
|
|
|
/* Tanaka Torahiko no Ultra-ryuu Shougi - Ibisha Anaguma-hen (Japan) -> SLPS_02.261 */
|
2022-07-30 16:31:05 +00:00
|
|
|
else if (string_is_equal_fast(&raw_game_id[7], ".", STRLEN_CONST(".")))
|
2022-07-30 16:22:04 +00:00
|
|
|
{
|
|
|
|
raw_game_id[7] = raw_game_id[8];
|
|
|
|
raw_game_id[8] = raw_game_id[9];
|
|
|
|
raw_game_id[9] = raw_game_id[10];
|
|
|
|
}
|
2021-12-30 13:43:02 +00:00
|
|
|
raw_game_id[10] = '\0';
|
2017-09-26 01:51:50 +00:00
|
|
|
|
2021-12-30 13:43:02 +00:00
|
|
|
string_remove_all_whitespace(game_id, raw_game_id);
|
|
|
|
cue_append_multi_disc_suffix(game_id, filename);
|
|
|
|
return true;
|
|
|
|
}
|
2022-07-30 16:31:05 +00:00
|
|
|
else if (string_is_equal_fast(&disc_data[pos], "LSP-", STRLEN_CONST("LSP-")))
|
2021-12-30 13:43:02 +00:00
|
|
|
{
|
|
|
|
string_remove_all_whitespace(game_id, raw_game_id);
|
|
|
|
game_id[10] = '\0';
|
|
|
|
cue_append_multi_disc_suffix(game_id, filename);
|
|
|
|
return true;
|
|
|
|
}
|
2015-09-25 22:05:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-30 13:43:02 +00:00
|
|
|
strcpy(game_id, "XXXXXXXXXX");
|
|
|
|
game_id[10] = '\0';
|
|
|
|
cue_append_multi_disc_suffix(game_id, filename);
|
2022-07-25 20:41:32 +00:00
|
|
|
return false;
|
2021-12-30 13:43:02 +00:00
|
|
|
}
|
2015-09-25 22:05:15 +00:00
|
|
|
|
2021-12-30 13:43:02 +00:00
|
|
|
int detect_psp_game(intfstream_t *fd, char *game_id, const char *filename)
|
|
|
|
{
|
|
|
|
#define DISC_DATA_SIZE_PSP 40000
|
|
|
|
int pos;
|
|
|
|
char disc_data[DISC_DATA_SIZE_PSP];
|
2017-09-26 01:51:50 +00:00
|
|
|
|
2021-12-30 13:43:02 +00:00
|
|
|
/* Load data into buffer and use pointers */
|
|
|
|
if (intfstream_seek(fd, 0, SEEK_SET) < 0)
|
|
|
|
return false;
|
2015-09-25 22:05:15 +00:00
|
|
|
|
2021-12-30 13:43:02 +00:00
|
|
|
if (intfstream_read(fd, disc_data, DISC_DATA_SIZE_PSP) <= 0)
|
|
|
|
return false;
|
2017-09-26 01:51:50 +00:00
|
|
|
|
2021-12-30 13:43:02 +00:00
|
|
|
disc_data[DISC_DATA_SIZE_PSP - 1] = '\0';
|
2015-09-25 22:05:15 +00:00
|
|
|
|
2021-12-30 13:43:02 +00:00
|
|
|
for (pos = 0; pos < DISC_DATA_SIZE_PSP; pos++)
|
2015-09-25 22:05:15 +00:00
|
|
|
{
|
2021-12-30 13:43:02 +00:00
|
|
|
strncpy(game_id, &disc_data[pos], 10);
|
|
|
|
game_id[10] = '\0';
|
2022-07-30 16:31:05 +00:00
|
|
|
if ( string_is_equal_fast(game_id, "U", STRLEN_CONST("U"))
|
|
|
|
|| string_is_equal_fast(game_id, "N", STRLEN_CONST("N")))
|
2021-12-30 13:43:02 +00:00
|
|
|
{
|
|
|
|
if (
|
2022-07-30 16:31:05 +00:00
|
|
|
( string_is_equal_fast(game_id, "ULES-", STRLEN_CONST("ULES-")))
|
|
|
|
|| (string_is_equal_fast(game_id, "ULUS-", STRLEN_CONST("ULUS-")))
|
|
|
|
|| (string_is_equal_fast(game_id, "ULJS-", STRLEN_CONST("ULJS-")))
|
|
|
|
|
|
|
|
|| (string_is_equal_fast(game_id, "ULEM-", STRLEN_CONST("ULEM-")))
|
|
|
|
|| (string_is_equal_fast(game_id, "ULUM-", STRLEN_CONST("ULUM-")))
|
|
|
|
|| (string_is_equal_fast(game_id, "ULJM-", STRLEN_CONST("ULJM-")))
|
|
|
|
|
|
|
|
|| (string_is_equal_fast(game_id, "UCES-", STRLEN_CONST("UCES-")))
|
|
|
|
|| (string_is_equal_fast(game_id, "UCUS-", STRLEN_CONST("UCUS-")))
|
|
|
|
|| (string_is_equal_fast(game_id, "UCJS-", STRLEN_CONST("UCJS-")))
|
|
|
|
|| (string_is_equal_fast(game_id, "UCAS-", STRLEN_CONST("UCAS-")))
|
|
|
|
|| (string_is_equal_fast(game_id, "UCKS-", STRLEN_CONST("UCKS-")))
|
|
|
|
|
|
|
|
|| (string_is_equal_fast(game_id, "ULKS-", STRLEN_CONST("ULKS-")))
|
|
|
|
|| (string_is_equal_fast(game_id, "ULAS-", STRLEN_CONST("ULAS-")))
|
|
|
|
|| (string_is_equal_fast(game_id, "NPEH-", STRLEN_CONST("NPEH-")))
|
|
|
|
|| (string_is_equal_fast(game_id, "NPUH-", STRLEN_CONST("NPUH-")))
|
|
|
|
|| (string_is_equal_fast(game_id, "NPJH-", STRLEN_CONST("NPJH-")))
|
|
|
|
|| (string_is_equal_fast(game_id, "NPHH-", STRLEN_CONST("NPHH-")))
|
|
|
|
|
|
|
|
|| (string_is_equal_fast(game_id, "NPEG-", STRLEN_CONST("NPEG-")))
|
|
|
|
|| (string_is_equal_fast(game_id, "NPUG-", STRLEN_CONST("NPUG-")))
|
|
|
|
|| (string_is_equal_fast(game_id, "NPJG-", STRLEN_CONST("NPJG-")))
|
|
|
|
|| (string_is_equal_fast(game_id, "NPHG-", STRLEN_CONST("NPHG-")))
|
|
|
|
|
|
|
|
|| (string_is_equal_fast(game_id, "NPEZ-", STRLEN_CONST("NPEZ-")))
|
|
|
|
|| (string_is_equal_fast(game_id, "NPUZ-", STRLEN_CONST("NPUZ-")))
|
|
|
|
|| (string_is_equal_fast(game_id, "NPJZ-", STRLEN_CONST("NPJZ-")))
|
2021-12-30 13:43:02 +00:00
|
|
|
)
|
|
|
|
{
|
|
|
|
cue_append_multi_disc_suffix(game_id, filename);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2015-09-25 22:05:15 +00:00
|
|
|
|
2021-12-30 13:43:02 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
int detect_gc_game(intfstream_t *fd, char *game_id, const char *filename)
|
|
|
|
{
|
|
|
|
char region_id;
|
|
|
|
char prefix[] = "DL-DOL-";
|
|
|
|
char pre_game_id[20];
|
|
|
|
char raw_game_id[20];
|
2015-09-25 22:05:15 +00:00
|
|
|
|
2021-12-30 13:43:02 +00:00
|
|
|
/* Load raw serial or quit */
|
|
|
|
if (intfstream_seek(fd, 0, SEEK_SET) < 0)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (intfstream_read(fd, raw_game_id, 4) <= 0)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
raw_game_id[4] = '\0';
|
|
|
|
|
|
|
|
/** Scrub files with bad data and log **/
|
|
|
|
if (raw_game_id[0] == '\0' || raw_game_id[0] == ' ')
|
|
|
|
{
|
2022-06-18 17:19:18 +00:00
|
|
|
#ifdef DEBUG
|
2021-12-30 13:43:02 +00:00
|
|
|
RARCH_LOG("[Scanner]: Scrubbing: %s\n", filename);
|
2022-06-18 17:19:18 +00:00
|
|
|
#endif
|
2021-12-30 13:43:02 +00:00
|
|
|
return false;
|
2015-09-25 22:05:15 +00:00
|
|
|
}
|
2016-05-26 15:34:44 +00:00
|
|
|
|
2021-12-30 13:43:02 +00:00
|
|
|
/** convert raw gamecube serial to redump serial.
|
|
|
|
not enough is known about the disc data to properly
|
|
|
|
convert every raw serial to redump serial. it will
|
|
|
|
only fail with the following excpetions: the
|
|
|
|
subregions of europe P-UKV, P-AUS, X-UKV, X-EUU
|
|
|
|
will not match redump.**/
|
2015-09-25 22:05:15 +00:00
|
|
|
|
2021-12-30 13:43:02 +00:00
|
|
|
/** insert prefix **/
|
|
|
|
strcpy(pre_game_id, prefix);
|
2017-09-26 01:51:50 +00:00
|
|
|
|
2021-12-30 13:43:02 +00:00
|
|
|
/** add raw serial **/
|
|
|
|
strcat(pre_game_id, raw_game_id);
|
2016-06-03 09:46:55 +00:00
|
|
|
|
2021-12-30 13:43:02 +00:00
|
|
|
/** check region **/
|
|
|
|
region_id = pre_game_id[10];
|
2016-06-03 19:06:13 +00:00
|
|
|
|
2021-12-30 13:43:02 +00:00
|
|
|
/** check multi-disc and insert suffix **/
|
|
|
|
cue_append_multi_disc_suffix(pre_game_id, filename);
|
|
|
|
strcpy(game_id, pre_game_id);
|
2016-06-03 09:46:55 +00:00
|
|
|
|
2021-12-30 13:43:02 +00:00
|
|
|
switch (region_id)
|
2016-06-03 09:46:55 +00:00
|
|
|
{
|
2021-12-30 13:43:02 +00:00
|
|
|
case 'E':
|
|
|
|
strcat(game_id, "-USA");
|
|
|
|
return true;
|
|
|
|
case 'J':
|
|
|
|
strcat(game_id, "-JPN");
|
|
|
|
return true;
|
|
|
|
case 'P': /** NYI: P can also be P-UKV, P-AUS **/
|
|
|
|
strcat(game_id, "-EUR");
|
|
|
|
return true;
|
|
|
|
case 'X': /** NYI: X can also be X-UKV, X-EUU **/
|
|
|
|
strcat(game_id, "-EUR");
|
|
|
|
return true;
|
|
|
|
case 'Y':
|
|
|
|
strcat(game_id, "-FAH");
|
|
|
|
return true;
|
|
|
|
case 'D':
|
|
|
|
strcat(game_id, "-NOE");
|
|
|
|
return true;
|
|
|
|
case 'S':
|
|
|
|
strcat(game_id, "-ESP");
|
|
|
|
return true;
|
|
|
|
case 'F':
|
|
|
|
strcat(game_id, "-FRA");
|
|
|
|
return true;
|
|
|
|
case 'I':
|
|
|
|
strcat(game_id, "-ITA");
|
|
|
|
return true;
|
|
|
|
case 'H':
|
|
|
|
strcat(game_id, "-HOL");
|
|
|
|
return true;
|
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
2015-09-25 22:05:15 +00:00
|
|
|
|
2021-12-30 13:43:02 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
int detect_scd_game(intfstream_t *fd, char *game_id, const char *filename)
|
|
|
|
{
|
|
|
|
char hyphen = '-';
|
|
|
|
char pre_game_id[15];
|
|
|
|
char raw_game_id[15];
|
|
|
|
char check_prefix_t_hyp[10];
|
|
|
|
char check_suffix_50[10];
|
|
|
|
char check_prefix_g_hyp[10];
|
|
|
|
char check_prefix_mk_hyp[10];
|
|
|
|
char region_id[10];
|
2022-06-18 17:12:03 +00:00
|
|
|
size_t length;
|
2021-12-30 13:43:02 +00:00
|
|
|
int lengthref;
|
|
|
|
int index;
|
|
|
|
char lgame_id[10];
|
|
|
|
char rgame_id[] = "-50";
|
|
|
|
|
|
|
|
/* Load raw serial or quit */
|
|
|
|
if (intfstream_seek(fd, 0x0193, SEEK_SET) < 0)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (intfstream_read(fd, raw_game_id, 11) <= 0)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
raw_game_id[11] = '\0';
|
|
|
|
|
|
|
|
if (raw_game_id[0] == ' ')
|
|
|
|
{
|
|
|
|
if (intfstream_seek(fd, 0x0194, SEEK_SET) < 0)
|
|
|
|
return false;
|
|
|
|
if (intfstream_read(fd, raw_game_id, 11) <= 0)
|
|
|
|
return false;
|
|
|
|
raw_game_id[11] = '\0';
|
2016-06-03 09:46:55 +00:00
|
|
|
}
|
2015-09-25 22:05:15 +00:00
|
|
|
|
2021-12-30 13:43:02 +00:00
|
|
|
/* Load raw region id or quit */
|
|
|
|
if (intfstream_seek(fd, 0x0200, SEEK_SET) < 0)
|
|
|
|
return false;
|
2016-06-03 10:36:48 +00:00
|
|
|
|
2021-12-30 13:43:02 +00:00
|
|
|
if (intfstream_read(fd, region_id, 1) <= 0)
|
|
|
|
return false;
|
2016-06-03 10:36:48 +00:00
|
|
|
|
2021-12-30 13:43:02 +00:00
|
|
|
region_id[1] = '\0';
|
|
|
|
|
2022-06-18 17:12:03 +00:00
|
|
|
#ifdef DEBUG
|
2021-12-30 13:43:02 +00:00
|
|
|
/** Scrub files with bad data and log **/
|
|
|
|
if (raw_game_id[0] == '\0' || raw_game_id[0] == ' ' || raw_game_id[0] == '0')
|
|
|
|
RARCH_LOG("[Scanner]: Scrubbing: %s\n", filename);
|
2022-06-18 17:12:03 +00:00
|
|
|
#endif
|
2016-06-03 10:36:48 +00:00
|
|
|
|
2021-12-30 13:43:02 +00:00
|
|
|
/** convert raw Sega - Mega-CD - Sega CD serial to redump serial. **/
|
|
|
|
/** process raw serial to a pre serial without spaces **/
|
|
|
|
string_remove_all_whitespace(pre_game_id, raw_game_id); /** rule: remove all spaces from the raw serial globally **/
|
|
|
|
|
|
|
|
/** disect this pre serial into parts **/
|
2022-06-18 17:12:03 +00:00
|
|
|
length = strlen(pre_game_id);
|
2021-12-30 13:43:02 +00:00
|
|
|
lengthref = length - 2;
|
|
|
|
strncpy(check_prefix_t_hyp, pre_game_id, 2);
|
|
|
|
check_prefix_t_hyp[2] = '\0';
|
|
|
|
strncpy(check_prefix_g_hyp, pre_game_id, 2);
|
|
|
|
check_prefix_g_hyp[2] = '\0';
|
|
|
|
strncpy(check_prefix_mk_hyp, pre_game_id, 3);
|
|
|
|
check_prefix_mk_hyp[3] = '\0';
|
|
|
|
strncpy(check_suffix_50, &pre_game_id[lengthref], length - 2 + 1);
|
|
|
|
check_suffix_50[2] = '\0';
|
|
|
|
|
|
|
|
/** redump serials are built differently for each prefix **/
|
|
|
|
if (!strcmp(check_prefix_t_hyp, "T-"))
|
|
|
|
{
|
|
|
|
if (!strcmp(region_id, "U") || !strcmp(region_id, "J"))
|
|
|
|
{
|
2022-07-26 05:01:10 +00:00
|
|
|
if ((index = string_index_last_occurance(pre_game_id, hyphen)) == -1)
|
2021-12-30 13:43:02 +00:00
|
|
|
return false;
|
|
|
|
strncpy(game_id, pre_game_id, index);
|
|
|
|
game_id[index] = '\0';
|
|
|
|
cue_append_multi_disc_suffix(game_id, filename);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2022-07-26 05:01:10 +00:00
|
|
|
if ((index = string_index_last_occurance(pre_game_id, hyphen)) == -1)
|
2021-12-30 13:43:02 +00:00
|
|
|
return false;
|
|
|
|
strncpy(lgame_id, pre_game_id, index);
|
|
|
|
lgame_id[index] = '\0';
|
|
|
|
strcat(game_id, lgame_id);
|
|
|
|
strcat(game_id, rgame_id);
|
|
|
|
cue_append_multi_disc_suffix(game_id, filename);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (!strcmp(check_prefix_g_hyp, "G-"))
|
|
|
|
{
|
2022-07-26 05:01:10 +00:00
|
|
|
if ((index = string_index_last_occurance(pre_game_id, hyphen)) == -1)
|
2021-12-30 13:43:02 +00:00
|
|
|
return false;
|
|
|
|
strncpy(game_id, pre_game_id, index);
|
|
|
|
game_id[index] = '\0';
|
|
|
|
cue_append_multi_disc_suffix(game_id, filename);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
else if (!strcmp(check_prefix_mk_hyp, "MK-"))
|
|
|
|
{
|
|
|
|
if (!strcmp(check_suffix_50, "50"))
|
|
|
|
{
|
|
|
|
strncpy(lgame_id, &pre_game_id[3], 4);
|
|
|
|
lgame_id[4] = '\0';
|
|
|
|
strcat(game_id, lgame_id);
|
|
|
|
strcat(game_id, rgame_id);
|
|
|
|
cue_append_multi_disc_suffix(game_id, filename);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
strncpy(game_id, &pre_game_id[3], 4);
|
|
|
|
game_id[4] = '\0';
|
|
|
|
cue_append_multi_disc_suffix(game_id, filename);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
string_trim_whitespace(raw_game_id);
|
|
|
|
strcpy(game_id, raw_game_id);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
2015-09-25 22:05:15 +00:00
|
|
|
}
|
|
|
|
|
2021-12-30 13:43:02 +00:00
|
|
|
int detect_sat_game(intfstream_t *fd, char *game_id, const char *filename)
|
2015-09-25 22:05:15 +00:00
|
|
|
{
|
2021-12-30 13:43:02 +00:00
|
|
|
char raw_game_id[15];
|
|
|
|
char raw_region_id[15];
|
|
|
|
char region_id;
|
|
|
|
char check_prefix_t_hyp[10];
|
|
|
|
char check_prefix_mk_hyp[10];
|
|
|
|
char check_suffix_5[10];
|
|
|
|
char check_suffix_50[10];
|
|
|
|
int length;
|
|
|
|
char lgame_id[10];
|
|
|
|
char rgame_id[10];
|
|
|
|
char game_id50[] = "-50";
|
|
|
|
|
|
|
|
/* Load raw serial or quit */
|
|
|
|
if (intfstream_seek(fd, 0x0030, SEEK_SET) < 0)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (intfstream_read(fd, raw_game_id, 9) <= 0)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
raw_game_id[9] = '\0';
|
|
|
|
|
|
|
|
/* Load raw region id or quit */
|
|
|
|
if (intfstream_seek(fd, 0x0050, SEEK_SET) < 0)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (intfstream_read(fd, raw_region_id, 1) <= 0)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
raw_region_id[1] = '\0';
|
|
|
|
|
|
|
|
/** Scrub files with bad data and log **/
|
|
|
|
if (raw_game_id[0] == '\0' || raw_game_id[0] == ' ')
|
|
|
|
{
|
2022-06-18 17:19:18 +00:00
|
|
|
#ifdef DEBUG
|
2021-12-30 13:43:02 +00:00
|
|
|
RARCH_LOG("[Scanner]: Scrubbing: %s\n", filename);
|
2022-06-18 17:19:18 +00:00
|
|
|
#endif
|
2021-12-30 13:43:02 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
region_id = raw_region_id[0];
|
|
|
|
|
|
|
|
string_trim_whitespace(raw_game_id);
|
2015-09-25 22:05:15 +00:00
|
|
|
|
2021-12-30 13:43:02 +00:00
|
|
|
/** disect this raw serial into parts **/
|
|
|
|
strncpy(check_prefix_t_hyp, raw_game_id, 2);
|
|
|
|
check_prefix_t_hyp[2] = '\0';
|
|
|
|
strncpy(check_prefix_mk_hyp, raw_game_id, 3);
|
|
|
|
check_prefix_mk_hyp[3] = '\0';
|
|
|
|
length = strlen(raw_game_id);
|
|
|
|
strncpy(check_suffix_5, &raw_game_id[length - 2], 2);
|
|
|
|
check_suffix_5[2] = '\0';
|
|
|
|
strncpy(check_suffix_50, &raw_game_id[length - 2], 2);
|
|
|
|
check_suffix_50[2] = '\0';
|
|
|
|
|
|
|
|
/** redump serials are built differently for each region **/
|
|
|
|
switch (region_id)
|
|
|
|
{
|
|
|
|
case 'U':
|
|
|
|
if (strcmp(check_prefix_mk_hyp, "MK-") == 0)
|
|
|
|
{
|
|
|
|
strncpy(game_id, &raw_game_id[3], length - 3);
|
|
|
|
game_id[length - 3] = '\0';
|
|
|
|
cue_append_multi_disc_suffix(game_id, filename);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
strcpy(game_id, raw_game_id);
|
|
|
|
cue_append_multi_disc_suffix(game_id, filename);
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
case 'E':
|
|
|
|
strncpy(lgame_id, &raw_game_id[0], 2);
|
|
|
|
lgame_id[2] = '\0';
|
|
|
|
if (strcmp(check_suffix_5, "-5") == 0 || strcmp(check_suffix_50, "50") == 0)
|
|
|
|
{
|
|
|
|
strncpy(rgame_id, &raw_game_id[2], length - 4);
|
|
|
|
rgame_id[length - 4] = '\0';
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
strncpy(rgame_id, &raw_game_id[2], length - 1);
|
|
|
|
rgame_id[length - 1] = '\0';
|
|
|
|
}
|
|
|
|
strcat(game_id, lgame_id);
|
|
|
|
strcat(game_id, rgame_id);
|
|
|
|
strcat(game_id, game_id50);
|
|
|
|
cue_append_multi_disc_suffix(game_id, filename);
|
|
|
|
return true;
|
|
|
|
case 'J':
|
|
|
|
strcpy(game_id, raw_game_id);
|
|
|
|
cue_append_multi_disc_suffix(game_id, filename);
|
|
|
|
return true;
|
|
|
|
default:
|
|
|
|
strcpy(game_id, raw_game_id);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
2015-09-25 22:05:15 +00:00
|
|
|
}
|
2015-09-16 20:39:47 +00:00
|
|
|
|
2021-12-30 13:43:02 +00:00
|
|
|
int detect_dc_game(intfstream_t *fd, char *game_id, const char *filename)
|
2015-09-26 22:12:17 +00:00
|
|
|
{
|
2021-12-30 13:43:02 +00:00
|
|
|
char hyphen = '-';
|
|
|
|
char hyphen_str[] = "-";
|
|
|
|
int total_hyphens;
|
|
|
|
int total_hyphens_recalc;
|
|
|
|
char pre_game_id[50];
|
|
|
|
char raw_game_id[50];
|
|
|
|
char check_prefix_t_hyp[10];
|
|
|
|
char check_prefix_t[10];
|
|
|
|
char check_prefix_hdr_hyp[10];
|
|
|
|
char check_prefix_mk_hyp[10];
|
2022-06-18 17:12:03 +00:00
|
|
|
size_t length;
|
|
|
|
size_t length_recalc;
|
2021-12-30 13:43:02 +00:00
|
|
|
int index;
|
|
|
|
size_t size_t_var;
|
|
|
|
char lgame_id[20];
|
|
|
|
char rgame_id[20];
|
|
|
|
|
|
|
|
/* Load raw serial or quit */
|
|
|
|
if (intfstream_seek(fd, 0x0050, SEEK_SET) < 0)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (intfstream_read(fd, raw_game_id, 10) <= 0)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
raw_game_id[10] = '\0';
|
|
|
|
|
|
|
|
/** Scrub files with bad data and log **/
|
|
|
|
if (raw_game_id[0] == '\0' || raw_game_id[0] == ' ')
|
2015-09-26 22:12:17 +00:00
|
|
|
{
|
2022-06-18 17:12:03 +00:00
|
|
|
#ifdef DEBUG
|
2021-12-30 13:43:02 +00:00
|
|
|
RARCH_LOG("[Scanner]: Scrubbing: %s\n", filename);
|
2022-06-18 17:12:03 +00:00
|
|
|
#endif
|
2021-12-30 13:43:02 +00:00
|
|
|
return false;
|
|
|
|
}
|
2015-09-26 22:12:17 +00:00
|
|
|
|
2021-12-30 13:43:02 +00:00
|
|
|
string_trim_whitespace(raw_game_id);
|
|
|
|
string_replace_multi_space_with_single_space(raw_game_id);
|
|
|
|
string_replace_whitespace_with_single_character(raw_game_id, hyphen);
|
2022-06-18 17:12:03 +00:00
|
|
|
length = strlen(raw_game_id);
|
2021-12-30 13:43:02 +00:00
|
|
|
total_hyphens = string_count_occurrences_single_character(raw_game_id, hyphen);
|
|
|
|
|
|
|
|
/** disect this raw serial into parts **/
|
|
|
|
strncpy(check_prefix_t_hyp, raw_game_id, 2);
|
|
|
|
check_prefix_t_hyp[2] = '\0';
|
|
|
|
strncpy(check_prefix_t, raw_game_id, 1);
|
|
|
|
check_prefix_t[1] = '\0';
|
|
|
|
strncpy(check_prefix_hdr_hyp, raw_game_id, 4);
|
|
|
|
check_prefix_hdr_hyp[4] = '\0';
|
|
|
|
strncpy(check_prefix_mk_hyp, raw_game_id, 3);
|
|
|
|
check_prefix_mk_hyp[3] = '\0';
|
|
|
|
|
|
|
|
/** redump serials are built differently for each prefix **/
|
|
|
|
if (!strcmp(check_prefix_t_hyp, "T-"))
|
|
|
|
{
|
|
|
|
if (total_hyphens >= 2)
|
2015-09-26 22:12:17 +00:00
|
|
|
{
|
2021-12-30 13:43:02 +00:00
|
|
|
index = string_index_last_occurance(raw_game_id, hyphen);
|
|
|
|
if (index < 0)
|
|
|
|
return false;
|
|
|
|
else
|
|
|
|
size_t_var = (size_t)index;
|
|
|
|
strncpy(lgame_id, &raw_game_id[0], size_t_var);
|
|
|
|
lgame_id[index] = '\0';
|
|
|
|
strncpy(rgame_id, &raw_game_id[index + 1], length - 1);
|
|
|
|
rgame_id[length - 1] = '\0';
|
|
|
|
strcat(game_id, lgame_id);
|
|
|
|
strcat(game_id, hyphen_str);
|
|
|
|
strcat(game_id, rgame_id);
|
|
|
|
cue_append_multi_disc_suffix(game_id, filename);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (length <= 7)
|
2020-06-11 00:39:07 +00:00
|
|
|
{
|
2021-12-30 13:43:02 +00:00
|
|
|
strncpy(game_id, raw_game_id, 7);
|
|
|
|
game_id[7] = '\0';
|
|
|
|
cue_append_multi_disc_suffix(game_id, filename);
|
|
|
|
return true;
|
2020-06-11 00:39:07 +00:00
|
|
|
}
|
2021-12-30 13:43:02 +00:00
|
|
|
else
|
2020-06-11 00:39:07 +00:00
|
|
|
{
|
2021-12-30 13:43:02 +00:00
|
|
|
strncpy(lgame_id, raw_game_id, 7);
|
|
|
|
lgame_id[7] = '\0';
|
|
|
|
strncpy(rgame_id, &raw_game_id[length - 2], length - 1);
|
|
|
|
rgame_id[length - 1] = '\0';
|
|
|
|
strcat(game_id, lgame_id);
|
|
|
|
strcat(game_id, hyphen_str);
|
|
|
|
strcat(game_id, rgame_id);
|
|
|
|
cue_append_multi_disc_suffix(game_id, filename);
|
|
|
|
return true;
|
2020-06-11 00:39:07 +00:00
|
|
|
}
|
2021-12-30 13:43:02 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (!strcmp(check_prefix_t, "T"))
|
|
|
|
{
|
|
|
|
strncpy(lgame_id, raw_game_id, 1);
|
|
|
|
lgame_id[1] = '\0';
|
|
|
|
strncpy(rgame_id, &raw_game_id[1], length - 1);
|
|
|
|
rgame_id[length - 1] = '\0';
|
|
|
|
sprintf(pre_game_id, "%s%s%s", lgame_id, hyphen_str, rgame_id);
|
|
|
|
total_hyphens_recalc = string_count_occurrences_single_character(pre_game_id, hyphen);
|
|
|
|
|
|
|
|
if (total_hyphens_recalc >= 2)
|
|
|
|
{
|
|
|
|
index = string_index_last_occurance(pre_game_id, hyphen);
|
|
|
|
if (index < 0)
|
|
|
|
return false;
|
|
|
|
else
|
|
|
|
size_t_var = (size_t)index;
|
|
|
|
strncpy(lgame_id, pre_game_id, size_t_var);
|
|
|
|
lgame_id[index] = '\0';
|
2022-06-18 17:12:03 +00:00
|
|
|
length_recalc = strlen(pre_game_id);
|
2021-12-30 13:43:02 +00:00
|
|
|
strncpy(rgame_id, &pre_game_id[length_recalc - 2], length_recalc - 1);
|
|
|
|
rgame_id[length_recalc - 1] = '\0';
|
|
|
|
strcat(game_id, lgame_id);
|
|
|
|
strcat(game_id, hyphen_str);
|
|
|
|
strcat(game_id, rgame_id);
|
|
|
|
cue_append_multi_disc_suffix(game_id, filename);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
length_recalc = strlen(pre_game_id) - 1;
|
|
|
|
if (length_recalc <= 8)
|
2020-06-11 00:39:07 +00:00
|
|
|
{
|
2021-12-30 13:43:02 +00:00
|
|
|
strncpy(game_id, pre_game_id, 8);
|
|
|
|
game_id[8] = '\0';
|
|
|
|
cue_append_multi_disc_suffix(game_id, filename);
|
|
|
|
return true;
|
2020-06-11 00:39:07 +00:00
|
|
|
}
|
2021-12-30 13:43:02 +00:00
|
|
|
else
|
2020-06-11 00:39:07 +00:00
|
|
|
{
|
2021-12-30 13:43:02 +00:00
|
|
|
strncpy(lgame_id, pre_game_id, 7);
|
|
|
|
lgame_id[7] = '\0';
|
|
|
|
strncpy(rgame_id, &pre_game_id[length_recalc - 2], length_recalc - 1);
|
|
|
|
rgame_id[length_recalc - 1] = '\0';
|
|
|
|
strcat(game_id, lgame_id);
|
|
|
|
strcat(game_id, hyphen_str);
|
|
|
|
strcat(game_id, rgame_id);
|
|
|
|
cue_append_multi_disc_suffix(game_id, filename);
|
|
|
|
return true;
|
2020-06-11 00:39:07 +00:00
|
|
|
}
|
2015-09-26 22:12:17 +00:00
|
|
|
}
|
2021-12-30 13:43:02 +00:00
|
|
|
}
|
|
|
|
else if (!strcmp(check_prefix_hdr_hyp, "HDR-"))
|
|
|
|
{
|
|
|
|
if (total_hyphens >= 2)
|
|
|
|
{
|
|
|
|
index = string_index_last_occurance(raw_game_id, hyphen);
|
|
|
|
if (index < 0)
|
|
|
|
return false;
|
|
|
|
strncpy(lgame_id, raw_game_id, index - 1);
|
|
|
|
lgame_id[index - 1] = '\0';
|
|
|
|
strncpy(rgame_id, &raw_game_id[length - 4], length - 3);
|
|
|
|
rgame_id[length - 3] = '\0';
|
|
|
|
strcat(game_id, lgame_id);
|
|
|
|
strcat(game_id, hyphen_str);
|
|
|
|
strcat(game_id, rgame_id);
|
|
|
|
cue_append_multi_disc_suffix(game_id, filename);
|
|
|
|
return true;
|
|
|
|
}
|
2015-09-26 22:12:17 +00:00
|
|
|
else
|
2021-12-30 13:43:02 +00:00
|
|
|
{
|
|
|
|
strcpy(game_id, raw_game_id);
|
|
|
|
cue_append_multi_disc_suffix(game_id, filename);
|
|
|
|
return true;
|
|
|
|
}
|
2015-09-26 22:12:17 +00:00
|
|
|
}
|
2021-12-30 13:43:02 +00:00
|
|
|
else if (!strcmp(check_prefix_mk_hyp, "MK-"))
|
|
|
|
{
|
2015-09-26 22:12:17 +00:00
|
|
|
|
2021-12-30 13:43:02 +00:00
|
|
|
if (length <= 8)
|
|
|
|
{
|
|
|
|
strncpy(game_id, raw_game_id, 8);
|
|
|
|
game_id[8] = '\0';
|
|
|
|
cue_append_multi_disc_suffix(game_id, filename);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
strncpy(lgame_id, raw_game_id, 8);
|
|
|
|
lgame_id[8] = '\0';
|
|
|
|
strncpy(rgame_id, &raw_game_id[length - 2], length - 1);
|
|
|
|
rgame_id[length - 1] = '\0';
|
|
|
|
strcat(game_id, lgame_id);
|
|
|
|
strcat(game_id, hyphen_str);
|
|
|
|
strcat(game_id, rgame_id);
|
|
|
|
cue_append_multi_disc_suffix(game_id, filename);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
strcpy(game_id, raw_game_id);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
2015-09-26 22:12:17 +00:00
|
|
|
}
|
|
|
|
|
2021-12-30 13:43:02 +00:00
|
|
|
int detect_wii_game(intfstream_t *fd, char *game_id, const char *filename)
|
2017-10-27 07:58:19 +00:00
|
|
|
{
|
2021-12-30 13:43:02 +00:00
|
|
|
char raw_game_id[15];
|
|
|
|
|
|
|
|
/* Load raw serial or quit */
|
|
|
|
if (intfstream_seek(fd, 0x0000, SEEK_SET) < 0)
|
|
|
|
return false;
|
2017-10-27 07:58:19 +00:00
|
|
|
|
2021-12-30 13:43:02 +00:00
|
|
|
if (intfstream_read(fd, raw_game_id, 6) <= 0)
|
|
|
|
return false;
|
2022-04-03 02:08:30 +00:00
|
|
|
|
2022-07-30 16:31:05 +00:00
|
|
|
if (string_is_equal_fast(raw_game_id, "WBFS", STRLEN_CONST("WBFS")))
|
2022-04-03 02:08:30 +00:00
|
|
|
{
|
|
|
|
if (intfstream_seek(fd, 0x0200, SEEK_SET) < 0)
|
|
|
|
return false;
|
|
|
|
if (intfstream_read(fd, raw_game_id, 6) <= 0)
|
|
|
|
return false;
|
|
|
|
}
|
2021-12-30 13:43:02 +00:00
|
|
|
raw_game_id[6] = '\0';
|
|
|
|
|
|
|
|
/** Scrub files with bad data and log **/
|
|
|
|
if (raw_game_id[0] == '\0' || raw_game_id[0] == ' ')
|
2017-10-27 07:58:19 +00:00
|
|
|
{
|
2022-06-18 17:19:18 +00:00
|
|
|
#ifdef DEBUG
|
2021-12-30 13:43:02 +00:00
|
|
|
RARCH_LOG("[Scanner]: Scrubbing: %s\n", filename);
|
2022-06-18 17:19:18 +00:00
|
|
|
#endif
|
2021-12-30 13:43:02 +00:00
|
|
|
return false;
|
2017-10-27 07:58:19 +00:00
|
|
|
}
|
|
|
|
|
2021-12-30 13:43:02 +00:00
|
|
|
cue_append_multi_disc_suffix(game_id, filename);
|
|
|
|
strcpy(game_id, raw_game_id);
|
|
|
|
return true;
|
2017-10-27 07:58:19 +00:00
|
|
|
}
|
|
|
|
|
2017-07-30 03:23:05 +00:00
|
|
|
/**
|
|
|
|
* Check for an ASCII serial in the first few bits of the ISO (Wii).
|
|
|
|
*/
|
2017-09-17 05:31:58 +00:00
|
|
|
int detect_serial_ascii_game(intfstream_t *fd, char *game_id)
|
2017-07-30 03:23:05 +00:00
|
|
|
{
|
|
|
|
unsigned pos;
|
2020-06-10 14:24:52 +00:00
|
|
|
int number_of_ascii = 0;
|
|
|
|
bool rv = false;
|
2017-07-30 03:23:05 +00:00
|
|
|
|
|
|
|
for (pos = 0; pos < 10000; pos++)
|
|
|
|
{
|
2017-09-17 05:31:58 +00:00
|
|
|
intfstream_seek(fd, pos, SEEK_SET);
|
|
|
|
if (intfstream_read(fd, game_id, 15) > 0)
|
2017-07-30 03:23:05 +00:00
|
|
|
{
|
2017-07-30 08:11:41 +00:00
|
|
|
unsigned i;
|
2020-06-10 14:24:52 +00:00
|
|
|
game_id[15] = '\0';
|
|
|
|
number_of_ascii = 0;
|
2017-07-30 03:23:05 +00:00
|
|
|
|
2019-04-29 02:04:33 +00:00
|
|
|
/* When scanning WBFS files, "WBFS" is discovered as the first serial. Ignore it. */
|
2020-06-10 14:24:52 +00:00
|
|
|
if (string_is_equal(game_id, "WBFS"))
|
2018-04-29 13:51:38 +00:00
|
|
|
continue;
|
|
|
|
|
2017-07-30 08:11:41 +00:00
|
|
|
/* Loop through until we run out of ASCII characters. */
|
|
|
|
for (i = 0; i < 15; i++)
|
|
|
|
{
|
|
|
|
/* Is the given character ASCII? A-Z, 0-9, - */
|
2020-06-10 14:24:52 +00:00
|
|
|
if ( (game_id[i] == 45) ||
|
|
|
|
(game_id[i] >= 48 && game_id[i] <= 57) ||
|
|
|
|
(game_id[i] >= 65 && game_id[i] <= 90))
|
|
|
|
number_of_ascii++;
|
2017-07-30 08:11:41 +00:00
|
|
|
else
|
2017-07-30 03:23:05 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2020-06-10 14:24:52 +00:00
|
|
|
/* If the length of the text is between 3 and 9 characters,
|
|
|
|
* it could be a serial. */
|
|
|
|
if (number_of_ascii > 3 && number_of_ascii < 9)
|
2017-07-30 08:11:41 +00:00
|
|
|
{
|
|
|
|
/* Cut the string off, and return it as a valid serial. */
|
2020-06-10 14:24:52 +00:00
|
|
|
game_id[number_of_ascii] = '\0';
|
|
|
|
rv = true;
|
2017-07-30 03:23:05 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
2021-12-30 13:43:02 +00:00
|
|
|
int detect_system(intfstream_t *fd, const char **system_name, const char * filename)
|
2015-09-16 20:39:47 +00:00
|
|
|
{
|
|
|
|
int i;
|
2021-12-30 13:43:02 +00:00
|
|
|
char magic[50];
|
2015-09-16 20:39:47 +00:00
|
|
|
|
2022-06-18 17:19:18 +00:00
|
|
|
#ifdef DEBUG
|
2021-12-30 13:43:02 +00:00
|
|
|
RARCH_LOG("[Scanner]: %s\n", msg_hash_to_str(MSG_COMPARING_WITH_KNOWN_MAGIC_NUMBERS));
|
2022-06-18 17:19:18 +00:00
|
|
|
#endif
|
2015-09-16 20:39:47 +00:00
|
|
|
for (i = 0; MAGIC_NUMBERS[i].system_name != NULL; i++)
|
|
|
|
{
|
2021-12-30 13:43:02 +00:00
|
|
|
if (intfstream_seek(fd, MAGIC_NUMBERS[i].offset, SEEK_SET) >= 0)
|
2015-09-16 20:39:47 +00:00
|
|
|
{
|
2021-12-30 13:43:02 +00:00
|
|
|
if (intfstream_read(fd, magic, MAGIC_NUMBERS[i].length_magic) > 0)
|
|
|
|
{
|
|
|
|
magic[MAGIC_NUMBERS[i].length_magic] = '\0';
|
|
|
|
if (memcmp(MAGIC_NUMBERS[i].magic, magic, MAGIC_NUMBERS[i].length_magic) == 0)
|
|
|
|
{
|
|
|
|
*system_name = MAGIC_NUMBERS[i].system_name;
|
2022-06-18 17:19:18 +00:00
|
|
|
#ifdef DEBUG
|
2021-12-30 13:43:02 +00:00
|
|
|
RARCH_LOG("[Scanner]: Name: %s\n", filename);
|
|
|
|
RARCH_LOG("[Scanner]: System: %s\n", MAGIC_NUMBERS[i].system_name);
|
2022-06-18 17:19:18 +00:00
|
|
|
#endif
|
2021-12-30 13:43:02 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
2015-09-27 00:14:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-06-18 17:19:18 +00:00
|
|
|
#ifdef DEBUG
|
2021-12-30 13:43:02 +00:00
|
|
|
RARCH_LOG("[Scanner]: Name: %s\n", filename);
|
|
|
|
RARCH_LOG("[Scanner]: System: Unknown\n");
|
2022-06-18 17:19:18 +00:00
|
|
|
#endif
|
2021-12-30 13:43:02 +00:00
|
|
|
return false;
|
2015-09-16 20:39:47 +00:00
|
|
|
}
|
|
|
|
|
2018-04-12 22:18:11 +00:00
|
|
|
static int64_t intfstream_get_file_size(const char *path)
|
2017-09-17 21:26:06 +00:00
|
|
|
{
|
2018-04-12 22:18:11 +00:00
|
|
|
int64_t rv;
|
2017-12-11 12:21:44 +00:00
|
|
|
intfstream_t *fd = intfstream_open_file(path,
|
2017-12-11 11:53:47 +00:00
|
|
|
RETRO_VFS_FILE_ACCESS_READ, RETRO_VFS_FILE_ACCESS_HINT_NONE);
|
2017-12-11 12:21:44 +00:00
|
|
|
if (!fd)
|
2017-09-17 21:26:06 +00:00
|
|
|
return -1;
|
2017-12-11 12:21:44 +00:00
|
|
|
rv = intfstream_get_size(fd);
|
|
|
|
intfstream_close(fd);
|
2017-12-11 19:24:00 +00:00
|
|
|
free(fd);
|
2017-09-17 21:26:06 +00:00
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
2018-04-12 22:18:11 +00:00
|
|
|
static bool update_cand(int64_t *cand_index, int64_t *last_index,
|
2020-06-10 14:24:52 +00:00
|
|
|
uint64_t *largest, char *last_file, uint64_t *offset,
|
|
|
|
uint64_t *size, char *track_path, uint64_t max_len)
|
2017-09-17 21:26:06 +00:00
|
|
|
{
|
2018-04-09 17:30:36 +00:00
|
|
|
if (*cand_index != -1)
|
|
|
|
{
|
2018-04-12 22:18:11 +00:00
|
|
|
if ((uint64_t)(*last_index - *cand_index) > *largest)
|
2018-04-09 17:30:36 +00:00
|
|
|
{
|
|
|
|
*largest = *last_index - *cand_index;
|
2018-04-12 22:47:42 +00:00
|
|
|
strlcpy(track_path, last_file, (size_t)max_len);
|
2018-04-09 17:30:36 +00:00
|
|
|
*offset = *cand_index;
|
|
|
|
*size = *largest;
|
|
|
|
*cand_index = -1;
|
|
|
|
return true;
|
|
|
|
}
|
2020-06-10 14:24:52 +00:00
|
|
|
*cand_index = -1;
|
2018-04-09 17:30:36 +00:00
|
|
|
}
|
|
|
|
return false;
|
2017-09-17 21:26:06 +00:00
|
|
|
}
|
|
|
|
|
2017-09-18 00:39:41 +00:00
|
|
|
int cue_find_track(const char *cue_path, bool first,
|
2018-04-12 22:18:11 +00:00
|
|
|
uint64_t *offset, uint64_t *size, char *track_path, uint64_t max_len)
|
2015-09-16 20:39:47 +00:00
|
|
|
{
|
2016-06-30 04:02:30 +00:00
|
|
|
int rv;
|
2017-09-17 05:31:58 +00:00
|
|
|
intfstream_info_t info;
|
2020-08-26 17:46:13 +00:00
|
|
|
char tmp_token[MAX_TOKEN_LEN];
|
2020-08-18 12:47:57 +00:00
|
|
|
char last_file[PATH_MAX_LENGTH];
|
|
|
|
char cue_dir[PATH_MAX_LENGTH];
|
2017-09-19 19:29:28 +00:00
|
|
|
intfstream_t *fd = NULL;
|
2018-04-12 22:18:11 +00:00
|
|
|
int64_t last_index = -1;
|
|
|
|
int64_t cand_index = -1;
|
2017-09-19 19:29:28 +00:00
|
|
|
int32_t cand_track = -1;
|
|
|
|
int32_t track = 0;
|
2018-04-12 22:18:11 +00:00
|
|
|
uint64_t largest = 0;
|
|
|
|
int64_t volatile file_size = -1;
|
2017-09-19 19:29:28 +00:00
|
|
|
bool is_data = false;
|
2020-08-18 12:47:57 +00:00
|
|
|
cue_dir[0] = last_file[0] = '\0';
|
2017-09-18 00:46:02 +00:00
|
|
|
|
2020-08-18 12:47:57 +00:00
|
|
|
fill_pathname_basedir(cue_dir, cue_path, sizeof(cue_dir));
|
2017-09-17 05:31:58 +00:00
|
|
|
|
2020-06-10 14:24:52 +00:00
|
|
|
info.type = INTFSTREAM_FILE;
|
|
|
|
fd = (intfstream_t*)intfstream_init(&info);
|
2015-09-16 20:39:47 +00:00
|
|
|
|
2015-09-17 18:31:04 +00:00
|
|
|
if (!fd)
|
2017-09-17 17:14:51 +00:00
|
|
|
goto error;
|
2017-09-17 05:31:58 +00:00
|
|
|
|
2017-12-11 11:15:00 +00:00
|
|
|
if (!intfstream_open(fd, cue_path,
|
2017-12-11 11:53:47 +00:00
|
|
|
RETRO_VFS_FILE_ACCESS_READ, RETRO_VFS_FILE_ACCESS_HINT_NONE))
|
2015-09-16 20:39:47 +00:00
|
|
|
{
|
2022-06-18 17:19:18 +00:00
|
|
|
#ifdef DEBUG
|
2015-09-16 20:39:47 +00:00
|
|
|
RARCH_LOG("Could not open CUE file '%s': %s\n", cue_path,
|
|
|
|
strerror(errno));
|
2022-06-18 17:19:18 +00:00
|
|
|
#endif
|
2017-09-12 03:04:27 +00:00
|
|
|
goto error;
|
2015-09-16 20:39:47 +00:00
|
|
|
}
|
|
|
|
|
2022-06-18 17:19:18 +00:00
|
|
|
#ifdef DEBUG
|
2015-09-16 20:39:47 +00:00
|
|
|
RARCH_LOG("Parsing CUE file '%s'...\n", cue_path);
|
2022-06-18 17:19:18 +00:00
|
|
|
#endif
|
2015-09-16 20:39:47 +00:00
|
|
|
|
2016-10-09 07:56:03 +00:00
|
|
|
tmp_token[0] = '\0';
|
|
|
|
|
2017-09-17 21:26:06 +00:00
|
|
|
rv = -EINVAL;
|
|
|
|
|
2020-08-26 17:46:13 +00:00
|
|
|
while (get_token(fd, tmp_token, sizeof(tmp_token)) > 0)
|
2015-09-16 20:39:47 +00:00
|
|
|
{
|
2019-08-01 23:16:18 +00:00
|
|
|
if (string_is_equal_noncase(tmp_token, "FILE"))
|
2015-09-16 20:39:47 +00:00
|
|
|
{
|
2017-09-17 21:26:06 +00:00
|
|
|
/* Set last index to last EOF */
|
2018-04-09 17:30:36 +00:00
|
|
|
if (file_size != -1)
|
2017-09-17 21:26:06 +00:00
|
|
|
last_index = file_size;
|
|
|
|
|
|
|
|
/* We're changing files since the candidate, update it */
|
2020-06-10 14:24:52 +00:00
|
|
|
if (update_cand(&cand_index, &last_index,
|
|
|
|
&largest, last_file, offset,
|
|
|
|
size, track_path, max_len))
|
2018-04-09 17:30:36 +00:00
|
|
|
{
|
2017-09-17 21:26:06 +00:00
|
|
|
rv = 0;
|
2018-04-09 17:30:36 +00:00
|
|
|
if (first)
|
2017-09-17 21:26:06 +00:00
|
|
|
goto clean;
|
|
|
|
}
|
|
|
|
|
2020-08-26 17:46:13 +00:00
|
|
|
get_token(fd, tmp_token, sizeof(tmp_token));
|
2022-08-04 12:18:11 +00:00
|
|
|
fill_pathname_join_special(last_file, cue_dir,
|
2020-08-18 12:47:57 +00:00
|
|
|
tmp_token, sizeof(last_file));
|
2017-09-17 21:26:06 +00:00
|
|
|
|
2017-12-11 12:21:44 +00:00
|
|
|
file_size = intfstream_get_file_size(last_file);
|
2015-09-16 20:39:47 +00:00
|
|
|
|
2020-08-26 17:46:13 +00:00
|
|
|
get_token(fd, tmp_token, sizeof(tmp_token));
|
2017-09-17 21:26:06 +00:00
|
|
|
|
2017-06-06 08:20:34 +00:00
|
|
|
}
|
2019-08-01 23:16:18 +00:00
|
|
|
else if (string_is_equal_noncase(tmp_token, "TRACK"))
|
2017-06-06 08:20:34 +00:00
|
|
|
{
|
2020-08-26 17:46:13 +00:00
|
|
|
get_token(fd, tmp_token, sizeof(tmp_token));
|
|
|
|
get_token(fd, tmp_token, sizeof(tmp_token));
|
2019-08-01 23:16:18 +00:00
|
|
|
is_data = !string_is_equal_noncase(tmp_token, "AUDIO");
|
2017-09-17 21:26:06 +00:00
|
|
|
++track;
|
2018-04-09 17:30:36 +00:00
|
|
|
}
|
2019-08-01 23:16:18 +00:00
|
|
|
else if (string_is_equal_noncase(tmp_token, "INDEX"))
|
2018-04-09 17:30:36 +00:00
|
|
|
{
|
2017-09-17 21:26:06 +00:00
|
|
|
int m, s, f;
|
2020-08-26 17:46:13 +00:00
|
|
|
get_token(fd, tmp_token, sizeof(tmp_token));
|
|
|
|
get_token(fd, tmp_token, sizeof(tmp_token));
|
2016-01-20 16:34:19 +00:00
|
|
|
|
2017-06-06 08:20:34 +00:00
|
|
|
if (sscanf(tmp_token, "%02d:%02d:%02d", &m, &s, &f) < 3)
|
|
|
|
{
|
2022-06-18 17:19:18 +00:00
|
|
|
#ifdef DEBUG
|
2017-06-06 08:20:34 +00:00
|
|
|
RARCH_LOG("Error parsing time stamp '%s'\n", tmp_token);
|
2022-06-18 17:19:18 +00:00
|
|
|
#endif
|
2017-09-12 03:04:27 +00:00
|
|
|
goto error;
|
2017-06-06 08:20:34 +00:00
|
|
|
}
|
2016-01-20 16:34:19 +00:00
|
|
|
|
2017-09-17 21:26:06 +00:00
|
|
|
last_index = (size_t) (((m * 60 + s) * 75) + f) * 2352;
|
2015-09-16 20:39:47 +00:00
|
|
|
|
2017-09-17 21:26:06 +00:00
|
|
|
/* If we've changed tracks since the candidate, update it */
|
|
|
|
if (cand_track != -1 && track != cand_track &&
|
2020-06-10 14:24:52 +00:00
|
|
|
update_cand(&cand_index, &last_index, &largest,
|
|
|
|
last_file, offset,
|
|
|
|
size, track_path, max_len))
|
2018-04-09 17:30:36 +00:00
|
|
|
{
|
2017-09-17 21:26:06 +00:00
|
|
|
rv = 0;
|
2018-04-09 17:30:36 +00:00
|
|
|
if (first)
|
2017-09-17 21:26:06 +00:00
|
|
|
goto clean;
|
|
|
|
}
|
|
|
|
|
2018-04-09 17:30:36 +00:00
|
|
|
if (!is_data)
|
2017-09-17 21:26:06 +00:00
|
|
|
continue;
|
|
|
|
|
2018-04-09 17:30:36 +00:00
|
|
|
if (cand_index == -1)
|
|
|
|
{
|
2017-09-17 21:26:06 +00:00
|
|
|
cand_index = last_index;
|
|
|
|
cand_track = track;
|
|
|
|
}
|
2015-09-16 20:39:47 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-09 17:30:36 +00:00
|
|
|
if (file_size != -1)
|
2017-09-18 00:52:11 +00:00
|
|
|
last_index = file_size;
|
|
|
|
|
2020-06-10 14:24:52 +00:00
|
|
|
if (update_cand(&cand_index, &last_index,
|
|
|
|
&largest, last_file, offset,
|
|
|
|
size, track_path, max_len))
|
2017-09-17 21:26:06 +00:00
|
|
|
rv = 0;
|
2015-09-16 20:39:47 +00:00
|
|
|
|
|
|
|
clean:
|
2017-09-17 05:31:58 +00:00
|
|
|
intfstream_close(fd);
|
2017-09-21 22:03:40 +00:00
|
|
|
free(fd);
|
2015-09-16 20:39:47 +00:00
|
|
|
return rv;
|
2017-09-12 03:04:27 +00:00
|
|
|
|
|
|
|
error:
|
|
|
|
if (fd)
|
2017-09-21 21:38:29 +00:00
|
|
|
{
|
2017-09-17 05:31:58 +00:00
|
|
|
intfstream_close(fd);
|
2017-09-21 21:38:29 +00:00
|
|
|
free(fd);
|
|
|
|
}
|
2017-09-12 03:04:27 +00:00
|
|
|
return -errno;
|
2015-09-16 20:39:47 +00:00
|
|
|
}
|
2017-09-18 00:39:41 +00:00
|
|
|
|
2018-04-12 22:47:42 +00:00
|
|
|
bool cue_next_file(intfstream_t *fd,
|
|
|
|
const char *cue_path, char *path, uint64_t max_len)
|
2017-09-18 02:18:50 +00:00
|
|
|
{
|
2020-08-26 17:46:13 +00:00
|
|
|
char tmp_token[MAX_TOKEN_LEN];
|
2020-08-18 12:47:57 +00:00
|
|
|
char cue_dir[PATH_MAX_LENGTH];
|
2017-09-19 19:29:28 +00:00
|
|
|
bool rv = false;
|
|
|
|
cue_dir[0] = '\0';
|
2017-09-18 02:18:50 +00:00
|
|
|
|
2020-08-18 12:47:57 +00:00
|
|
|
fill_pathname_basedir(cue_dir, cue_path, sizeof(cue_dir));
|
2017-09-18 02:18:50 +00:00
|
|
|
|
|
|
|
tmp_token[0] = '\0';
|
|
|
|
|
2020-08-26 17:46:13 +00:00
|
|
|
while (get_token(fd, tmp_token, sizeof(tmp_token)) > 0)
|
2017-09-18 02:18:50 +00:00
|
|
|
{
|
2019-08-01 23:16:18 +00:00
|
|
|
if (string_is_equal_noncase(tmp_token, "FILE"))
|
2017-09-18 02:18:50 +00:00
|
|
|
{
|
2020-08-26 17:46:13 +00:00
|
|
|
get_token(fd, tmp_token, sizeof(tmp_token));
|
2022-08-04 12:18:11 +00:00
|
|
|
fill_pathname_join_special(path, cue_dir,
|
|
|
|
tmp_token, (size_t)max_len);
|
2017-09-18 02:18:50 +00:00
|
|
|
rv = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
2017-09-20 07:55:53 +00:00
|
|
|
int gdi_find_track(const char *gdi_path, bool first,
|
2018-04-12 22:18:11 +00:00
|
|
|
char *track_path, uint64_t max_len)
|
2017-09-18 00:39:41 +00:00
|
|
|
{
|
|
|
|
int rv;
|
|
|
|
intfstream_info_t info;
|
2020-08-26 17:46:13 +00:00
|
|
|
char tmp_token[MAX_TOKEN_LEN];
|
2017-09-19 19:29:28 +00:00
|
|
|
intfstream_t *fd = NULL;
|
2018-04-12 22:18:11 +00:00
|
|
|
uint64_t largest = 0;
|
2017-09-19 19:29:28 +00:00
|
|
|
int size = -1;
|
|
|
|
int mode = -1;
|
2018-04-12 22:18:11 +00:00
|
|
|
int64_t file_size = -1;
|
2017-09-18 00:39:41 +00:00
|
|
|
|
2017-09-19 19:29:28 +00:00
|
|
|
info.type = INTFSTREAM_FILE;
|
|
|
|
|
|
|
|
fd = (intfstream_t*)intfstream_init(&info);
|
2017-09-18 00:39:41 +00:00
|
|
|
|
|
|
|
if (!fd)
|
|
|
|
goto error;
|
|
|
|
|
2017-12-11 11:15:00 +00:00
|
|
|
if (!intfstream_open(fd, gdi_path,
|
2017-12-11 11:53:47 +00:00
|
|
|
RETRO_VFS_FILE_ACCESS_READ, RETRO_VFS_FILE_ACCESS_HINT_NONE))
|
2017-09-18 00:39:41 +00:00
|
|
|
{
|
2022-06-18 17:19:18 +00:00
|
|
|
#ifdef DEBUG
|
2017-09-18 00:39:41 +00:00
|
|
|
RARCH_LOG("Could not open GDI file '%s': %s\n", gdi_path,
|
|
|
|
strerror(errno));
|
2022-06-18 17:19:18 +00:00
|
|
|
#endif
|
2017-09-18 00:39:41 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2022-06-18 17:19:18 +00:00
|
|
|
#ifdef DEBUG
|
2017-09-18 00:39:41 +00:00
|
|
|
RARCH_LOG("Parsing GDI file '%s'...\n", gdi_path);
|
2022-06-18 17:19:18 +00:00
|
|
|
#endif
|
2017-09-18 00:39:41 +00:00
|
|
|
|
|
|
|
tmp_token[0] = '\0';
|
|
|
|
|
|
|
|
rv = -EINVAL;
|
|
|
|
|
|
|
|
/* Skip track count */
|
2020-08-26 17:46:13 +00:00
|
|
|
get_token(fd, tmp_token, sizeof(tmp_token));
|
2017-09-18 00:39:41 +00:00
|
|
|
|
|
|
|
/* Track number */
|
2020-08-26 17:46:13 +00:00
|
|
|
while (get_token(fd, tmp_token, sizeof(tmp_token)) > 0)
|
2017-09-18 00:39:41 +00:00
|
|
|
{
|
|
|
|
/* Offset */
|
2020-08-26 17:46:13 +00:00
|
|
|
if (get_token(fd, tmp_token, sizeof(tmp_token)) <= 0)
|
2017-09-18 00:39:41 +00:00
|
|
|
{
|
|
|
|
errno = EINVAL;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Mode */
|
2020-08-26 17:46:13 +00:00
|
|
|
if (get_token(fd, tmp_token, sizeof(tmp_token)) <= 0)
|
2017-09-18 00:39:41 +00:00
|
|
|
{
|
|
|
|
errno = EINVAL;
|
|
|
|
goto error;
|
|
|
|
}
|
2020-06-10 14:24:52 +00:00
|
|
|
|
2017-09-18 00:39:41 +00:00
|
|
|
mode = atoi(tmp_token);
|
|
|
|
|
|
|
|
/* Sector size */
|
2020-08-26 17:46:13 +00:00
|
|
|
if (get_token(fd, tmp_token, sizeof(tmp_token)) <= 0)
|
2017-09-18 00:39:41 +00:00
|
|
|
{
|
|
|
|
errno = EINVAL;
|
|
|
|
goto error;
|
|
|
|
}
|
2020-06-10 14:24:52 +00:00
|
|
|
|
2017-09-18 00:39:41 +00:00
|
|
|
size = atoi(tmp_token);
|
|
|
|
|
|
|
|
/* File name */
|
2020-08-26 17:46:13 +00:00
|
|
|
if (get_token(fd, tmp_token, sizeof(tmp_token)) <= 0)
|
2017-09-18 00:39:41 +00:00
|
|
|
{
|
|
|
|
errno = EINVAL;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check for data track */
|
|
|
|
if (!(mode == 0 && size == 2352))
|
|
|
|
{
|
2020-08-18 12:47:57 +00:00
|
|
|
char last_file[PATH_MAX_LENGTH];
|
|
|
|
char gdi_dir[PATH_MAX_LENGTH];
|
2017-09-20 07:55:53 +00:00
|
|
|
|
2020-08-18 12:47:57 +00:00
|
|
|
fill_pathname_basedir(gdi_dir, gdi_path, sizeof(gdi_dir));
|
2022-08-04 12:18:11 +00:00
|
|
|
fill_pathname_join_special(last_file,
|
2020-08-18 12:47:57 +00:00
|
|
|
gdi_dir, tmp_token, sizeof(last_file));
|
|
|
|
|
2022-08-04 12:18:11 +00:00
|
|
|
if ((file_size = intfstream_get_file_size(last_file)) < 0)
|
2017-09-18 00:39:41 +00:00
|
|
|
goto error;
|
2017-09-19 19:29:28 +00:00
|
|
|
|
2018-04-12 22:18:11 +00:00
|
|
|
if ((uint64_t)file_size > largest)
|
2017-09-18 00:39:41 +00:00
|
|
|
{
|
2018-04-12 22:47:42 +00:00
|
|
|
strlcpy(track_path, last_file, (size_t)max_len);
|
|
|
|
|
|
|
|
rv = 0;
|
2017-09-18 00:39:41 +00:00
|
|
|
largest = file_size;
|
2018-04-12 22:47:42 +00:00
|
|
|
|
2017-09-18 00:39:41 +00:00
|
|
|
if (first)
|
|
|
|
goto clean;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Disc offset (not used?) */
|
2020-08-26 17:46:13 +00:00
|
|
|
if (get_token(fd, tmp_token, sizeof(tmp_token)) <= 0)
|
2017-09-18 00:39:41 +00:00
|
|
|
{
|
|
|
|
errno = EINVAL;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
clean:
|
|
|
|
intfstream_close(fd);
|
2017-09-20 10:18:31 +00:00
|
|
|
free(fd);
|
2017-09-18 00:39:41 +00:00
|
|
|
return rv;
|
|
|
|
|
|
|
|
error:
|
|
|
|
if (fd)
|
2017-09-20 10:18:31 +00:00
|
|
|
{
|
2017-09-18 00:39:41 +00:00
|
|
|
intfstream_close(fd);
|
2017-09-20 10:18:31 +00:00
|
|
|
free(fd);
|
|
|
|
}
|
2017-09-18 00:39:41 +00:00
|
|
|
return -errno;
|
|
|
|
}
|
2017-09-18 02:18:50 +00:00
|
|
|
|
2017-09-20 07:55:53 +00:00
|
|
|
bool gdi_next_file(intfstream_t *fd, const char *gdi_path,
|
2018-04-12 22:18:11 +00:00
|
|
|
char *path, uint64_t max_len)
|
2017-09-18 02:18:50 +00:00
|
|
|
{
|
2020-08-26 17:46:13 +00:00
|
|
|
char tmp_token[MAX_TOKEN_LEN];
|
2017-09-19 19:29:28 +00:00
|
|
|
bool rv = false;
|
2017-09-18 02:18:50 +00:00
|
|
|
|
2017-09-19 19:29:28 +00:00
|
|
|
tmp_token[0] = '\0';
|
2017-09-18 02:18:50 +00:00
|
|
|
|
|
|
|
/* Skip initial track count */
|
2020-08-26 17:46:13 +00:00
|
|
|
if (intfstream_tell(fd) == 0)
|
|
|
|
get_token(fd, tmp_token, sizeof(tmp_token));
|
2017-09-18 02:18:50 +00:00
|
|
|
|
2020-08-26 17:46:13 +00:00
|
|
|
get_token(fd, tmp_token, sizeof(tmp_token)); /* Track number */
|
|
|
|
get_token(fd, tmp_token, sizeof(tmp_token)); /* Offset */
|
|
|
|
get_token(fd, tmp_token, sizeof(tmp_token)); /* Mode */
|
|
|
|
get_token(fd, tmp_token, sizeof(tmp_token)); /* Sector size */
|
2017-09-20 07:55:53 +00:00
|
|
|
|
2017-09-18 02:18:50 +00:00
|
|
|
/* File name */
|
2020-08-26 17:46:13 +00:00
|
|
|
if (get_token(fd, tmp_token, sizeof(tmp_token)) > 0)
|
2017-09-18 02:18:50 +00:00
|
|
|
{
|
2020-08-18 12:47:57 +00:00
|
|
|
char gdi_dir[PATH_MAX_LENGTH];
|
2017-09-20 07:55:53 +00:00
|
|
|
|
2020-08-18 12:47:57 +00:00
|
|
|
fill_pathname_basedir(gdi_dir, gdi_path, sizeof(gdi_dir));
|
2022-08-04 12:18:11 +00:00
|
|
|
fill_pathname_join_special(path, gdi_dir, tmp_token, (size_t)max_len);
|
2020-06-10 14:24:52 +00:00
|
|
|
|
|
|
|
rv = true;
|
2017-09-20 07:55:53 +00:00
|
|
|
|
2017-09-18 02:18:50 +00:00
|
|
|
/* Disc offset */
|
2020-08-26 17:46:13 +00:00
|
|
|
get_token(fd, tmp_token, sizeof(tmp_token));
|
2017-09-18 02:18:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|