1201 lines
43 KiB
C
1201 lines
43 KiB
C
/*
|
|
pce.c - PC-Engine support for uCON64
|
|
|
|
Copyright (c) 1999 - 2001 NoisyB <noisyb@gmx.net>
|
|
Copyright (c) 2003 - 2004 dbjh
|
|
|
|
|
|
This program 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 Foundation; either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program 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 this program; if not, write to the Free Software
|
|
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
*/
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
#include <ctype.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#ifdef HAVE_UNISTD_H
|
|
#include <unistd.h>
|
|
#endif
|
|
#include <sys/stat.h>
|
|
#include "misc/chksum.h"
|
|
#include "misc/misc.h"
|
|
#include "misc/string.h"
|
|
#include "misc/file.h"
|
|
#ifdef USE_ZLIB
|
|
#include "misc/archive.h"
|
|
#endif
|
|
#include "misc/getopt2.h" // st_getopt2_t
|
|
#include "ucon64.h"
|
|
#include "ucon64_misc.h"
|
|
#include "pce.h"
|
|
#include "backup/mgd.h"
|
|
#include "backup/msg.h"
|
|
|
|
|
|
#define PCENGINE_HEADER_START 0x448
|
|
#define PCENGINE_HEADER_LEN (sizeof (st_pce_header_t))
|
|
|
|
|
|
// static unsigned int pcengine_chksum (st_rominfo_t *rominfo);
|
|
|
|
const st_getopt2_t pcengine_usage[] =
|
|
{
|
|
{
|
|
NULL, 0, 0, 0,
|
|
NULL, "PC-Engine (CD Unit/Core Grafx(II)/Shuttle/GT/LT/Super CDROM/DUO(-R(X)))\n"
|
|
"Super Grafx/Turbo (Grafx(16)/CD/DUO/Express)"/*"1987/19XX/19XX NEC"*/,
|
|
NULL
|
|
},
|
|
{
|
|
"pce", 0, 0, UCON64_PCE,
|
|
NULL, "force recognition",
|
|
&ucon64_wf[WF_OBJ_PCE_SWITCH]
|
|
},
|
|
{
|
|
"int", 0, 0, UCON64_INT,
|
|
NULL, "force ROM is in interleaved (bit-swapped) format",
|
|
&ucon64_wf[WF_OBJ_ALL_SWITCH]
|
|
},
|
|
{
|
|
"nint", 0, 0, UCON64_NINT,
|
|
NULL, "force ROM is not in interleaved (bit-swapped) format",
|
|
&ucon64_wf[WF_OBJ_ALL_SWITCH]
|
|
},
|
|
{
|
|
"msg", 0, 0, UCON64_MSG,
|
|
NULL, "convert to Magic Super Griffin/MSG",
|
|
&ucon64_wf[WF_OBJ_PCE_DEFAULT]
|
|
},
|
|
{
|
|
"mgd", 0, 0, UCON64_MGD,
|
|
NULL, "convert to Multi Game Doctor*/MGD2/RAW",
|
|
&ucon64_wf[WF_OBJ_ALL_DEFAULT_NO_SPLIT]
|
|
},
|
|
{
|
|
"swap", 0, 0, UCON64_SWAP,
|
|
NULL, "swap bits of all bytes in file (TurboGrafx-16 <-> PC-Engine)",
|
|
&ucon64_wf[WF_OBJ_ALL_INIT_PROBE]
|
|
},
|
|
{
|
|
"f", 0, 0, UCON64_F,
|
|
NULL, "fix region protection",
|
|
&ucon64_wf[WF_OBJ_ALL_DEFAULT]
|
|
},
|
|
{
|
|
"multi", 1, 0, UCON64_MULTI,
|
|
"SIZE", "make multi-game file for use with PCE-PRO flash card, truncated\n"
|
|
"to SIZE Mbit; file with loader must be specified first, then\n"
|
|
"all the ROMs, multi-game file to create last",
|
|
&ucon64_wf[WF_OBJ_ALL_INIT_PROBE_STOP]
|
|
},
|
|
{NULL, 0, 0, 0, NULL, NULL, NULL}
|
|
};
|
|
|
|
#define PCE_MAKER_MAX 86
|
|
static const char *pce_maker[PCE_MAKER_MAX] =
|
|
{
|
|
NULL, "ACCOLADE", "AICOM", "ARTMIC", "ASK KODANSHA",
|
|
"ASMIK", "ATLUS", "AZUMA", "BIG DON", "BIGCLUB",
|
|
"BIT2", "BULLET PROOF", "CAPCOM", "CINEMAWARE", "COCONUTS",
|
|
"CREAM", "DATA EAST", "DEKA", "DISNEY", "FACE",
|
|
"FUJITV", "FUN PROJECT", "GAMES EXPRESS", "HOMEDATA", "HUDSON",
|
|
"HUDSON V1", "HUDSON V2", "HUMAN", "ICOM", "IGS",
|
|
"IMAGE", "IMAX", "INTEC", "IREM", "KANEKO",
|
|
"KONAMI", "KSS", "LASER SOFT", "LORICIEL", "MAGAE CHIP VERSION",
|
|
"MANLEY & ASSOCIATES", "MASYNYA & NCS", "MASYNYA", "MEDIA RINGS", "NAMCO",
|
|
"NATSUME", "NATSUME", "NAXAT SOFT", "NAXAT", "NCS",
|
|
"NEC / HUDSON", "NEC AVENUE & TAITO", "NEC AVENUE", "NEC HOME ELECTRONICS", "NEC",
|
|
"NHK", "NICHIBUTSU", "NIHON BUSSAN", "PACK-IN-VIDEO", "PALSOFT",
|
|
"PSYGNOSYS", "RANDOM HOUSE", "SALIO", "SEGA", "SEIBU KAIHATSU",
|
|
"SGX", "SPECTRUM HOLOBYTE", "SSL", "SUMMER PROJECT", "SUNRISE",
|
|
"SUNSOFT", "TAISANG VERSION", "TAITO 384K STYLE", "TAITO", "TAKARA",
|
|
"TECHNOS", "TELENET", "TENGEN", "THE HU62680 TEAM", "TITUS",
|
|
"TONKIN HOUSE", "UNI POST", "UPL", "VICTOR", "VIDEO SYSTEM",
|
|
"WOLF TEAM"
|
|
};
|
|
|
|
|
|
typedef struct
|
|
{
|
|
uint32_t crc32;
|
|
uint8_t maker;
|
|
const char *serial;
|
|
uint32_t date;
|
|
const char *comment;
|
|
} st_pce_data_t;
|
|
|
|
|
|
static const st_pce_data_t pce_data[] =
|
|
{
|
|
{0x0038b5b5, 70, "SS90002", 100890, NULL},
|
|
{0x00c38e69, 73, "TP02012", 60790, NULL},
|
|
{0x00f83029, 42, NULL, 0, NULL},
|
|
{0x0112d0c7, 42, "NCS90005", 141290, "1p"},
|
|
{0x013a747f, 24, "HC91051", 61291, "1p"},
|
|
{0x01a76935, 44, "NC63003", 261288, NULL},
|
|
{0x020dc2df, 58, "PV1001", 230389, "3M"},
|
|
{0x0243453b, 24, "HC63016", 90289, "aka MILITARY MADNESS,2p"},
|
|
{0x0258accb, 33, NULL, 0, NULL},
|
|
{0x02a578c5, 24, NULL, 91, "1p"},
|
|
{0x02db6fe5, 24, NULL, 0, NULL},
|
|
{0x02dde03e, 22, "T4955754200915", 0, NULL},
|
|
{0x033e8c4a, 73, "TP02006", 260190, "1p"},
|
|
{0x03883ee8, 48, "NX90003", 60490, "2p"},
|
|
{0x03e28cff, 24, "HC62003", 281287, "1p"},
|
|
{0x04188c5c, 83, "JC63005", 290690, "3p"},
|
|
{0x04bf5eaf, 54, "TGX030064", 0, NULL},
|
|
{0x05054f4f, 12, NULL, 0, NULL},
|
|
{0x0517da65, 35, "KM91001", 151191, NULL},
|
|
{0x05362516, 24, "HC93065", 101293, "5p"},
|
|
{0x053a0f83, 58, NULL, 0, "aka DEEP BLUE KAITEI SHINWA,1p"},
|
|
{0x05453628, 19, "FA02-007", 71290, NULL},
|
|
{0x0590a156, 33, "IC02004", 60790, NULL},
|
|
{0x05a4b72e, 24, NULL, 0, "1p (AKA BLODIA)"},
|
|
{0x07a226fb, 54, "TGX020003", 0, "1p"},
|
|
{0x07bc34dc, 44, "TGX040085", 0, "aka GENPEI TORAMADEN VOLUME 2,1p"},
|
|
{0x088d896d, 54, NULL, 0, "1p"},
|
|
{0x08a09b9a, 24, "HC90030", 270490, "aka BLUE BLINK"},
|
|
{0x09048174, 58, "PV1001", 230389, "3M"},
|
|
{0x09509315, 73, NULL, 0, NULL},
|
|
{0x09a0bfcc, 73, "TP03016", 250191, "4p"},
|
|
{0x09cbb5e6, 84, "VS-90002", 70290, NULL},
|
|
{0x0aa88f33, 22, "T4955754200939", 0, "1p"},
|
|
{0x0ad97b04, 57, NULL, 93, NULL},
|
|
{0x0b7f6e5f, 42, "NCS91002", 290391, "5p"},
|
|
{0x0be0e0a8, 24, "TGX020039", 0, "aka ADVENTURE ISLAND,1p"},
|
|
{0x0d766139, 3, "NX91005", 61291, "1p"},
|
|
{0x0df57c90, 44, NULL, 0, NULL},
|
|
{0x106bb7b2, 70, "SS90003", 121090, "1p"},
|
|
{0x109ba474, 42, "NCS91001", 270491, "aka SHOCKMAN,2p"},
|
|
{0x10b60601, 13, NULL, 290493, "5p"},
|
|
{0x113dd5f0, 24, "HC89019", 70789, "aka BLAZING LAZERS,1p"},
|
|
{0x11a36745, 44, "NC63004", 110888, NULL},
|
|
{0x12c4e6fd, 19, "FA02-007", 71290, NULL},
|
|
{0x13bf0409, 27, "HM89002", 231289, NULL},
|
|
{0x149d0511, 33, "HC63007", 250388, "1p (BOOTLEG TRAINER VERSION)"},
|
|
{0x14daf737, 83, NULL, 0, NULL},
|
|
{0x14fad3ba, 44, NULL, 0, "2p"},
|
|
{0x1555697e, 68, "HC91050", 201291, NULL},
|
|
{0x166a0e44, 48, "NX90004", 200790, "2p"},
|
|
{0x1772a6bc, 73, "TP02007", 230290, NULL},
|
|
{0x1772b229, 32, "IG90001", 0, NULL},
|
|
{0x17a47d0d, 48, "NX90008", 71290, NULL},
|
|
{0x17ba3032, 48, "NX89003", 131089, "1p"},
|
|
{0x1828d2e5, 56, "NB91005", 291191, NULL},
|
|
{0x19ff94e5, 73, "TP03021", 130392, NULL},
|
|
{0x1a8393c6, 44, "NC63002", 150788, "1p"},
|
|
{0x1b1a80a2, 6, "HC63015", 40389, "5p"},
|
|
{0x1b2d0077, 57, "NB96002", 271192, "1p"},
|
|
{0x1b5b1cb1, 56, "NB90003", 280990, NULL},
|
|
{0x1bc36b36, 29, "AI02005", 141290, "aka SINISTRON,1p"},
|
|
{0x1c6ff459, 43, "MR90002", 141290, "1p,linkable"},
|
|
{0x1cad4b7f, 2, "AC89003", 11289, NULL},
|
|
{0x1e1d0319, 73, "NAPH-1009", 0, NULL},
|
|
{0x1e2cbcf8, 0, NULL, 0, "5p"},
|
|
{0x1eb30eeb, 27, "HM89001", 220689, NULL},
|
|
{0x20a7d128, 48, "NX90006", 261090, NULL},
|
|
{0x20ef87fd, 8, "PV-2004", 230390, NULL},
|
|
{0x21b5409c, 24, "HC91039", 210691, NULL},
|
|
{0x231b1535, 73, NULL, 0, NULL},
|
|
{0x23d22d63, 29, "ITGX10001", 0, "aka WORLD BEACH VOLLEYBALL,4p"},
|
|
{0x23ec8970, 23, "HD90001", 100890, NULL},
|
|
{0x2546efe0, 61, "NAPH-1021", 270991, NULL},
|
|
{0x25a02bee, 19, "FA03-009", 120791, "1p"},
|
|
{0x25be2b81, 34, "TGX040051", 0, "2p"},
|
|
{0x25de250a, 24, "HC90030", 270490, "aka BLUE BLINK"},
|
|
{0x25e0f6e9, 5, "AS02002", 130490, "TGX020005"},
|
|
{0x26020c77, 24, NULL, 0, NULL},
|
|
{0x261f1013, 24, "HC90028", 300390, "aka CHEW-MAN-FU,2p"},
|
|
{0x2739b927, 44, NULL, 0, NULL},
|
|
{0x2762792b, 48, NULL, 0, "2p"},
|
|
{0x27a4d11a, 42, "NCS89003", 280389, "2p"},
|
|
{0x283b74e0, 54, NULL, 0, NULL},
|
|
{0x2841fd1e, 24, NULL, 0, NULL},
|
|
{0x284ebe25, 24, NULL, 0, NULL},
|
|
{0x29eec024, 24, "HC92058", 101092, "aka WORLD SPORTS COMPETITION,5p"},
|
|
{0x2a3e08e2, 16, NULL, 0, NULL},
|
|
{0x2b54cba2, 7, "HC63016", 221288, "5p"},
|
|
{0x2b94aedc, 26, "HC91047", 270991, "1p"},
|
|
{0x2bc023fc, 68, "HC91050", 201291, NULL},
|
|
{0x2cb5cd55, 24, "HC89024", 151289, "1p"},
|
|
{0x2cb796e2, 24, "HC89024", 151289, "1p"},
|
|
{0x2cb92290, 33, "IC01002", 11289, "aka MR.HELI's BIG ADVENTURE,1p"},
|
|
{0x2cee30ee, 54, "TGX040077", 0, NULL},
|
|
{0x2db4c1fd, 28, "TGX040076", 0, NULL},
|
|
{0x2df97bd0, 19, NULL, 0, NULL},
|
|
{0x2e5ac9c0, 43, "TGX010031", 0, "1p"},
|
|
{0x2e955051, 80, "TON90002", 140990, NULL},
|
|
{0x2f8935aa, 24, "HC63012", 300888, "aka KEITH COURAGE IN ALPHA ZONES"},
|
|
{0x2fd65312, 9, "BG01004", 220889, NULL},
|
|
{0x3028f7ca, 24, "HC91043", 190791, "1p"},
|
|
{0x30cc3563, 24, "HC91046", 90891, "2p"},
|
|
{0x30d4bd0e, 26, NULL, 0, "1p"},
|
|
{0x31dd1c32, 48, "NX89001", 300589, NULL},
|
|
{0x31e2e7b6, 24, "HC91041", 50491, NULL},
|
|
{0x320f5018, 0, "HC692", 91, "EXTRA BACKUP RAM CARD"},
|
|
{0x3219849c, 44, "NC91005", 271291, NULL},
|
|
{0x345f43e9, 24, "HC90031", 210990, NULL},
|
|
{0x348022f7, 24, "TGX020014", 0, "aka KATO & KEN CHAN"},
|
|
{0x34e089a9, 44, "NC63001", 200588, NULL},
|
|
{0x34fd4ef2, 29, "AI02005", 141290, "aka SINISTRON,1p"},
|
|
{0x364508da, 42, "NCS91002", 290391, "5p"},
|
|
{0x38e2917d, 24, NULL, 0, NULL},
|
|
{0x390710ec, 29, NULL, 0, NULL},
|
|
{0x3920105a, 54, NULL, 0, NULL},
|
|
{0x3aea2f8f, 29, "AI-03004", 60791, "aka TRICKY KICK"},
|
|
{0x3b13af61, 0, "HC89026", 301189, NULL},
|
|
{0x3b3808bd, 24, NULL, 0, "EXTRA SAVE RAM THING BY HUDSON"},
|
|
{0x3e4eaf98, 15, "CC-01001", 81289, NULL},
|
|
{0x3e647d8b, 24, "HC91039", 210691, NULL},
|
|
{0x3e79734c, 33, "ICO3006", 190791, NULL},
|
|
{0x3f982d0f, 1, "ATGX04TUTG", 0, NULL},
|
|
{0x3f9f95a4, 54, NULL, 0, NULL},
|
|
{0x4148fd7c, 14, "CJ92002", 130392, NULL},
|
|
{0x428f36cd, 42, "NCS89002", 230289, "5p"},
|
|
{0x43efc974, 48, "NX90001", 10390, "aka PSYCHOSIS,2p"},
|
|
{0x442405d5, 42, "NCS91003", 270991, NULL},
|
|
{0x44af9bea, 24, "TGX020027", 0, "aka DORAEMON MEIKYU DAISAKUSEN,1p"},
|
|
{0x44e7df53, 11, "MC91002", 240591, NULL},
|
|
{0x44f60137, 32, "IG89002", 0, NULL},
|
|
{0x457f2bc4, 23, "HD91013", 291191, NULL},
|
|
{0x45885afb, 73, NULL, 0, "2p"},
|
|
{0x462256fb, 9, "BG01004", 220889, NULL},
|
|
{0x469a0fdf, 21, "JC63002", 240389, "aka WAR OF THE DEAD,1p"},
|
|
{0x471903c6, 5, "AS01001", 81289, NULL},
|
|
{0x47afe6d7, 16, "TGX040037", 0, NULL},
|
|
{0x4938b8bb, 24, "HC91041", 50491, NULL},
|
|
{0x4a135429, 18, "TGX040066", 0, "1p"},
|
|
{0x4a3df3ca, 44, "NC90003", 270490, NULL},
|
|
{0x4bd38f17, 82, "UP02002", 280990, "1p"},
|
|
{0x4c2126b0, 24, "HC91044", 220291, "1p"},
|
|
{0x4caa6be9, 16, NULL, 0, "1p"},
|
|
{0x4cef0456, 42, "NCS90005", 141290, "1p"},
|
|
{0x4d344c8c, 24, NULL, 0, NULL},
|
|
{0x4d3b0bc9, 44, "NC91001", 150391, NULL},
|
|
{0x4d539c9f, 83, "JC63011", 20891, "1p"},
|
|
{0x4df54b81, 54, "TGX030064", 0, NULL},
|
|
{0x4f2844b0, 80, NULL, 0, NULL},
|
|
{0x4f2bd39f, 71, "H54G-1004", 140789, NULL},
|
|
{0x500472d4, 12, NULL, 0, NULL},
|
|
{0x5157a395, 24, NULL, 0, NULL},
|
|
{0x51e86451, 73, NULL, 0, "2p"},
|
|
{0x52520bc6, 54, NULL, 0, NULL},
|
|
{0x53109ae6, 24, "HC62005", 220188, NULL},
|
|
{0x534e8808, 27, "HM92006", 131192, NULL},
|
|
{0x53b7784b, 43, NULL, 60392, NULL},
|
|
{0x560d2305, 27, "HM91004", 10391, NULL},
|
|
{0x56488b36, 58, "PV-1007", 291191, NULL},
|
|
{0x56739bc7, 45, NULL, 0, NULL},
|
|
{0x574352c6, 50, NULL, 0, NULL},
|
|
{0x57615647, 49, "TGX040087", 0, "2p"},
|
|
{0x57a436a2, 1, NULL, 0, NULL},
|
|
{0x57f183ae, 24, NULL, 89, NULL},
|
|
{0x589d33eb, 83, NULL, 0, NULL},
|
|
{0x595bb22a, 24, "HC63016", 90289, "2p"},
|
|
{0x59d07314, 44, "NC64001", 210489, "1p"},
|
|
{0x59e44f45, 24, "HS93054", 100293, "5p"},
|
|
{0x5c4d1991, 15, "CC-01001", 81289, NULL},
|
|
{0x5c78fee1, 20, "MC66680", 40889, "1p"},
|
|
{0x5cdb3f5b, 70, "SS89001", 170389, "1p"},
|
|
{0x5cf59d80, 35, "KM92004", 280292, NULL},
|
|
{0x5d0e3105, 24, "HE-1097", 60790, "1p"},
|
|
{0x5e4fa713, 24, NULL, 0, NULL},
|
|
{0x5f2c9a45, 22, "T4955754200984", 0, "2p"},
|
|
{0x6069c5e7, 24, "HC62006", 301187, "aka JJ & JEFF"},
|
|
{0x60ecae22, 48, "NX89001", 300589, NULL},
|
|
{0x60edf4e1, 48, "NX63001", 140988, NULL},
|
|
{0x616ea179, 16, "DE90004", 290391, "1p"},
|
|
{0x61a6e210, 48, NULL, 0, NULL},
|
|
{0x61b80005, 58, "PV1003", 221289, "1p"},
|
|
{0x6203de23, 22, NULL, 0, NULL},
|
|
{0x625221a6, 24, "HC90034", 200790, NULL},
|
|
{0x6257cce7, 52, NULL, 0, NULL},
|
|
{0x62654ad5, 73, "TPO1002", 300689, NULL},
|
|
{0x6273a9d4, 44, "TGX020018", 0, "1p"},
|
|
{0x62ec2956, 44, "NC63004", 110888, NULL},
|
|
{0x633a3d48, 73, "TP02010", 310590, "2p"},
|
|
{0x637ba71d, 30, NULL, 0, "BOOTLEG"},
|
|
{0x64301ff1, 24, "TGX040058", 0, "1p"},
|
|
{0x64580427, 52, "H67G-1002", 91288, "1p"},
|
|
{0x647718f9, 35, "KM92003", 210292, NULL},
|
|
{0x65fdb863, 75, "NX90002", 300390, "aka HOT BLOOD HIGHSCHOOL DODGEBALL"},
|
|
{0x67573bac, 24, "HC92052", 240192, NULL},
|
|
{0x67aab7a1, 58, "PV-1005", 141290, "1p"},
|
|
{0x67aede77, 24, NULL, 0, NULL},
|
|
{0x67ec5ec4, 16, "DE90005", 300390, "aka DROP OFF"},
|
|
{0x6923d736, 24, "HC62004", 301087, "1p"},
|
|
{0x6976d5b3, 30, "1992", 0, NULL},
|
|
{0x6a628982, 63, NULL, 0, NULL},
|
|
{0x6b319457, 44, NULL, 0, "1p"},
|
|
{0x6c30f0ac, 30, NULL, 0, "BOOTLEG"},
|
|
{0x6c34aaea, 56, "NB1001", 10290, "1p"},
|
|
{0x6cca614c, 24, "HC90040", 221290, NULL},
|
|
{0x6e297e49, 82, "UP02002", 280990, "1p"},
|
|
{0x6eab778c, 71, "HC63009", 30688, "1p"},
|
|
{0x6f4fd790, 73, "TP02006", 260190, "1p"},
|
|
{0x6fd6827c, 49, "NCS63001", 230988, NULL},
|
|
{0x70749841, 13, NULL, 290493, "5p"},
|
|
{0x70d90e20, 44, "TGX020019", 0, "4p"},
|
|
{0x7146027c, 27, "HM94007", 150194, NULL},
|
|
{0x727f4656, 1, "JC63012", 240792, NULL},
|
|
{0x72814acb, 44, NULL, 0, NULL},
|
|
{0x72a2c22c, 73, "TP01003", 291189, NULL},
|
|
{0x72cb0f9d, 63, "H49G-1001", 141088, NULL},
|
|
{0x72d6860b, 19, NULL, 0, NULL},
|
|
{0x72e00bc4, 44, "NC92003", 250692, NULL},
|
|
{0x73614660, 54, NULL, 0, NULL},
|
|
{0x73e994a0, 48, "NX90001", 10390, "aka PSYCHOSIS,2p"},
|
|
{0x740491c2, 24, "HC92053", 201192, "1p"},
|
|
{0x7424452e, 66, "TGX040067", 0, "1p,linkable"},
|
|
{0x745408ae, 42, "NCS89002", 230289, "5p"},
|
|
{0x74903426, 48, "NX91003", 120491, NULL},
|
|
{0x756a1802, 24, NULL, 0, NULL},
|
|
{0x76164593, 73, "TP02014", 141290, NULL},
|
|
{0x7632db90, 2, "AC89001", 200389, NULL},
|
|
{0x767245cd, 24, "TGX020008", 0, "aka THE KUNG FU,1p"},
|
|
{0x775bd3e1, 73, "TPO3019", 200991, NULL},
|
|
{0x786d9bbd, 73, NULL, 0, "2p"},
|
|
{0x79362389, 12, "NX91002", 220391, "2p"},
|
|
{0x7aa9d4dc, 24, "TGX030010", 0, "aka GUNHED,1p"},
|
|
{0x7acb60c8, 73, "TP03019", 200991, "4p"},
|
|
{0x7b96317c, 24, "HC90034", 200790, NULL},
|
|
{0x7d3e6f33, 24, NULL, 0, NULL},
|
|
{0x7d48d2fc, 73, "TP02015", 180191, "2p"},
|
|
{0x805a34b9, 83, "JC63013", 290493, NULL},
|
|
{0x80c3f824, 44, "NC62001", 0, "aka GHOST TRAVEL STORY"},
|
|
{0x82ae3b16, 12, "JC63004", 230290, "aka TIGER ROAD"},
|
|
{0x82def9ee, 36, "NV91001", 131291, NULL},
|
|
{0x83213ade, 48, "NX90005", 280990, NULL},
|
|
{0x8420b12b, 24, "HC92056", 100792, NULL},
|
|
{0x850829f2, 64, "HC91049", 221191, "1p"},
|
|
{0x85101c20, 52, "NAPH-1007", 220690, NULL},
|
|
{0x854c37b3, 44, "NC89003", 70789, "2p"},
|
|
{0x85a1e7b6, 27, "HM90003", 270490, NULL},
|
|
{0x85aa49d0, 29, "ITGX10007", 0, "aka VIOLENT SOLDIER"},
|
|
{0x85b85ff9, 73, "TP02012", 60790, NULL},
|
|
{0x85cc9b60, 45, NULL, 0, NULL},
|
|
{0x86087b39, 42, "NCS89006", 290989, "2p"},
|
|
{0x8793758c, 44, "NC92002", 70492, "aka Samurai Ghost,1p"},
|
|
{0x87fd22ad, 24, "HC90036", 71290, "5p,linkable"},
|
|
{0x88796264, 24, "TGX020035", 0, "aka BE BALL,2p"},
|
|
{0x8a046cdc, 44, "NC92003", 250692, NULL},
|
|
{0x8aa4b220, 24, "HC90037", 100890, "2p"},
|
|
{0x8acfc8aa, 0, NULL, 0, "2p"},
|
|
{0x8bf34ffa, 24, NULL, 0, NULL},
|
|
{0x8c4588e2, 24, "HC91048", 230891, "2p"},
|
|
{0x8c565cb6, 44, "NC89004", 80989, "1p"},
|
|
{0x8dc0d85f, 73, "TP02015", 180191, "2p"},
|
|
{0x8def5aa1, 24, "HC93062", 250693, NULL},
|
|
{0x8e25dc77, 73, "TP02009", 270390, NULL},
|
|
{0x8e4d75a8, 73, "TP02007", 230290, NULL},
|
|
{0x8e71d4f3, 24, NULL, 0, "aka DRAGON'S CURSE,1p"},
|
|
{0x8f02fd20, 24, "HC89018", 250589, NULL},
|
|
{0x8f4d9f94, 31, "IM92001", 0, "aka THE LOST SUNHEART"},
|
|
{0x90ed6575, 27, "HM89001", 220689, NULL},
|
|
{0x9107bcc8, 52, NULL, 0, NULL},
|
|
{0x91e6896f, 19, NULL, 261090, "FA02-005,1p"},
|
|
{0x92521f34, 54, "TGX040062", 0, "1p"},
|
|
{0x92c919ea, 70, "SS90003", 121090, "1p"},
|
|
{0x93f05168, 24, NULL, 0, NULL},
|
|
{0x93f316f7, 24, "TGX030015", 0, "aka NECTARIS,2p"},
|
|
{0x94c55627, 73, "TP01005", 271289, "1p"},
|
|
{0x951aa310, 24, NULL, 0, NULL},
|
|
{0x951ed380, 44, "NC92001", 100192, "1p"},
|
|
{0x958bcd09, 24, "HC90027", 230390, "1p"},
|
|
{0x95f90dec, 41, NULL, 90, NULL},
|
|
{0x965c95b3, 73, "TP02011", 290690, "1p"},
|
|
{0x968770f6, 71, "HC90028", 300390, "aka CHEW-MAN-FU,2p"},
|
|
{0x968d908a, 83, "JC63008", 290391, NULL},
|
|
{0x9693d259, 60, "CJ0001", 131291, "2p"},
|
|
{0x96e0cd9d, 73, "TP01002", 300689, NULL},
|
|
{0x9759a20d, 54, NULL, 0, NULL},
|
|
{0x97c5ee9a, 83, "JC63009", 141290, NULL},
|
|
{0x9893e0e6, 48, "NX90001", 10390, "aka PSYCHOSIS,2p"},
|
|
{0x9897fa86, 19, "FA02-006", 70990, NULL},
|
|
{0x98b03ec9, 0, NULL, 0, "CRACKED TO WORK ON JAP PC-E"},
|
|
{0x99033916, 43, "MR92005", 60392, NULL},
|
|
{0x9913a9de, 24, "TGX080097", 0, "2p"},
|
|
{0x99496db3, 73, "TP02008", 20390, "1p"},
|
|
{0x99f2865c, 24, "HC89025", 250590, "1p"},
|
|
{0x99f7a572, 37, "TJ03002", 290391, "1p,linkable"},
|
|
{0x9a41c638, 13, NULL, 0, "5p"},
|
|
{0x9abb4d1f, 24, "HC90036", 71290, "5p,linkable"},
|
|
{0x9b5ebc58, 16, "DE64001", 30389, "4p"},
|
|
{0x9bb8d362, 78, NULL, 0, NULL},
|
|
{0x9c49ef11, 26, "HC89022", 171189, "1p"},
|
|
{0x9c7a8ee4, 29, NULL, 0, "aka TRICKY"},
|
|
{0x9d1a0f5a, 25, "HC89022", 171189, "1p"},
|
|
{0x9e86ffb0, 42, "NCS89006", 290989, "2p"},
|
|
{0x9ec6fc6c, 22, NULL, 0, NULL},
|
|
{0x9edc0aea, 73, "TPO2014", 141290, NULL},
|
|
{0x9fb4de48, 33, "ICO3006", 190791, NULL},
|
|
{0xa019b724, 44, NULL, 0, NULL},
|
|
{0xa0c97557, 29, "AI-02001", 90390, "1p"},
|
|
{0xa15a1f37, 44, "NC90008", 111290, "1p"},
|
|
{0xa170b60e, 24, "HC93063", 20493, "2p"},
|
|
{0xa17d4d7e, 24, "HC89019", 70789, "aka BLAZING LAZERS,1p"},
|
|
{0xa2a0776e, 84, "VS-89001", 190689, "1p"},
|
|
{0xa32430d5, 55, "NV92001", 310192, NULL},
|
|
{0xa326334a, 62, "SL01001", 221189, "1p"},
|
|
{0xa3303978, 44, "NC90006", 90990, "1p"},
|
|
{0xa5290dd0, 43, "MR91004", 131291, NULL},
|
|
{0xa586d190, 73, NULL, 0, NULL},
|
|
{0xa594fac0, 80, "TON90003", 121090, NULL},
|
|
{0xa6088275, 73, NULL, 0, NULL},
|
|
{0xa6539306, 80, "TON90004", 91190, NULL},
|
|
{0xa71d70d0, 42, "NCS90001", 260190, NULL},
|
|
{0xa80c565f, 33, "IC02003", 270790, NULL},
|
|
{0xa9084d6e, 42, "NCS89004", 0, NULL},
|
|
{0xa98d276a, 29, "TGX030030", 0, "1p"},
|
|
{0xa9a94e1b, 25, NULL, 0, "1p"},
|
|
{0xa9ab2954, 44, NULL, 0, NULL},
|
|
{0xa9fab7d2, 40, "TGX040069", 0, "1p"},
|
|
{0xab3c5804, 24, "HE-1097", 60790, "1p"},
|
|
{0xad226f30, 73, "TP01005", 271289, "1p"},
|
|
{0xad450dfc, 53, NULL, 0, NULL},
|
|
{0xad6e0376, 83, NULL, 0, "3p"},
|
|
{0xae26f30f, 24, "TGX060078", 0, "1p"},
|
|
{0xae9fe1aa, 33, "TGX040050", 0, NULL},
|
|
{0xaf2dd2af, 24, "HC91045", 50791, "1p"},
|
|
{0xb01ee703, 24, "HC92059", 250992, NULL},
|
|
{0xb01f70c2, 16, "DE89003", 10989, "1p"},
|
|
{0xb0ba689f, 51, NULL, 0, NULL},
|
|
{0xb101b333, 48, "XX-XX-90", 0, NULL},
|
|
{0xb122787b, 24, "HC63010", 80788, NULL},
|
|
{0xb18d102d, 48, "NX91003", 120491, NULL},
|
|
{0xb24e6504, 28, "TGX040054", 0, NULL},
|
|
{0xb268f2a2, 56, NULL, 92, NULL},
|
|
{0xb2ef558d, 73, NULL, 0, NULL},
|
|
{0xb300c5d0, 24, "HC92061", 111292, "5p,linkable"},
|
|
{0xb3eeea2e, 44, "NC91004", 181091, "1p"},
|
|
{0xb486a8ed, 12, "NAPH-1008", 270790, "1p"},
|
|
{0xb4d29e3b, 48, "NX91004", 291191, "1p"},
|
|
{0xb5326b16, 80, NULL, 0, NULL},
|
|
{0xb54debd1, 69, "TGX020001", 0, "aka MAJIN EIYU WATARU,1p"},
|
|
{0xb552c906, 54, "TGX020008", 0, "1p"},
|
|
{0xb630ab25, 24, "HC89024", 151289, "1p"},
|
|
{0xb64de6fd, 48, NULL, 0, NULL},
|
|
{0xb74ec562, 17, "DE90006", 80191, NULL},
|
|
{0xb77f2e2f, 43, NULL, 0, NULL},
|
|
{0xb866d282, 22, "T4955754200946", 0, NULL},
|
|
{0xb926c682, 44, "NC90001", 160390, "1p"},
|
|
{0xb9899178, 44, "NC90007", 280990, NULL},
|
|
{0xb99a85b6, 64, "HC91049", 221191, "1p"},
|
|
{0xb9dfc085, 27, "HM89002", 231289, NULL},
|
|
{0xba4d0dd4, 73, "TP03018", 90891, NULL},
|
|
{0xbb3ca04a, 3, "NX91005", 61291, "1p"},
|
|
{0xbb654d1c, 24, "HC92057", 70892, "2p"},
|
|
{0xbb761f3b, 19, "FA02-006", 70990, NULL},
|
|
{0xbc655cf3, 5, "AS01001", 81289, NULL},
|
|
{0xbe62eef5, 16, "DE89002", 10489, NULL},
|
|
{0xbe850530, 29, NULL, 270790, "aka SONIC SPIKE"},
|
|
{0xbe8b6e3b, 58, "PV-1008", 0, NULL},
|
|
{0xbe990010, 48, NULL, 0, NULL},
|
|
{0xbf3e2cc7, 19, "FA64-0001", 10389, NULL},
|
|
{0xbf52788e, 83, "JC63006", 300390, NULL},
|
|
{0xbf797067, 12, "JC63004", 230290, "aka TIGER ROAD"},
|
|
{0xc02b1b59, 34, NULL, 0, NULL},
|
|
{0xc0905ca9, 74, "HC63008", 220488, "aka VICTORY LIFE,5p"},
|
|
{0xc0af0947, 42, NULL, 0, NULL},
|
|
{0xc150637a, 0, "BG01003", 280689, NULL},
|
|
{0xc159761b, 40, NULL, 0, NULL},
|
|
{0xc2287894, 58, NULL, 0, NULL},
|
|
{0xc267e25d, 73, "TP01003", 291189, NULL},
|
|
{0xc28b0d8a, 33, "IC03005", 130391, "2p"},
|
|
{0xc3212c24, 81, "PJ91001", 60491, NULL},
|
|
{0xc356216b, 2, NULL, 0, "2p"},
|
|
{0xc42b6d76, 70, "SS89002", 221289, "1p"},
|
|
{0xc4eb68a5, 44, "NC63004", 110888, NULL},
|
|
{0xc5fdfa89, 24, "HC89020", 80889, "2p"},
|
|
{0xc614116c, 58, "PV1003", 221289, "1p"},
|
|
{0xc6f764ec, 22, "T4955754200922", 0, "1p"},
|
|
{0xc6fa6373, 24, "HC90032", 180191, "1p"},
|
|
{0xc7327632, 42, "NCS90002", 230290, NULL},
|
|
{0xc74ffbc9, 77, "TG90001", 100890, "1p"},
|
|
{0xc7847df7, 24, NULL, 0, NULL},
|
|
{0xc81d0371, 48, NULL, 0, "aka PARANOIA"},
|
|
{0xc8a412e1, 33, NULL, 0, "1p"},
|
|
{0xc8c084e3, 44, "NC89003", 70789, "2p"},
|
|
{0xc8c7d63e, 63, "HG8G-1006", 290989, "aka ALTERED BEAST,1p"},
|
|
{0xc90971ba, 44, "NC90007", 280990, NULL},
|
|
{0xc9d7426a, 48, "NX89002", 100889, "4p"},
|
|
{0xca12afba, 2, "AC90001", 211290, "1p"},
|
|
{0xca68ff21, 42, "NCS89005", 190489, NULL},
|
|
{0xca72a828, 63, "NAPH-1011", 280990, NULL},
|
|
{0xcaad79ce, 73, "TP01004", 221289, NULL},
|
|
{0xcab21b2e, 10, "NX89004", 260190, "1p"},
|
|
{0xcacc06fb, 6, "BG01003", 280689, "aka LEGENDARY AXE II"},
|
|
{0xcae1f5db, 67, "TGX040072", 0, "1p"},
|
|
{0xcc799d92, 11, "MC91002", 240591, NULL},
|
|
{0xcc7d3eeb, 73, NULL, 0, NULL},
|
|
{0xce2e4f9f, 84, "VS-90002", 70290, NULL},
|
|
{0xcec3d28a, 33, "HC63007", 250388, "1p"},
|
|
{0xcf73d8fc, 24, "HC89017", 270489, "1p"},
|
|
{0xcfc5a395, 73, "TP02013", 30890, "aka TOUR OF HELL"},
|
|
{0xcfcfc7be, 44, "NC89003", 70789, "2p"},
|
|
{0xcfec1d6a, 19, "TGX040090", 0, NULL},
|
|
{0xd0c250ca, 19, "FA01-002", 230689, NULL},
|
|
{0xd15cb6bb, 12, "HE93002", 120693, "2p"},
|
|
{0xd20f382f, 79, "NX91001", 150391, NULL},
|
|
{0xd233c05a, 48, "NX90008", 71290, NULL},
|
|
{0xd329cf9a, 24, "HC89020", 80889, "2p"},
|
|
{0xd3fd6971, 24, "HC90037", 100890, "2p"},
|
|
{0xd4c5af46, 6, NULL, 0, NULL},
|
|
{0xd50ff730, 52, "H54G-1005", 250889, NULL},
|
|
{0xd5c782f2, 24, NULL, 0, "1p"},
|
|
{0xd5ce2d5f, 24, "HC89021", 150989, NULL},
|
|
{0xd634d931, 54, NULL, 0, NULL},
|
|
{0xd6fc51ce, 22, "T4955754200984", 0, "2p"},
|
|
{0xd7921df2, 52, "H54G-1003", 270189, NULL},
|
|
{0xd7cfd70f, 56, "NB91004", 120791, NULL},
|
|
{0xd8373de6, 84, "VS-90003", 191090, NULL},
|
|
{0xd9e1549a, 24, "HC90040", 221290, NULL},
|
|
{0xda059c9b, 83, "JC63008", 290391, NULL},
|
|
{0xdb872a64, 77, "TTGX20001", 0, "1p"},
|
|
{0xdc268242, 54, "TGX020008", 0, "1p"},
|
|
{0xdc47434b, 29, "AI-02002", 20690, "1p"},
|
|
{0xdc760a07, 24, "HC89023", 311089, "aka CRATERMAZE,1p"},
|
|
{0xdca24a76, 63, "H49G-1001", 141088, NULL},
|
|
{0xdcd3e602, 19, "FA01-002", 230689, NULL},
|
|
{0xdcf3675c, 44, NULL, 261288, NULL},
|
|
{0xdd0ebf8c, 59, "PL91001", 151191, "1p"},
|
|
{0xdd175efd, 82, "UP01001", 190190, NULL},
|
|
{0xdd1d1035, 42, "NCS89005", 190489, NULL},
|
|
{0xdd35451d, 54, NULL, 0, NULL},
|
|
{0xddc3e809, 63, "NAPH-1015", 71290, "1p"},
|
|
{0xde963b7e, 39, "H54G-1004", 140789, NULL},
|
|
{0xdf10c895, 82, NULL, 0, NULL},
|
|
{0xdf804dc7, 70, "SS90001", 20390, "1p"},
|
|
{0xdfd4593a, 33, "IC04007", 21092, "1p"},
|
|
{0xe14dee08, 56, "NB89002", 140990, NULL},
|
|
{0xe1a73797, 70, NULL, 0, NULL},
|
|
{0xe203f223, 63, "NAPH-1016", 211290, NULL},
|
|
{0xe3284ba7, 24, "TGX040084", 0, "1p"},
|
|
{0xe4124fe0, 33, NULL, 0, "1p"},
|
|
{0xe415ea19, 24, "TGX040080", 0, "1p"},
|
|
{0xe439f299, 24, "HC90028", 300390, "aka CHEW-MAN-FU,2p"},
|
|
{0xe4b3415c, 83, "JC63006", 300390, NULL},
|
|
{0xe5b6b3e5, 22, "T4955754200977", 0, NULL},
|
|
{0xe5e7b8b7, 12, "H54G-1004", 140789, NULL},
|
|
{0xe6458212, 73, NULL, 0, "2p"},
|
|
{0xe6c93ae7, 47, "NX90007", 211290, NULL},
|
|
{0xe6ee1468, 58, "PV1004", 270790, NULL},
|
|
{0xe6f16616, 54, "PCE-SC1", 0, NULL},
|
|
{0xe749a22c, 72, "TP03021", 130392, NULL},
|
|
{0xe7529890, 83, "JC63013", 290493, NULL},
|
|
{0xe84890a5, 73, NULL, 0, NULL},
|
|
{0xe8702d51, 33, "IC04007", 21092, "1p"},
|
|
{0xe87190f1, 6, "AT03001", 41091, "aka SOMER ASSAULT,1p"},
|
|
{0xe88987bb, 27, "HM91005", 300891, NULL},
|
|
{0xea324f07, 24, "HC89018", 250589, NULL},
|
|
{0xeb4e600b, 33, "IC63001", 140189, "1p"},
|
|
{0xeb923de5, 73, "TP01004", 221289, NULL},
|
|
{0xeb9452f0, 42, NULL, 0, NULL},
|
|
{0xed3a71f8, 24, "TGX040079", 0, "1p"},
|
|
{0xeda32d95, 54, "TGX040056", 0, "1p"},
|
|
{0xee156721, 43, "MR91003", 80391, "1p"},
|
|
{0xeeb6dd43, 80, NULL, 0, NULL},
|
|
{0xeecfa5fd, 38, "TGX040061", 0, "4p"},
|
|
{0xf0227837, 6, "TGX040089", 0, "aka MESOPOTAMIA"},
|
|
{0xf022be13, 2, "AC89002", 280789, NULL},
|
|
{0xf0ab946e, 25, "HC91047", 270991, "1p"},
|
|
{0xf0cc3363, 84, NULL, 0, NULL},
|
|
{0xf207ecae, 33, "HC63009", 30688, "1p"},
|
|
{0xf2e46d25, 4, "AK91002", 221191, NULL},
|
|
{0xf2e6856d, 22, NULL, 0, NULL},
|
|
{0xf370b58e, 54, "TGX040060", 0, NULL},
|
|
{0xf4148600, 19, "FA02-004", 290690, "1p"},
|
|
{0xf42aa73e, 73, "TP02010", 310590, "2p"},
|
|
{0xf45afbca, 73, NULL, 0, NULL},
|
|
{0xf46298e3, 83, "JC63005", 290690, "3p"},
|
|
{0xf5b90d55, 19, "FA01-003", 241189, "1p"},
|
|
{0xf70112e5, 32, "IG89001", 11189, NULL},
|
|
{0xf79657dd, 24, "HC63015", 40389, "5p"},
|
|
{0xf860455c, 68, "HC92060", 41292, NULL},
|
|
{0xf8861456, 70, "SS90002", 100890, NULL},
|
|
{0xf8f85eec, 44, "NC90004", 290690, "1p"},
|
|
{0xf91b055f, 70, "SS90001", 20390, "1p"},
|
|
{0xf999356f, 24, "HC63014", 181188, NULL},
|
|
{0xfaa6e187, 76, NULL, 0, NULL},
|
|
{0xfae0fc60, 67, "TGX040072", 0, "1p"},
|
|
{0xfaecce20, 35, "KM91002", 61291, "2p"},
|
|
{0xfb0fdcfe, 4, "AK90001", 200490, NULL},
|
|
{0xfb37ddc4, 43, NULL, 0, "aka SOHKO BAN WORLD"},
|
|
{0xfba3a1a4, 71, "NX90006", 261090, NULL},
|
|
{0xfde08d6d, 48, "NX91002", 220391, "2p"},
|
|
{0xff898f87, 52, "NAPH-1010", 310890, NULL},
|
|
{0xffd92458, 22, "T4955754200953", 0, "1p"}
|
|
};
|
|
|
|
|
|
typedef struct st_pce_header
|
|
{
|
|
char pad[48];
|
|
} st_pce_header_t;
|
|
|
|
st_pce_header_t pce_header;
|
|
|
|
|
|
static int
|
|
pce_compare (const void *key, const void *found)
|
|
{
|
|
/*
|
|
The return statement looks overly complicated, but is really necessary.
|
|
This construct:
|
|
return ((st_pce_data_t *) key)->crc32 - ((st_pce_data_t *) found)->crc32;
|
|
does *not* work correctly for all cases.
|
|
*/
|
|
return (int) (((int64_t) ((st_pce_data_t *) key)->crc32 -
|
|
(int64_t) ((st_pce_data_t *) found)->crc32) / 2);
|
|
}
|
|
|
|
|
|
static void
|
|
swapbits (unsigned char *buffer, int size)
|
|
{
|
|
int n, byte, bit;
|
|
|
|
for (n = 0; n < size; n++)
|
|
{
|
|
byte = 0;
|
|
for (bit = 0; bit < 8; bit++)
|
|
if (buffer[n] & (1 << bit))
|
|
byte |= 1 << (7 - bit);
|
|
buffer[n] = byte;
|
|
}
|
|
}
|
|
|
|
|
|
// header format is specified in src/backup/ffe.h
|
|
int
|
|
pcengine_msg (st_rominfo_t *rominfo)
|
|
{
|
|
char src_name[FILENAME_MAX], dest_name[FILENAME_MAX];
|
|
unsigned char *rom_buffer = NULL;
|
|
st_msg_header_t header;
|
|
int size = ucon64.file_size - rominfo->buheader_len;
|
|
|
|
if (rominfo->interleaved)
|
|
if (!(rom_buffer = (unsigned char *) malloc (size)))
|
|
{
|
|
fprintf (stderr, ucon64_msg[ROM_BUFFER_ERROR], size);
|
|
return -1;
|
|
}
|
|
|
|
memset (&header, 0, MSG_HEADER_LEN);
|
|
header.size = size / 8192;
|
|
header.emulation = size == 3 * MBIT ? 1 : 0;
|
|
header.id1 = 0xaa;
|
|
header.id2 = 0xbb;
|
|
header.type = 2;
|
|
|
|
strcpy (src_name, ucon64.rom);
|
|
strcpy (dest_name, ucon64.rom);
|
|
set_suffix (dest_name, ".msg");
|
|
ucon64_file_handler (dest_name, src_name, 0);
|
|
|
|
ucon64_fwrite (&header, 0, MSG_HEADER_LEN, dest_name, "wb");
|
|
if (rominfo->interleaved)
|
|
{
|
|
// Magic Super Griffin files should not be "interleaved"
|
|
ucon64_fread (rom_buffer, rominfo->buheader_len, size, src_name);
|
|
swapbits (rom_buffer, size);
|
|
ucon64_fwrite (rom_buffer, MSG_HEADER_LEN, size, dest_name, "ab");
|
|
free (rom_buffer);
|
|
}
|
|
else
|
|
fcopy (src_name, rominfo->buheader_len, size, dest_name, "ab");
|
|
|
|
printf (ucon64_msg[WROTE], dest_name);
|
|
remove_temp_file ();
|
|
return 0;
|
|
}
|
|
|
|
|
|
// see src/backup/mgd.h for the file naming scheme
|
|
int
|
|
pcengine_mgd (st_rominfo_t *rominfo)
|
|
{
|
|
char src_name[FILENAME_MAX], dest_name[FILENAME_MAX];
|
|
unsigned char *rom_buffer = NULL;
|
|
int size = ucon64.file_size - rominfo->buheader_len;
|
|
|
|
if (!rominfo->interleaved)
|
|
if (!(rom_buffer = (unsigned char *) malloc (size)))
|
|
{
|
|
fprintf (stderr, ucon64_msg[ROM_BUFFER_ERROR], size);
|
|
return -1;
|
|
}
|
|
|
|
strcpy (src_name, ucon64.rom);
|
|
mgd_make_name (ucon64.rom, UCON64_PCE, size, dest_name);
|
|
ucon64_file_handler (dest_name, src_name, OF_FORCE_BASENAME);
|
|
|
|
// bit-swapping images for the MGD2 only makes sense for owners of a TG-16
|
|
// (American version of the PCE)
|
|
if (!rominfo->interleaved)
|
|
{
|
|
ucon64_fread (rom_buffer, rominfo->buheader_len, size, src_name);
|
|
swapbits (rom_buffer, size);
|
|
ucon64_fwrite (rom_buffer, 0, size, dest_name, "wb");
|
|
free (rom_buffer);
|
|
}
|
|
else
|
|
fcopy (src_name, rominfo->buheader_len, size, dest_name, "wb");
|
|
|
|
printf (ucon64_msg[WROTE], dest_name);
|
|
remove_temp_file ();
|
|
|
|
mgd_write_index_file ((char *) basename2 (dest_name), 1);
|
|
return 0;
|
|
}
|
|
|
|
|
|
int
|
|
pcengine_swap (st_rominfo_t *rominfo)
|
|
{
|
|
char src_name[FILENAME_MAX], dest_name[FILENAME_MAX];
|
|
unsigned char *rom_buffer;
|
|
int size = ucon64.file_size - rominfo->buheader_len;
|
|
|
|
if (!(rom_buffer = (unsigned char *) malloc (size)))
|
|
{
|
|
fprintf (stderr, ucon64_msg[ROM_BUFFER_ERROR], size);
|
|
return -1;
|
|
}
|
|
|
|
strcpy (src_name, ucon64.rom);
|
|
strcpy (dest_name, ucon64.rom);
|
|
ucon64_file_handler (dest_name, src_name, 0);
|
|
|
|
if (rominfo->buheader_len) // copy header (if present)
|
|
fcopy (src_name, 0, rominfo->buheader_len, dest_name, "wb");
|
|
|
|
ucon64_fread (rom_buffer, rominfo->buheader_len, size, src_name);
|
|
swapbits (rom_buffer, size);
|
|
ucon64_fwrite (rom_buffer, rominfo->buheader_len, size, dest_name,
|
|
rominfo->buheader_len ? "ab" : "wb");
|
|
free (rom_buffer);
|
|
|
|
printf (ucon64_msg[WROTE], dest_name);
|
|
remove_temp_file ();
|
|
return 0;
|
|
}
|
|
|
|
|
|
int
|
|
pcengine_f (st_rominfo_t *rominfo)
|
|
/*
|
|
Region protection codes are found in (American) TurboGrafx-16 games. It
|
|
prevents those games from running on a PC-Engine. One search pattern seems
|
|
sufficient to fix/crack all TG-16 games. In addition to that, the protection
|
|
code appears to be always somewhere in the first 32 kB.
|
|
*/
|
|
{
|
|
char src_name[FILENAME_MAX], dest_name[FILENAME_MAX], buffer[32 * 1024];
|
|
int bytesread, n;
|
|
|
|
puts ("Attempting to fix region protection code...");
|
|
|
|
strcpy (src_name, ucon64.rom);
|
|
strcpy (dest_name, ucon64.rom);
|
|
ucon64_file_handler (dest_name, src_name, 0);
|
|
fcopy (src_name, 0, ucon64.file_size, dest_name, "wb"); // no copy if one file
|
|
|
|
if ((bytesread = ucon64_fread (buffer, rominfo->buheader_len, 32 * 1024, src_name)) <= 0)
|
|
return -1;
|
|
|
|
// '!' == ASCII 33 (\x21), '*' == 42 (\x2a)
|
|
if (rominfo->interleaved)
|
|
n = change_mem (buffer, bytesread, "\x94\x02\x0f", 3, '*', '!', "\x01", 1, 0);
|
|
else
|
|
n = change_mem (buffer, bytesread, "\x29\x40\xf0", 3, '*', '!', "\x80", 1, 0);
|
|
|
|
ucon64_fwrite (buffer, rominfo->buheader_len, 32 * 1024, dest_name, "r+b");
|
|
|
|
printf ("Found %d pattern%s\n", n, n != 1 ? "s" : "");
|
|
printf (ucon64_msg[WROTE], dest_name);
|
|
remove_temp_file ();
|
|
return n;
|
|
}
|
|
|
|
|
|
static void
|
|
write_game_table_entry (FILE *destfile, int file_no, int totalsize)
|
|
{
|
|
int n;
|
|
unsigned char name[0x1c];
|
|
const char *p;
|
|
|
|
fseek (destfile, 0xb000 + (file_no - 1) * 0x20, SEEK_SET);
|
|
fputc (0xff, destfile); // 0x0 = 0xff
|
|
|
|
memset (name, ' ', 0x1c);
|
|
p = basename2 (ucon64.rom);
|
|
n = strlen (p);
|
|
if (n > 0x1c)
|
|
n = 0x1c;
|
|
memcpy (name, p, n);
|
|
for (n = 0; n < 0x1c; n++)
|
|
{
|
|
if (!isprint ((int) name[n]))
|
|
name[n] = '.';
|
|
else
|
|
name[n] = toupper (name[n]); // loader only supports upper case characters
|
|
}
|
|
fwrite (name, 1, 0x1c, destfile); // 0x1 - 0x1c = name
|
|
fputc (0, destfile); // 0x1d = 0
|
|
fputc (totalsize / MBIT, destfile); // 0x1e = bank code
|
|
fputc (0, destfile); // 0x1f = flags (x, D (reserved), x, x, x, x, x, x)
|
|
}
|
|
|
|
|
|
int
|
|
pcengine_multi (int truncate_size, char *fname)
|
|
{
|
|
#define BUFSIZE (32 * 1024)
|
|
int n, n_files, file_no, bytestowrite, byteswritten, totalsize = 0, done,
|
|
truncated = 0, paddedsize, org_do_not_calc_crc = ucon64.do_not_calc_crc;
|
|
struct stat fstate;
|
|
FILE *srcfile, *destfile;
|
|
char destname[FILENAME_MAX];
|
|
unsigned char buffer[BUFSIZE];
|
|
|
|
if (truncate_size == 0)
|
|
{
|
|
fprintf (stderr, "ERROR: Can't make multi-game file of 0 bytes\n");
|
|
return -1;
|
|
}
|
|
|
|
if (fname != NULL)
|
|
{
|
|
strcpy (destname, fname);
|
|
n_files = ucon64.argc;
|
|
}
|
|
else
|
|
{
|
|
strcpy (destname, ucon64.argv[ucon64.argc - 1]);
|
|
n_files = ucon64.argc - 1;
|
|
}
|
|
|
|
ucon64_file_handler (destname, NULL, OF_FORCE_BASENAME);
|
|
if ((destfile = fopen (destname, "wb")) == NULL)
|
|
{
|
|
fprintf (stderr, ucon64_msg[OPEN_WRITE_ERROR], destname);
|
|
return -1;
|
|
}
|
|
|
|
printf ("Creating multi-game file for PCE-PRO: %s\n", destname);
|
|
|
|
file_no = 0;
|
|
for (n = 1; n < n_files; n++)
|
|
{
|
|
if (access (ucon64.argv[n], F_OK))
|
|
continue; // "file" does not exist (option)
|
|
stat (ucon64.argv[n], &fstate);
|
|
if (!S_ISREG (fstate.st_mode))
|
|
continue;
|
|
if (file_no == 32) // loader + 31 games
|
|
{
|
|
printf ("WARNING: A multi-game file can contain a maximum of 31 games. The other files\n"
|
|
" are ignored.\n");
|
|
break;
|
|
}
|
|
|
|
ucon64.console = UCON64_UNKNOWN;
|
|
ucon64.rom = ucon64.argv[n];
|
|
ucon64.file_size = fsizeof (ucon64.rom);
|
|
// DON'T use fstate.st_size, because file could be compressed
|
|
ucon64.rominfo->buheader_len = UCON64_ISSET (ucon64.buheader_len) ?
|
|
ucon64.buheader_len : 0;
|
|
ucon64.rominfo->interleaved = UCON64_ISSET (ucon64.interleaved) ?
|
|
ucon64.interleaved : 0;
|
|
ucon64.do_not_calc_crc = 1;
|
|
if (pcengine_init (ucon64.rominfo) != 0)
|
|
printf ("WARNING: %s does not appear to be a PC-Engine ROM\n", ucon64.rom);
|
|
|
|
if ((srcfile = fopen (ucon64.rom, "rb")) == NULL)
|
|
{
|
|
fprintf (stderr, ucon64_msg[OPEN_READ_ERROR], ucon64.rom);
|
|
continue;
|
|
}
|
|
if (ucon64.rominfo->buheader_len)
|
|
fseek (srcfile, ucon64.rominfo->buheader_len, SEEK_SET);
|
|
|
|
if (file_no == 0)
|
|
{
|
|
printf ("Loader: %s\n", ucon64.rom);
|
|
if (ucon64.file_size - ucon64.rominfo->buheader_len != 7 * 8192)
|
|
printf ("WARNING: Are you sure %s is a loader binary?\n", ucon64.rom);
|
|
}
|
|
else
|
|
{
|
|
printf ("ROM%d: %s\n", file_no, ucon64.rom);
|
|
write_game_table_entry (destfile, file_no, totalsize);
|
|
fseek (destfile, totalsize, SEEK_SET); // restore file pointer
|
|
}
|
|
file_no++;
|
|
|
|
done = 0;
|
|
byteswritten = 0; // # of bytes written per file
|
|
while (!done)
|
|
{
|
|
bytestowrite = fread (buffer, 1, BUFSIZE, srcfile);
|
|
if (totalsize + bytestowrite > truncate_size)
|
|
{
|
|
bytestowrite = truncate_size - totalsize;
|
|
done = 1;
|
|
truncated = 1;
|
|
printf ("Output file is %d Mbit, truncating %s, skipping %d bytes\n",
|
|
truncate_size / MBIT, ucon64.rom, ucon64.file_size -
|
|
ucon64.rominfo->buheader_len - (byteswritten + bytestowrite));
|
|
}
|
|
totalsize += bytestowrite;
|
|
if (bytestowrite == 0)
|
|
done = 1;
|
|
fwrite (buffer, 1, bytestowrite, destfile);
|
|
byteswritten += bytestowrite;
|
|
}
|
|
fclose (srcfile);
|
|
if (truncated)
|
|
break;
|
|
|
|
// games have to be aligned to (start at) a 1 Mbit boundary
|
|
paddedsize = (totalsize + MBIT - 1) & ~(MBIT - 1);
|
|
// printf ("paddedsize: %d (%f); totalsize: %d (%f)\n",
|
|
// paddedsize, paddedsize / (1.0 * MBIT), totalsize, totalsize / (1.0 * MBIT));
|
|
if (paddedsize > totalsize)
|
|
{
|
|
if (paddedsize > truncate_size)
|
|
{
|
|
truncated = 1; // not *really* truncated
|
|
paddedsize = truncate_size;
|
|
}
|
|
|
|
memset (buffer, 0, BUFSIZE);
|
|
while (totalsize < paddedsize)
|
|
{
|
|
bytestowrite = paddedsize - totalsize > BUFSIZE ?
|
|
BUFSIZE : paddedsize - totalsize;
|
|
fwrite (buffer, 1, bytestowrite, destfile);
|
|
totalsize += bytestowrite;
|
|
}
|
|
}
|
|
if (truncated)
|
|
break;
|
|
}
|
|
// fill the next game table entry
|
|
fseek (destfile, 0xb000 + (file_no - 1) * 0x20, SEEK_SET);
|
|
fputc (0, destfile); // indicate no next game
|
|
fclose (destfile);
|
|
ucon64.console = UCON64_PCE;
|
|
ucon64.do_not_calc_crc = org_do_not_calc_crc;
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
static int
|
|
pcengine_check (unsigned char *buf, unsigned int len)
|
|
// This function was contributed by Cowering. Comments are his unless stated
|
|
// otherwise.
|
|
{
|
|
int i, f1 = 0, f2 = 0, f3 = 0, f4 = 0, f5 = 0;
|
|
|
|
// don't crash for too small (non-PCE) files - dbjh
|
|
if (len < 0x200)
|
|
return 0;
|
|
|
|
// Directly look for swapped dead moon (U). Lots of zeroes at file start
|
|
// fakes out header detector.
|
|
// We probably don't need this (no "header detector") - dbjh
|
|
if (buf[0] == 0x1e && buf[1] == 0x2a && buf[2] == 0x95)
|
|
return 1;
|
|
if (buf[0] == 0x12 && buf[1] == 0xe0 && buf[16] == 0x4a) // F-1 Pilot
|
|
return 1;
|
|
if (buf[0] == 0x20 && buf[1] == 0x81 && buf[16] == 0x81) // Cyber Knight
|
|
return 1;
|
|
if (buf[0] == 0x03 && buf[1] == 0x03 && buf[16] == 0x02) // Gaia no monsho
|
|
return 1;
|
|
#if 0 // no reason to not recognise this dump - dbjh
|
|
if (len == 0x40400) // BIOS with 2 headers on front, deleted from database now
|
|
return 0;
|
|
#endif
|
|
/*
|
|
// two headers on a CD-ROM BIOS (bad dump)
|
|
if (len == 0x40200 && buf[0x200] == 0x32 && buf[0x210] == 0xa0 && buf[0x220] == 0xf7)
|
|
return 1;
|
|
*/
|
|
// super mario pirate conversion
|
|
if (len > 65000 && !strncmp ((const char*) &buf[0x77f0], "JGGKGKGGGGGGJGJG", 16))
|
|
return 1;
|
|
if (buf[0x20] == 0x7c && buf[0x21] == 0xe3 && buf[0x22] == 0xe6) // 5 in 1
|
|
return 1;
|
|
if (buf[0x10] == 0xc7 && buf[0x30] == 0xe9 && buf[0x50] == 0xa1) // Sekikehara
|
|
return 1;
|
|
if (!strncmp ((const char *) &buf[0], "!BM FORMAT!", 11)) // boxy boy (U)
|
|
return 1;
|
|
if (!strncmp ((const char *) &buf[0], "PUSH RUN BUTTON", 15)) // boxy boy (J)
|
|
return 1;
|
|
// US CD sys 2.01
|
|
if (len > 0x3ffc7 && !strncmp ((const char *) &buf[0x3ffb6], "PC Engine CD-ROM", 16))
|
|
return 1;
|
|
|
|
for (i = 0 ; i < 0x200; i++)
|
|
{
|
|
if (buf[i] == 0x00)
|
|
f1++;
|
|
if (buf[i] == 0xff)
|
|
f4++;
|
|
if (buf[i] == 0x78)
|
|
f2 = 1;
|
|
if (buf[i] == 0xa9)
|
|
f3 = 1;
|
|
if (buf[i] == 0x85 || buf[i] == 0x8d)
|
|
f5 = 1;
|
|
}
|
|
if ((f4 > 200) || ((f1 > 200) && (f2 + f3 != 2)))
|
|
return 0;
|
|
if (f2 + f3 + f5 >= 2)
|
|
return 1;
|
|
return 0;
|
|
}
|
|
|
|
|
|
int
|
|
pcengine_init (st_rominfo_t *rominfo)
|
|
{
|
|
int result = -1, size, swapped, x;
|
|
unsigned char *rom_buffer;
|
|
st_pce_data_t *info, key;
|
|
|
|
x = ucon64.file_size % (16 * 1024);
|
|
rominfo->buheader_len = UCON64_ISSET (ucon64.buheader_len) ?
|
|
ucon64.buheader_len : (ucon64.file_size > x ? x : 0);
|
|
|
|
size = ucon64.file_size - rominfo->buheader_len;
|
|
if (!(rom_buffer = (unsigned char *) malloc (size)))
|
|
{
|
|
fprintf (stderr, ucon64_msg[ROM_BUFFER_ERROR], size);
|
|
return -1;
|
|
}
|
|
ucon64_fread (rom_buffer, rominfo->buheader_len, size, ucon64.rom);
|
|
|
|
if (pcengine_check (rom_buffer, size) == 1)
|
|
result = 0;
|
|
|
|
swapped = -1;
|
|
/*
|
|
29 40 f0 => unhacked
|
|
29 40 80 => U.S.A. -> Jap hack
|
|
94 02 0f => bit-swapped and unhacked
|
|
94 02 01 => bit-swapped and hacked
|
|
|
|
According to Cowering 2 or 3 games don't use these opcodes to check if a
|
|
Japanese game is running on an American console. If they are present then
|
|
it is in the first 500 (or so) bytes.
|
|
The check for "A..Z" is a fix for Puzznic (J). The check for "HESM" a fix
|
|
for:
|
|
Fire Pro Wrestling - 2nd Bout Sounds
|
|
Fire Pro Wrestling 3 - Legend Bout Sounds
|
|
*/
|
|
x = size > 32768 ? 32768 : size;
|
|
if ((memmem2 (rom_buffer, x, "\x94\x02\x0f", 3, 0) ||
|
|
memmem2 (rom_buffer, x, "\x94\x02\x01", 3, 0)) &&
|
|
memmem2 (rom_buffer, x, "ABCDEFGHIJKLMNOPQRSTUVWXYZ", 26, 0) == 0 &&
|
|
memcmp (rom_buffer, "HESM", 4))
|
|
swapped = 1;
|
|
if (UCON64_ISSET (ucon64.interleaved))
|
|
swapped = ucon64.interleaved;
|
|
|
|
if ((result == -1 && swapped != 0) || swapped == 1)
|
|
{ // don't swap the bits if -nint is specified
|
|
if (!UCON64_ISSET (ucon64.do_not_calc_crc) || swapped == 1)
|
|
ucon64.fcrc32 = crc32 (0, rom_buffer, size);
|
|
swapbits (rom_buffer, size);
|
|
if (pcengine_check (rom_buffer, size) == 1)
|
|
{
|
|
swapped = 1;
|
|
result = 0;
|
|
}
|
|
if (swapped != 1)
|
|
{
|
|
ucon64.crc32 = ucon64.fcrc32;
|
|
ucon64.fcrc32 = 0;
|
|
}
|
|
}
|
|
if (swapped != -1)
|
|
rominfo->interleaved = swapped;
|
|
|
|
if (ucon64.console == UCON64_PCE)
|
|
result = 0;
|
|
|
|
rominfo->header_start = PCENGINE_HEADER_START;
|
|
rominfo->header_len = PCENGINE_HEADER_LEN;
|
|
rominfo->console_usage = pcengine_usage[0].help;
|
|
rominfo->copier_usage = rominfo->buheader_len ? msg_usage[0].help : mgd_usage[0].help;
|
|
|
|
if (!UCON64_ISSET (ucon64.do_not_calc_crc) && result == 0)
|
|
{
|
|
if (!ucon64.crc32)
|
|
ucon64.crc32 = crc32 (0, rom_buffer, size);
|
|
// additional info
|
|
key.crc32 = ucon64.crc32;
|
|
info = (st_pce_data_t *) bsearch (&key, pce_data,
|
|
sizeof pce_data / sizeof (st_pce_data_t),
|
|
sizeof (st_pce_data_t), pce_compare);
|
|
if (info)
|
|
{
|
|
if (info->maker)
|
|
rominfo->maker = NULL_TO_UNKNOWN_S (pce_maker[MIN (info->maker,
|
|
PCE_MAKER_MAX - 1)]);
|
|
|
|
if (info->serial)
|
|
if (info->serial[0])
|
|
{
|
|
strcat (rominfo->misc, "\nSerial: ");
|
|
strcat (rominfo->misc, info->serial);
|
|
}
|
|
|
|
if (info->date)
|
|
{
|
|
int day = info->date / 10000, month = (info->date % 10000) / 100,
|
|
year = info->date % 100;
|
|
char date[80];
|
|
|
|
date[0] = 0;
|
|
if (day)
|
|
sprintf (date, "\nDate: %d/%d/19%d", day, month, year);
|
|
else if (month)
|
|
sprintf (date, "\nDate: %d/19%d", month, year);
|
|
else if (year)
|
|
sprintf (date, "\nDate: 19%d", year);
|
|
strcat (rominfo->misc, date);
|
|
}
|
|
|
|
if (info->comment)
|
|
if (info->comment[0])
|
|
{
|
|
strcat (rominfo->misc, "\nComment: ");
|
|
strcat (rominfo->misc, info->comment);
|
|
}
|
|
}
|
|
}
|
|
|
|
free (rom_buffer);
|
|
return result;
|
|
}
|