Add support for /arcade folder, and MRA xml decoding
* round trip xml launch * roms load * removed debug * added binary data and changed rom format * changed hex format * fixed bug * added structure and start/length * removed base64 support * removed base64 support * fixed parsing bugs * fixed hex parse bug * fixed parser * fixing paths * fixed rbf parser * fixed initialization bug * fixed extension removal for when there are multiple extension options * fixed core path and cleaned up filelength * added md5 checks to arcade roms * fixed rbf search * added error support * Simplify error checking code * fixed arcade error message pop up * fixed bug in part zip initialization * removed dtdt * don't load second rom0 if first works * fixed directory problem * added more comments * added / to zip path * fixed / bug, truncate mame zip error message * fixed scrolling RBF * fixed scrolling name and error message * added code to remove _date in scrolling text * remove redundant /
This commit is contained in:
committed by
sorgelig
parent
aedb73aa12
commit
d981092caa
5
Makefile
5
Makefile
@@ -18,11 +18,13 @@ INCLUDE = -I./
|
||||
INCLUDE += -I./support/minimig
|
||||
INCLUDE += -I./lib/libco
|
||||
INCLUDE += -I./lib/miniz
|
||||
INCLUDE += -I./lib/md5
|
||||
|
||||
PRJ = MiSTer
|
||||
C_SRC = $(wildcard *.c) \
|
||||
$(wildcard ./lib/miniz/*.c) \
|
||||
lib/libco/arm.c
|
||||
$(wildcard ./lib/md5/*.c) \
|
||||
lib/libco/arm.c
|
||||
|
||||
CPP_SRC = $(wildcard *.cpp) \
|
||||
$(wildcard ./support/minimig/*.cpp) \
|
||||
@@ -32,6 +34,7 @@ CPP_SRC = $(wildcard *.cpp) \
|
||||
$(wildcard ./support/x86/*.cpp) \
|
||||
$(wildcard ./support/snes/*.cpp) \
|
||||
$(wildcard ./support/neogeo/*.cpp) \
|
||||
$(wildcard ./support/arcade/*.cpp) \
|
||||
$(wildcard ./support/megacd/*.cpp) \
|
||||
lib/lodepng/lodepng.cpp
|
||||
|
||||
|
||||
@@ -238,7 +238,6 @@ void FileClose(fileTYPE *file)
|
||||
int FileOpenEx(fileTYPE *file, const char *name, int mode, char mute)
|
||||
{
|
||||
make_fullpath((char*)name, mode);
|
||||
|
||||
FileClose(file);
|
||||
file->mode = 0;
|
||||
file->type = 0;
|
||||
|
||||
15
fpga_io.cpp
15
fpga_io.cpp
@@ -14,6 +14,7 @@
|
||||
#include "file_io.h"
|
||||
#include "input.h"
|
||||
#include "osd.h"
|
||||
#include "menu.h"
|
||||
|
||||
#include "fpga_base_addr_ac5.h"
|
||||
#include "fpga_manager.h"
|
||||
@@ -448,7 +449,7 @@ static int make_env(const char *name, const char *cfg)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fpga_load_rbf(const char *name, const char *cfg)
|
||||
int fpga_load_rbf(const char *name, const char *cfg, const char *xml)
|
||||
{
|
||||
OsdDisable();
|
||||
static char path[1024];
|
||||
@@ -470,7 +471,10 @@ int fpga_load_rbf(const char *name, const char *cfg)
|
||||
int rbf = open(path, O_RDONLY);
|
||||
if (rbf < 0)
|
||||
{
|
||||
char error[4096];
|
||||
snprintf(error,4096,"%s\nNot Found", name);
|
||||
printf("Couldn't open file %s\n", path);
|
||||
Info(error,5000);
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
@@ -524,7 +528,7 @@ int fpga_load_rbf(const char *name, const char *cfg)
|
||||
}
|
||||
}
|
||||
close(rbf);
|
||||
app_restart(!strcasecmp(name, "menu.rbf") ? "menu.rbf" : path);
|
||||
app_restart(!strcasecmp(name, "menu.rbf") ? "menu.rbf" : path,xml);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -637,7 +641,7 @@ char *getappname()
|
||||
return dest;
|
||||
}
|
||||
|
||||
void app_restart(const char *path)
|
||||
void app_restart(const char *path, const char *xml)
|
||||
{
|
||||
sync();
|
||||
fpga_core_reset(1);
|
||||
@@ -647,7 +651,10 @@ void app_restart(const char *path)
|
||||
|
||||
char *appname = getappname();
|
||||
printf("restarting the %s\n", appname);
|
||||
execl(appname, appname, path, NULL);
|
||||
if (xml)
|
||||
execl(appname, appname, path, xml,NULL);
|
||||
else
|
||||
execl(appname, appname, path, NULL);
|
||||
|
||||
printf("Something went wrong. Rebooting...\n");
|
||||
reboot(0);
|
||||
|
||||
@@ -26,10 +26,10 @@ int is_fpga_ready(int quick);
|
||||
int fpga_get_fio_size();
|
||||
int fpga_get_io_version();
|
||||
|
||||
int fpga_load_rbf(const char *name, const char *cfg = NULL);
|
||||
int fpga_load_rbf(const char *name, const char *cfg = NULL, const char *xml=NULL);
|
||||
|
||||
void reboot(int cold);
|
||||
void app_restart(const char *path);
|
||||
void app_restart(const char *path, const char *xml=NULL);
|
||||
char *getappname();
|
||||
|
||||
#endif
|
||||
|
||||
330
lib/md5/md5.c
Normal file
330
lib/md5/md5.c
Normal file
@@ -0,0 +1,330 @@
|
||||
/*
|
||||
* This code implements the MD5 message-digest algorithm.
|
||||
* The algorithm is due to Ron Rivest. This code was
|
||||
* written by Colin Plumb in 1993, no copyright is claimed.
|
||||
* This code is in the public domain; do with it what you wish.
|
||||
*
|
||||
* Equivalent code is available from RSA Data Security, Inc.
|
||||
* This code has been tested against that, and is equivalent,
|
||||
* except that you don't need to include two pages of legalese
|
||||
* with every copy.
|
||||
*
|
||||
* To compute the message digest of a chunk of bytes, declare an
|
||||
* MD5Context structure, pass it to MD5Init, call MD5Update as
|
||||
* needed on buffers full of bytes, and then call MD5Final, which
|
||||
* will fill a supplied 16-byte array with the digest.
|
||||
*/
|
||||
|
||||
/* This code was modified in 1997 by Jim Kingdon of Cyclic Software to
|
||||
not require an integer type which is exactly 32 bits. This work
|
||||
draws on the changes for the same purpose by Tatu Ylonen
|
||||
<ylo@cs.hut.fi> as part of SSH, but since I didn't actually use
|
||||
that code, there is no copyright issue. I hereby disclaim
|
||||
copyright in any changes I have made; this code remains in the
|
||||
public domain. */
|
||||
#define STDC_HEADERS 1
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#if HAVE_STRING_H || STDC_HEADERS
|
||||
#include <string.h> /* for memcpy() */
|
||||
#endif
|
||||
|
||||
/* Add prototype support. */
|
||||
#ifndef PROTO
|
||||
#if defined (USE_PROTOTYPES) ? USE_PROTOTYPES : defined (__STDC__)
|
||||
#define PROTO(ARGS) ARGS
|
||||
#else
|
||||
#define PROTO(ARGS) ()
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include "md5.h"
|
||||
|
||||
/* Little-endian byte-swapping routines. Note that these do not
|
||||
depend on the size of datatypes such as uint32, nor do they require
|
||||
us to detect the endianness of the machine we are running on. It
|
||||
is possible they should be macros for speed, but I would be
|
||||
surprised if they were a performance bottleneck for MD5. */
|
||||
|
||||
static uint32
|
||||
getu32 (addr)
|
||||
const unsigned char *addr;
|
||||
{
|
||||
return (((((unsigned long)addr[3] << 8) | addr[2]) << 8)
|
||||
| addr[1]) << 8 | addr[0];
|
||||
}
|
||||
|
||||
static void
|
||||
putu32 (data, addr)
|
||||
uint32 data;
|
||||
unsigned char *addr;
|
||||
{
|
||||
addr[0] = (unsigned char)data;
|
||||
addr[1] = (unsigned char)(data >> 8);
|
||||
addr[2] = (unsigned char)(data >> 16);
|
||||
addr[3] = (unsigned char)(data >> 24);
|
||||
}
|
||||
|
||||
/*
|
||||
* Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
|
||||
* initialization constants.
|
||||
*/
|
||||
void
|
||||
MD5Init(ctx)
|
||||
struct MD5Context *ctx;
|
||||
{
|
||||
ctx->buf[0] = 0x67452301;
|
||||
ctx->buf[1] = 0xefcdab89;
|
||||
ctx->buf[2] = 0x98badcfe;
|
||||
ctx->buf[3] = 0x10325476;
|
||||
|
||||
ctx->bits[0] = 0;
|
||||
ctx->bits[1] = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Update context to reflect the concatenation of another buffer full
|
||||
* of bytes.
|
||||
*/
|
||||
void
|
||||
MD5Update(ctx, buf, len)
|
||||
struct MD5Context *ctx;
|
||||
unsigned char const *buf;
|
||||
unsigned len;
|
||||
{
|
||||
uint32 t;
|
||||
|
||||
/* Update bitcount */
|
||||
|
||||
t = ctx->bits[0];
|
||||
if ((ctx->bits[0] = (t + ((uint32)len << 3)) & 0xffffffff) < t)
|
||||
ctx->bits[1]++; /* Carry from low to high */
|
||||
ctx->bits[1] += len >> 29;
|
||||
|
||||
t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */
|
||||
|
||||
/* Handle any leading odd-sized chunks */
|
||||
|
||||
if ( t ) {
|
||||
unsigned char *p = ctx->in + t;
|
||||
|
||||
t = 64-t;
|
||||
if (len < t) {
|
||||
memcpy(p, buf, len);
|
||||
return;
|
||||
}
|
||||
memcpy(p, buf, t);
|
||||
MD5Transform(ctx->buf, ctx->in);
|
||||
buf += t;
|
||||
len -= t;
|
||||
}
|
||||
|
||||
/* Process data in 64-byte chunks */
|
||||
|
||||
while (len >= 64) {
|
||||
memcpy(ctx->in, buf, 64);
|
||||
MD5Transform(ctx->buf, ctx->in);
|
||||
buf += 64;
|
||||
len -= 64;
|
||||
}
|
||||
|
||||
/* Handle any remaining bytes of data. */
|
||||
|
||||
memcpy(ctx->in, buf, len);
|
||||
}
|
||||
|
||||
/*
|
||||
* Final wrapup - pad to 64-byte boundary with the bit pattern
|
||||
* 1 0* (64-bit count of bits processed, MSB-first)
|
||||
*/
|
||||
void
|
||||
MD5Final(digest, ctx)
|
||||
unsigned char digest[16];
|
||||
struct MD5Context *ctx;
|
||||
{
|
||||
unsigned count;
|
||||
unsigned char *p;
|
||||
|
||||
/* Compute number of bytes mod 64 */
|
||||
count = (ctx->bits[0] >> 3) & 0x3F;
|
||||
|
||||
/* Set the first char of padding to 0x80. This is safe since there is
|
||||
always at least one byte free */
|
||||
p = ctx->in + count;
|
||||
*p++ = 0x80;
|
||||
|
||||
/* Bytes of padding needed to make 64 bytes */
|
||||
count = 64 - 1 - count;
|
||||
|
||||
/* Pad out to 56 mod 64 */
|
||||
if (count < 8) {
|
||||
/* Two lots of padding: Pad the first block to 64 bytes */
|
||||
memset(p, 0, count);
|
||||
MD5Transform(ctx->buf, ctx->in);
|
||||
|
||||
/* Now fill the next block with 56 bytes */
|
||||
memset(ctx->in, 0, 56);
|
||||
} else {
|
||||
/* Pad block to 56 bytes */
|
||||
memset(p, 0, count-8);
|
||||
}
|
||||
|
||||
/* Append length in bits and transform */
|
||||
putu32(ctx->bits[0], ctx->in + 56);
|
||||
putu32(ctx->bits[1], ctx->in + 60);
|
||||
|
||||
MD5Transform(ctx->buf, ctx->in);
|
||||
putu32(ctx->buf[0], digest);
|
||||
putu32(ctx->buf[1], digest + 4);
|
||||
putu32(ctx->buf[2], digest + 8);
|
||||
putu32(ctx->buf[3], digest + 12);
|
||||
memset(ctx, 0, sizeof(ctx)); /* In case it's sensitive */
|
||||
}
|
||||
|
||||
#ifndef ASM_MD5
|
||||
|
||||
/* The four core functions - F1 is optimized somewhat */
|
||||
|
||||
/* #define F1(x, y, z) (x & y | ~x & z) */
|
||||
#define F1(x, y, z) (z ^ (x & (y ^ z)))
|
||||
#define F2(x, y, z) F1(z, x, y)
|
||||
#define F3(x, y, z) (x ^ y ^ z)
|
||||
#define F4(x, y, z) (y ^ (x | ~z))
|
||||
|
||||
/* This is the central step in the MD5 algorithm. */
|
||||
#define MD5STEP(f, w, x, y, z, data, s) \
|
||||
( w += f(x, y, z) + data, w &= 0xffffffff, w = w<<s | w>>(32-s), w += x )
|
||||
|
||||
/*
|
||||
* The core of the MD5 algorithm, this alters an existing MD5 hash to
|
||||
* reflect the addition of 16 longwords of new data. MD5Update blocks
|
||||
* the data and converts bytes into longwords for this routine.
|
||||
*/
|
||||
void
|
||||
MD5Transform(buf, inraw)
|
||||
uint32 buf[4];
|
||||
const unsigned char inraw[64];
|
||||
{
|
||||
register uint32 a, b, c, d;
|
||||
uint32 in[16];
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 16; ++i)
|
||||
in[i] = getu32 (inraw + 4 * i);
|
||||
|
||||
a = buf[0];
|
||||
b = buf[1];
|
||||
c = buf[2];
|
||||
d = buf[3];
|
||||
|
||||
MD5STEP(F1, a, b, c, d, in[ 0]+0xd76aa478, 7);
|
||||
MD5STEP(F1, d, a, b, c, in[ 1]+0xe8c7b756, 12);
|
||||
MD5STEP(F1, c, d, a, b, in[ 2]+0x242070db, 17);
|
||||
MD5STEP(F1, b, c, d, a, in[ 3]+0xc1bdceee, 22);
|
||||
MD5STEP(F1, a, b, c, d, in[ 4]+0xf57c0faf, 7);
|
||||
MD5STEP(F1, d, a, b, c, in[ 5]+0x4787c62a, 12);
|
||||
MD5STEP(F1, c, d, a, b, in[ 6]+0xa8304613, 17);
|
||||
MD5STEP(F1, b, c, d, a, in[ 7]+0xfd469501, 22);
|
||||
MD5STEP(F1, a, b, c, d, in[ 8]+0x698098d8, 7);
|
||||
MD5STEP(F1, d, a, b, c, in[ 9]+0x8b44f7af, 12);
|
||||
MD5STEP(F1, c, d, a, b, in[10]+0xffff5bb1, 17);
|
||||
MD5STEP(F1, b, c, d, a, in[11]+0x895cd7be, 22);
|
||||
MD5STEP(F1, a, b, c, d, in[12]+0x6b901122, 7);
|
||||
MD5STEP(F1, d, a, b, c, in[13]+0xfd987193, 12);
|
||||
MD5STEP(F1, c, d, a, b, in[14]+0xa679438e, 17);
|
||||
MD5STEP(F1, b, c, d, a, in[15]+0x49b40821, 22);
|
||||
|
||||
MD5STEP(F2, a, b, c, d, in[ 1]+0xf61e2562, 5);
|
||||
MD5STEP(F2, d, a, b, c, in[ 6]+0xc040b340, 9);
|
||||
MD5STEP(F2, c, d, a, b, in[11]+0x265e5a51, 14);
|
||||
MD5STEP(F2, b, c, d, a, in[ 0]+0xe9b6c7aa, 20);
|
||||
MD5STEP(F2, a, b, c, d, in[ 5]+0xd62f105d, 5);
|
||||
MD5STEP(F2, d, a, b, c, in[10]+0x02441453, 9);
|
||||
MD5STEP(F2, c, d, a, b, in[15]+0xd8a1e681, 14);
|
||||
MD5STEP(F2, b, c, d, a, in[ 4]+0xe7d3fbc8, 20);
|
||||
MD5STEP(F2, a, b, c, d, in[ 9]+0x21e1cde6, 5);
|
||||
MD5STEP(F2, d, a, b, c, in[14]+0xc33707d6, 9);
|
||||
MD5STEP(F2, c, d, a, b, in[ 3]+0xf4d50d87, 14);
|
||||
MD5STEP(F2, b, c, d, a, in[ 8]+0x455a14ed, 20);
|
||||
MD5STEP(F2, a, b, c, d, in[13]+0xa9e3e905, 5);
|
||||
MD5STEP(F2, d, a, b, c, in[ 2]+0xfcefa3f8, 9);
|
||||
MD5STEP(F2, c, d, a, b, in[ 7]+0x676f02d9, 14);
|
||||
MD5STEP(F2, b, c, d, a, in[12]+0x8d2a4c8a, 20);
|
||||
|
||||
MD5STEP(F3, a, b, c, d, in[ 5]+0xfffa3942, 4);
|
||||
MD5STEP(F3, d, a, b, c, in[ 8]+0x8771f681, 11);
|
||||
MD5STEP(F3, c, d, a, b, in[11]+0x6d9d6122, 16);
|
||||
MD5STEP(F3, b, c, d, a, in[14]+0xfde5380c, 23);
|
||||
MD5STEP(F3, a, b, c, d, in[ 1]+0xa4beea44, 4);
|
||||
MD5STEP(F3, d, a, b, c, in[ 4]+0x4bdecfa9, 11);
|
||||
MD5STEP(F3, c, d, a, b, in[ 7]+0xf6bb4b60, 16);
|
||||
MD5STEP(F3, b, c, d, a, in[10]+0xbebfbc70, 23);
|
||||
MD5STEP(F3, a, b, c, d, in[13]+0x289b7ec6, 4);
|
||||
MD5STEP(F3, d, a, b, c, in[ 0]+0xeaa127fa, 11);
|
||||
MD5STEP(F3, c, d, a, b, in[ 3]+0xd4ef3085, 16);
|
||||
MD5STEP(F3, b, c, d, a, in[ 6]+0x04881d05, 23);
|
||||
MD5STEP(F3, a, b, c, d, in[ 9]+0xd9d4d039, 4);
|
||||
MD5STEP(F3, d, a, b, c, in[12]+0xe6db99e5, 11);
|
||||
MD5STEP(F3, c, d, a, b, in[15]+0x1fa27cf8, 16);
|
||||
MD5STEP(F3, b, c, d, a, in[ 2]+0xc4ac5665, 23);
|
||||
|
||||
MD5STEP(F4, a, b, c, d, in[ 0]+0xf4292244, 6);
|
||||
MD5STEP(F4, d, a, b, c, in[ 7]+0x432aff97, 10);
|
||||
MD5STEP(F4, c, d, a, b, in[14]+0xab9423a7, 15);
|
||||
MD5STEP(F4, b, c, d, a, in[ 5]+0xfc93a039, 21);
|
||||
MD5STEP(F4, a, b, c, d, in[12]+0x655b59c3, 6);
|
||||
MD5STEP(F4, d, a, b, c, in[ 3]+0x8f0ccc92, 10);
|
||||
MD5STEP(F4, c, d, a, b, in[10]+0xffeff47d, 15);
|
||||
MD5STEP(F4, b, c, d, a, in[ 1]+0x85845dd1, 21);
|
||||
MD5STEP(F4, a, b, c, d, in[ 8]+0x6fa87e4f, 6);
|
||||
MD5STEP(F4, d, a, b, c, in[15]+0xfe2ce6e0, 10);
|
||||
MD5STEP(F4, c, d, a, b, in[ 6]+0xa3014314, 15);
|
||||
MD5STEP(F4, b, c, d, a, in[13]+0x4e0811a1, 21);
|
||||
MD5STEP(F4, a, b, c, d, in[ 4]+0xf7537e82, 6);
|
||||
MD5STEP(F4, d, a, b, c, in[11]+0xbd3af235, 10);
|
||||
MD5STEP(F4, c, d, a, b, in[ 2]+0x2ad7d2bb, 15);
|
||||
MD5STEP(F4, b, c, d, a, in[ 9]+0xeb86d391, 21);
|
||||
|
||||
buf[0] += a;
|
||||
buf[1] += b;
|
||||
buf[2] += c;
|
||||
buf[3] += d;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef TEST
|
||||
/* Simple test program. Can use it to manually run the tests from
|
||||
RFC1321 for example. */
|
||||
#include <stdio.h>
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
struct MD5Context context;
|
||||
unsigned char checksum[16];
|
||||
int i;
|
||||
int j;
|
||||
|
||||
if (argc < 2)
|
||||
{
|
||||
fprintf (stderr, "usage: %s string-to-hash\n", argv[0]);
|
||||
exit (1);
|
||||
}
|
||||
for (j = 1; j < argc; ++j)
|
||||
{
|
||||
printf ("MD5 (\"%s\") = ", argv[j]);
|
||||
MD5Init (&context);
|
||||
MD5Update (&context, argv[j], strlen (argv[j]));
|
||||
MD5Final (checksum, &context);
|
||||
for (i = 0; i < 16; i++)
|
||||
{
|
||||
printf ("%02x", (unsigned int) checksum[i]);
|
||||
}
|
||||
printf ("\n");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif /* TEST */
|
||||
41
lib/md5/md5.h
Normal file
41
lib/md5/md5.h
Normal file
@@ -0,0 +1,41 @@
|
||||
/* See md5.c for explanation and copyright information. */
|
||||
|
||||
#ifndef MD5_H
|
||||
#define MD5_H
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Unlike previous versions of this code, uint32 need not be exactly
|
||||
32 bits, merely 32 bits or more. Choosing a data type which is 32
|
||||
bits instead of 64 is not important; speed is considerably more
|
||||
important. ANSI guarantees that "unsigned long" will be big enough,
|
||||
and always using it seems to have few disadvantages. */
|
||||
typedef unsigned long uint32;
|
||||
|
||||
struct MD5Context {
|
||||
uint32 buf[4];
|
||||
uint32 bits[2];
|
||||
unsigned char in[64];
|
||||
};
|
||||
#ifndef PROTO
|
||||
#if defined (USE_PROTOTYPES) ? USE_PROTOTYPES : defined (__STDC__)
|
||||
#define PROTO(ARGS) ARGS
|
||||
#else
|
||||
#define PROTO(ARGS) ()
|
||||
#endif
|
||||
#endif
|
||||
|
||||
void MD5Init PROTO((struct MD5Context *context));
|
||||
void MD5Update PROTO((struct MD5Context *context, unsigned char const *buf, unsigned len));
|
||||
void MD5Final PROTO((unsigned char digest[16], struct MD5Context *context));
|
||||
void MD5Transform PROTO((uint32 buf[4], const unsigned char in[64]));
|
||||
|
||||
/*
|
||||
* This is needed to make RSAREF happy on some MS-DOS compilers.
|
||||
*/
|
||||
typedef struct MD5Context MD5_CTX;
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif /* !MD5_H */
|
||||
2
main.cpp
2
main.cpp
@@ -66,7 +66,7 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
|
||||
FindStorage();
|
||||
user_io_init((argc > 1) ? argv[1] : "");
|
||||
user_io_init((argc > 1) ? argv[1] : "",(argc > 2) ? argv[2] : "");
|
||||
|
||||
#ifdef USE_SCHEDULER
|
||||
scheduler_init();
|
||||
|
||||
149
menu.cpp
149
menu.cpp
@@ -313,7 +313,7 @@ static void SelectFile(const char* pFileExt, unsigned char Options, unsigned cha
|
||||
strcat(SelectedPath, "/");
|
||||
strcat(SelectedPath, get_rbf_name());
|
||||
}
|
||||
pFileExt = "RBF";
|
||||
pFileExt = "RBFMRA";
|
||||
}
|
||||
else if (Options & SCANO_TXT)
|
||||
{
|
||||
@@ -4481,9 +4481,21 @@ void HandleUI(void)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// close OSD now as the new core may not even have one
|
||||
fpga_load_rbf(SelectedRBF);
|
||||
if (!strcasecmp(".mra",&(SelectedRBF[strlen(SelectedRBF) - 4])))
|
||||
{
|
||||
char rbfname[4096];
|
||||
char rbfpath[4096];
|
||||
fprintf(stderr,"MRA FILE LOADED - write code\n");
|
||||
// find the RBF file from the XML
|
||||
arcade_scan_xml_for_rbf(getFullPath(SelectedRBF),rbfname);
|
||||
fprintf(stderr,"MRA SelectedRBF: [%s]\n",SelectedRBF);
|
||||
fprintf(stderr,"MRA rbf: [%s]\n",rbfname);
|
||||
sprintf(rbfpath,"arcade/%s",rbfname);
|
||||
fpga_load_rbf(getFullPath(rbfpath),NULL,SelectedRBF);
|
||||
}
|
||||
else
|
||||
// close OSD now as the new core may not even have one
|
||||
fpga_load_rbf(SelectedRBF);
|
||||
break;
|
||||
|
||||
case MENU_CORE_FILE_SELECTED2:
|
||||
@@ -4597,6 +4609,84 @@ void open_joystick_setup()
|
||||
joymap_first = 1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* CalculateFileNameLengthWithoutExtension
|
||||
*
|
||||
* This function takes a filename and length, and returns
|
||||
* the length. It will remove the .rbf or .mra from the length
|
||||
* based on the fs_pFileExt global
|
||||
*
|
||||
* If the fs_pFileExt has multiple extensions, it will look through
|
||||
* each to try to find a match.
|
||||
*/
|
||||
int CalculateFileNameLengthWithoutExtension(char *name,char *possibleextensions)
|
||||
{
|
||||
|
||||
char *ext = possibleextensions;
|
||||
int found=0;
|
||||
/* the default length is the whole string */
|
||||
int len = strlen(name);
|
||||
/* find the extension on the end of the name*/
|
||||
char *fext = strrchr(name, '.');
|
||||
/* we want to push past the period - and just have rbf instead of .rbf*/
|
||||
if (fext) fext++;
|
||||
|
||||
/* walk through each extension and see if it matches */
|
||||
while (!found && *ext && fext)
|
||||
{
|
||||
char e[4];
|
||||
memcpy(e, ext, 3);
|
||||
if (e[2] == ' ')
|
||||
{
|
||||
e[2] = 0;
|
||||
if (e[1] == ' ') e[1] = 0;
|
||||
}
|
||||
|
||||
e[3] = 0;
|
||||
found = 1;
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
if (e[i] == '*') break;
|
||||
if (e[i] == '?' && fext[i]) continue;
|
||||
|
||||
if (tolower(e[i]) != tolower(fext[i])) found = 0;
|
||||
|
||||
if (!e[i] || !found) break;
|
||||
}
|
||||
if (found) break;
|
||||
|
||||
if (strlen(ext) < 3) break;
|
||||
ext += 3;
|
||||
}
|
||||
|
||||
/* if we haven't found a match, then the answer is the full length of the string */
|
||||
if (!found) return len;
|
||||
|
||||
/* we have a match, now we need to handle extensions that are less than 3 characters */
|
||||
char e[5];
|
||||
memcpy(e + 1, ext, 3);
|
||||
/* 0x20 is a space in ascii*/
|
||||
if (e[3] == 0x20)
|
||||
{
|
||||
e[3] = 0;
|
||||
if (e[2] == 0x20)
|
||||
{
|
||||
e[2] = 0;
|
||||
}
|
||||
}
|
||||
e[0] = '.';
|
||||
e[4] = 0;
|
||||
int l = strlen(e);
|
||||
|
||||
if ((len>l) && !strncasecmp(name + len - l, e, l)) len -= l;
|
||||
|
||||
//printf("len: %d l: %d str[%s] e[%s] ext[%s]\n",len,l,name,e,ext);
|
||||
return len;
|
||||
|
||||
}
|
||||
|
||||
|
||||
void ScrollLongName(void)
|
||||
{
|
||||
// this function is called periodically when file selection window is displayed
|
||||
@@ -4608,32 +4698,28 @@ void ScrollLongName(void)
|
||||
len = strlen(flist_SelectedItem()->altname); // get name length
|
||||
if (flist_SelectedItem()->de.d_type == DT_REG) // if a file
|
||||
{
|
||||
if (fs_ExtLen <= 3)
|
||||
{
|
||||
char e[5];
|
||||
memcpy(e + 1, fs_pFileExt, 3);
|
||||
if (e[3] == 0x20)
|
||||
{
|
||||
e[3] = 0;
|
||||
if (e[2] == 0x20)
|
||||
{
|
||||
e[2] = 0;
|
||||
}
|
||||
}
|
||||
e[0] = '.';
|
||||
e[4] = 0;
|
||||
int l = strlen(e);
|
||||
if ((len>l) && !strncasecmp(flist_SelectedItem()->altname + len - l, e, l)) len -= l;
|
||||
}
|
||||
len=CalculateFileNameLengthWithoutExtension(flist_SelectedItem()->altname,fs_pFileExt);
|
||||
}
|
||||
|
||||
|
||||
max_len = 30; // number of file name characters to display (one more required for scrolling)
|
||||
if (flist_SelectedItem()->de.d_type == DT_DIR)
|
||||
max_len = 25; // number of directory name characters to display
|
||||
|
||||
// if we are in a core, we might need to resize for the fixed date string at the end
|
||||
if (!cfg.rbf_hide_datecode && (fs_Options & SCANO_CORES)) {
|
||||
if (len > 9 && !strncmp(flist_SelectedItem()->altname+ len - 9, "_20", 3)) {
|
||||
len -= 9;
|
||||
}
|
||||
max_len=21; // __.__.__ remove that from the end
|
||||
}
|
||||
|
||||
//printf("ScrollLongName: len %d max_len %d [%s]\n",len,max_len,flist_SelectedItem()->altname);
|
||||
ScrollText(flist_iSelectedEntry()-flist_iFirstEntry(), flist_SelectedItem()->altname, 0, len, max_len, 1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void PrintFileName(char *name, int row, int maxinv)
|
||||
{
|
||||
int len;
|
||||
@@ -4705,26 +4791,7 @@ void PrintDirectory(void)
|
||||
|
||||
if (!(flist_DirItem(k)->de.d_type == DT_DIR)) // if a file
|
||||
{
|
||||
if (fs_ExtLen <= 3)
|
||||
{
|
||||
char e[5];
|
||||
memcpy(e + 1, fs_pFileExt, 3);
|
||||
if (e[3] == 0x20)
|
||||
{
|
||||
e[3] = 0;
|
||||
if (e[2] == 0x20)
|
||||
{
|
||||
e[2] = 0;
|
||||
}
|
||||
}
|
||||
e[0] = '.';
|
||||
e[4] = 0;
|
||||
int l = strlen(e);
|
||||
if ((len>l) && !strncasecmp(flist_DirItem(k)->altname + len - l, e, l))
|
||||
{
|
||||
len -= l;
|
||||
}
|
||||
}
|
||||
len=CalculateFileNameLengthWithoutExtension(flist_DirItem(k)->altname,fs_pFileExt);
|
||||
}
|
||||
|
||||
char *p = 0;
|
||||
|
||||
@@ -23,5 +23,8 @@
|
||||
// NeoGeo support
|
||||
#include "support/neogeo/loader.h"
|
||||
|
||||
// Arcade support
|
||||
#include "support/arcade/romutils.h"
|
||||
|
||||
// MEGACD support
|
||||
#include "support/megacd/megacd.h"
|
||||
#include "support/megacd/megacd.h"
|
||||
|
||||
195
support/arcade/buffer.cpp
Normal file
195
support/arcade/buffer.cpp
Normal file
@@ -0,0 +1,195 @@
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stddef.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "buffer.h"
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Function buffer_init
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// This function will return a struct with the values it needs before it
|
||||
// can be used with buffer_append. The default "expand_length" is
|
||||
//
|
||||
// Parameters:
|
||||
//
|
||||
// initial_size (IN) This parameter will preallocate the buffer with this
|
||||
// size in bytes.
|
||||
//
|
||||
// Returns:
|
||||
//
|
||||
// returns a struct, or NULL on error
|
||||
//
|
||||
// Error Definitions:
|
||||
//
|
||||
// NULL = Couldn't create the structure
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
buffer_data * buffer_init(unsigned int initial_size) {
|
||||
|
||||
buffer_data * buffer = NULL;
|
||||
|
||||
// only allow max initial size of SIZE_MAX
|
||||
if (initial_size > 65535) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// malloc the space for a pointer to a buffer_data
|
||||
buffer = (buffer_data *)malloc(sizeof(buffer_data));
|
||||
if (buffer == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// fill the struct up
|
||||
buffer->expand_length = initial_size;
|
||||
buffer->capacity = initial_size;
|
||||
buffer->length = 0;
|
||||
|
||||
// allocate the buffer space
|
||||
buffer->content = (char *)malloc(sizeof(char) * initial_size);
|
||||
buffer->content[0]=0;
|
||||
if (buffer->content == NULL) {
|
||||
// can't allocate the buffer, therefore we need to clean everything up
|
||||
free(buffer);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// return a pointer to our buffer_data structure
|
||||
return buffer;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Function buffer_append
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// This function will take data and append it into a buffer in the struct
|
||||
// given. It will growing as required (or as allowed by realloc) by the
|
||||
// length desired in the structure element "expand_length" plus the length
|
||||
// of the data being appended. If additional expansion is not desired, you
|
||||
// can set the struct element "expand_length" to zero.
|
||||
//
|
||||
// Parameters:
|
||||
//
|
||||
// buffer_data (IN/OUT) This parameter is a struct (mapped below) to
|
||||
// keep track of the internal buffer and its working parameters.
|
||||
//
|
||||
// typedef struct {
|
||||
// unsigned int length; // the current length of the content in bytes
|
||||
// unsigned int capacity; // the total capacity of "content" in bytes
|
||||
// unsigned int expand_length; // the amount to expand the buffer on resize
|
||||
// char * content; // the target for appending data
|
||||
// } buffer_data;
|
||||
//
|
||||
//
|
||||
// append_data (IN) This parameter is a const char * that is the data
|
||||
// to be appended.
|
||||
//
|
||||
// Returns:
|
||||
//
|
||||
// This function will return the amount of bytes appended. If the
|
||||
// return value is <= 0 there was an error.
|
||||
//
|
||||
// Error Definitions:
|
||||
//
|
||||
// -1 = No data was given to append
|
||||
// -2 = Additional space could not be allocated for the buffer.
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int buffer_append(buffer_data * buffer, const char * append_data) {
|
||||
|
||||
// ensure there IS something to append..
|
||||
const unsigned int append_len = strlen(append_data);
|
||||
if (append_len < 1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// is there enough space, or should we reallocate memory?
|
||||
if (buffer->length + append_len > buffer->capacity) {
|
||||
|
||||
const unsigned int realloc_size =
|
||||
buffer->capacity + append_len + buffer->expand_length;
|
||||
|
||||
// allocate the new buffer
|
||||
char *new_buffer = (char *)realloc(buffer->content, realloc_size);
|
||||
|
||||
// resize success..
|
||||
if (new_buffer == NULL) {
|
||||
return -2;
|
||||
}
|
||||
|
||||
// copy the data to append into the new content buffer
|
||||
strcat(new_buffer, append_data);
|
||||
|
||||
// update the struct with the new values
|
||||
buffer->content = new_buffer; // new buffer content
|
||||
buffer->capacity = realloc_size; // add the amount to expand beyond our initial needs
|
||||
buffer->length = buffer->length + append_len;
|
||||
|
||||
} else {
|
||||
// append the string
|
||||
strcat(buffer->content, append_data);
|
||||
}
|
||||
|
||||
// update the buffer length
|
||||
buffer->length += append_len;
|
||||
|
||||
// return the amount appended
|
||||
return append_len;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Function buffer_destroy
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// This function will destroy the inner buffer and reset all of the data
|
||||
// if the struct was dynamically allocated, it is expected that you will
|
||||
// take care of freeing the data.
|
||||
//
|
||||
// Parameters:
|
||||
//
|
||||
// buffer_data (IN) This parameter is a struct (mapped below) to
|
||||
// keep track of the internal buffer and its working parameters.
|
||||
//
|
||||
// typedef struct {
|
||||
// unsigned int length; // the current length of the content in bytes
|
||||
// unsigned int capacity; // the total capacity of "content" in bytes
|
||||
// unsigned int expand_length; // the amount to expand the buffer on resize
|
||||
// char * content; // the target for appending data
|
||||
// } buffer_data;
|
||||
//
|
||||
// Returns:
|
||||
//
|
||||
// returns nothing
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void buffer_destroy(buffer_data * buffer) {
|
||||
|
||||
// only work with valid data..
|
||||
if (buffer != NULL) {
|
||||
|
||||
// if the content is not null, free it.
|
||||
if (buffer->content != NULL) {
|
||||
free(buffer->content);
|
||||
}
|
||||
|
||||
// free the buffer
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
}
|
||||
15
support/arcade/buffer.h
Normal file
15
support/arcade/buffer.h
Normal file
@@ -0,0 +1,15 @@
|
||||
#ifndef STRING_UTILS_H_
|
||||
#define STRING_UTILS_H_
|
||||
|
||||
typedef struct {
|
||||
unsigned int length;
|
||||
unsigned int capacity;
|
||||
unsigned int expand_length;
|
||||
char * content;
|
||||
} buffer_data;
|
||||
|
||||
buffer_data * buffer_init(const unsigned int initial_size);
|
||||
int buffer_append(buffer_data *buffer, const char *append_data);
|
||||
void buffer_destroy(buffer_data * buffer);
|
||||
|
||||
#endif // STRING_UTILS_H_
|
||||
470
support/arcade/romutils.cpp
Normal file
470
support/arcade/romutils.cpp
Normal file
@@ -0,0 +1,470 @@
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/stat.h>
|
||||
#include <dirent.h>
|
||||
|
||||
|
||||
#include "sxmlc.h"
|
||||
|
||||
#include "../../user_io.h"
|
||||
#include "../../file_io.h"
|
||||
#include "../../menu.h"
|
||||
|
||||
#include "buffer.h"
|
||||
|
||||
|
||||
#include "md5.h"
|
||||
/*
|
||||
* adapted from https://gist.github.com/xsleonard/7341172
|
||||
*
|
||||
* hexstr_to_char will take hex strings in two types:
|
||||
*
|
||||
* 00 01 02
|
||||
* 000102
|
||||
* 00 01 2 03
|
||||
* 0001 0203
|
||||
*
|
||||
* and return an array and a length of binary values
|
||||
*
|
||||
* caller must free string that is returned
|
||||
*
|
||||
* */
|
||||
unsigned char* hexstr_to_char(const char* hexstr, size_t *out_len)
|
||||
{
|
||||
size_t len = strlen(hexstr);
|
||||
unsigned char* chrs = (unsigned char*)malloc((len+1) * sizeof(*chrs));
|
||||
int dest=0;
|
||||
// point to the beginning of the array
|
||||
const char *ptr = hexstr;
|
||||
while (*ptr) {
|
||||
// check to see if we have a space
|
||||
while (*ptr=='\n' || *ptr=='\r' || *ptr==' ' || *ptr=='\t' || *ptr==9 /*horiz tab*/) ptr++;
|
||||
if (*ptr==0) break;
|
||||
|
||||
// pull two characters off
|
||||
int val1= (*ptr % 32 + 9) % 25 * 16;
|
||||
ptr++;
|
||||
/* check to odd numbers of characters*/
|
||||
if (*ptr==0) {
|
||||
int val= (ptr[-1] % 32 + 9) % 25;
|
||||
chrs[dest++] = val;
|
||||
break;
|
||||
}
|
||||
int val2= (*ptr % 32 + 9) % 25;
|
||||
ptr++;
|
||||
chrs[dest++] = val1+val2;
|
||||
}
|
||||
chrs[dest]=0;
|
||||
*out_len = dest; /* dest is 0 based, so we don't need to subtract 1*/
|
||||
return chrs;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
user_io.h:int user_io_file_tx_start(const char *name,unsigned char index=0);
|
||||
user_io.h:int user_io_file_tx_body(const uint8_t *buf,uint16_t chunk);
|
||||
user_io.h:int user_io_file_tx_body_filepart(const char *name,int start=0, int len=0);
|
||||
user_io.h:int user_io_file_tx_finish();
|
||||
*/
|
||||
|
||||
|
||||
#define kBigTextSize 4096
|
||||
struct arc_struct {
|
||||
char md5[kBigTextSize];
|
||||
char zipname[kBigTextSize];
|
||||
char partzipname[kBigTextSize];
|
||||
char partname[kBigTextSize];
|
||||
char romname[kBigTextSize];
|
||||
char error_msg[kBigTextSize];
|
||||
int romindex;
|
||||
int offset;
|
||||
int length;
|
||||
int repeat;
|
||||
int insiderom;
|
||||
int validrom0;
|
||||
buffer_data *data;
|
||||
struct MD5Context context;
|
||||
};
|
||||
|
||||
char global_error_msg[kBigTextSize];
|
||||
|
||||
|
||||
/*
|
||||
* xml_send_rom
|
||||
*
|
||||
* This is a callback from the XML parser of the MRA file
|
||||
*
|
||||
* It parses the MRA, and sends commands to send rom parts to the fpga
|
||||
* */
|
||||
static int xml_send_rom(XMLEvent evt, const XMLNode* node, SXML_CHAR* text, const int n, SAX_Data* sd)
|
||||
{
|
||||
struct arc_struct *arc_info = (struct arc_struct *)sd->user;
|
||||
(void)(sd);
|
||||
|
||||
switch (evt)
|
||||
{
|
||||
case XML_EVENT_START_NODE:
|
||||
|
||||
/* initialization */
|
||||
|
||||
|
||||
// initialize things for each tag (node):
|
||||
buffer_destroy(arc_info->data);
|
||||
arc_info->data=buffer_init(kBigTextSize);
|
||||
arc_info->partname[0]=0;
|
||||
arc_info->offset=0;
|
||||
arc_info->length=-1;
|
||||
arc_info->repeat=1;
|
||||
|
||||
/* on the beginning of a rom tag, we need to reset the state*/
|
||||
if (!strcasecmp(node->tag,"rom"))
|
||||
{
|
||||
arc_info->insiderom=1;
|
||||
arc_info->romname[0]=0;
|
||||
arc_info->romindex=0;
|
||||
arc_info->md5[0]=0;
|
||||
MD5Init (&arc_info->context);
|
||||
}
|
||||
|
||||
// for each part tag, we clear the partzipname since it is optional and may not appear in the part tag
|
||||
if (!strcasecmp(node->tag,"part"))
|
||||
arc_info->partzipname[0]=0;
|
||||
|
||||
|
||||
//printf("XML_EVENT_START_NODE: tag [%s]\n",node->tag);
|
||||
// walk the attributes and save them in the data structure as appropriate
|
||||
for (int i = 0; i < node->n_attributes; i++)
|
||||
{
|
||||
//printf("attribute %d name [%s] value [%s]\n",i,node->attributes[i].name,node->attributes[i].value);
|
||||
if (!strcasecmp(node->attributes[i].name,"zip") && !strcasecmp(node->tag,"rom"))
|
||||
{
|
||||
strcpy(arc_info->zipname,node->attributes[i].value);
|
||||
}
|
||||
if (!strcasecmp(node->attributes[i].name,"name") && !strcasecmp(node->tag,"rom"))
|
||||
{
|
||||
strcpy(arc_info->romname,node->attributes[i].value);
|
||||
}
|
||||
if (!strcasecmp(node->attributes[i].name,"md5") && !strcasecmp(node->tag,"rom"))
|
||||
{
|
||||
strcpy(arc_info->md5,node->attributes[i].value);
|
||||
}
|
||||
if (!strcasecmp(node->attributes[i].name,"index") && !strcasecmp(node->tag,"rom"))
|
||||
{
|
||||
arc_info->romindex=atoi(node->attributes[i].value);
|
||||
}
|
||||
/* these only exist if we are inside the rom tag, and in a part tag*/
|
||||
if (arc_info->insiderom) {
|
||||
if (!strcasecmp(node->attributes[i].name,"zip") && !strcasecmp(node->tag,"part"))
|
||||
{
|
||||
strcpy(arc_info->partzipname,node->attributes[i].value);
|
||||
}
|
||||
if (!strcasecmp(node->attributes[i].name,"name") && !strcasecmp(node->tag,"part"))
|
||||
{
|
||||
strcpy(arc_info->partname,node->attributes[i].value);
|
||||
}
|
||||
if (!strcasecmp(node->attributes[i].name,"offset") && !strcasecmp(node->tag,"part"))
|
||||
{
|
||||
arc_info->offset=atoi(node->attributes[i].value);
|
||||
}
|
||||
if (!strcasecmp(node->attributes[i].name,"length") && !strcasecmp(node->tag,"part"))
|
||||
{
|
||||
arc_info->length=atoi(node->attributes[i].value);
|
||||
}
|
||||
if (!strcasecmp(node->attributes[i].name,"repeat") && !strcasecmp(node->tag,"part"))
|
||||
{
|
||||
arc_info->repeat=atoi(node->attributes[i].value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* at the beginning of each rom - tell the user_io to start a new message */
|
||||
if (!strcasecmp(node->tag,"rom"))
|
||||
{
|
||||
|
||||
// clear an error message if we have a second rom0
|
||||
// this is kind of a problem - you will never see the
|
||||
// error from the first rom0?
|
||||
//
|
||||
if (arc_info->romindex==0 && strlen(arc_info->zipname))
|
||||
arc_info->error_msg[0]=0;
|
||||
|
||||
user_io_file_tx_start(arc_info->romname,arc_info->romindex);
|
||||
}
|
||||
break;
|
||||
|
||||
case XML_EVENT_TEXT:
|
||||
/* the text node is the data between tags, ie: <part>this text</part>
|
||||
*
|
||||
* the buffer_append is part of a buffer library that will realloc automatically
|
||||
*/
|
||||
buffer_append(arc_info->data, text);
|
||||
//printf("XML_EVENT_TEXT: text [%s]\n",text);
|
||||
break;
|
||||
case XML_EVENT_END_NODE:
|
||||
//printf("XML_EVENT_END_NODE: tag [%s]\n",node->tag );
|
||||
|
||||
// At the end of a rom node (when it is closed) we need to calculate hash values and clean up
|
||||
if (!strcasecmp(node->tag,"rom")) {
|
||||
if (arc_info->insiderom)
|
||||
{
|
||||
unsigned char checksum[16];
|
||||
int checksumsame=1;
|
||||
char *md5=arc_info->md5;
|
||||
user_io_file_tx_finish();
|
||||
MD5Final (checksum, &arc_info->context);
|
||||
printf("md5[%s]\n",arc_info->md5);
|
||||
printf("md5-calc[");
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
char hex[10];
|
||||
snprintf(hex,10,"%02x", (unsigned int) checksum[i]);
|
||||
printf ("%02x", (unsigned int) checksum[i]);
|
||||
if (md5[0]!=hex[0] || md5[1]!=hex[1]) {
|
||||
checksumsame=0;
|
||||
}
|
||||
md5+=2;
|
||||
}
|
||||
printf ("]\n");
|
||||
if (checksumsame==0)
|
||||
{
|
||||
printf("mismatch\n");
|
||||
if (!strlen(arc_info->error_msg))
|
||||
snprintf(arc_info->error_msg,kBigTextSize,"md5 mismatch for rom %d",arc_info->romindex);
|
||||
}
|
||||
else
|
||||
{
|
||||
// this code sets the validerom0 and clears the message
|
||||
// if a rom with index 0 has a correct md5. It supresses
|
||||
// sending any further rom0 messages
|
||||
if (arc_info->romindex==0)
|
||||
{
|
||||
arc_info->validrom0=1;
|
||||
arc_info->error_msg[0]=0;
|
||||
}
|
||||
}
|
||||
}
|
||||
arc_info->insiderom=0;
|
||||
}
|
||||
|
||||
// At the end of a part node, send the rom part if we are inside a rom tag
|
||||
//int user_io_file_tx_body_filepart(const char *name,int start, int len)
|
||||
if (!strcasecmp(node->tag,"part") && arc_info->insiderom)
|
||||
{
|
||||
// suppress rom0 if we already sent a valid one
|
||||
// this is useful for merged rom sets - if the first one was valid, use it
|
||||
// the second might not be
|
||||
if (arc_info->romindex==0 && arc_info->validrom0==1)
|
||||
break;
|
||||
char fname[kBigTextSize*2+16];
|
||||
int start,length,repeat;
|
||||
repeat=arc_info->repeat;
|
||||
start=arc_info->offset;
|
||||
length=0;
|
||||
if (arc_info->length>0) length = arc_info->length;
|
||||
//printf("partname[%s]\n",arc_info->partname);
|
||||
//printf("zipname [%s]\n",arc_info->zipname);
|
||||
//printf("offset[%d]\n",arc_info->offset);
|
||||
//printf("length[%d]\n",arc_info->length);
|
||||
//printf("repeat[%d]\n",arc_info->repeat);
|
||||
//
|
||||
if (strlen(arc_info->partzipname))
|
||||
{
|
||||
if (arc_info->partzipname[0]=='/')
|
||||
sprintf(fname,"arcade%s/%s",arc_info->partzipname,arc_info->partname);
|
||||
else
|
||||
sprintf(fname,"arcade/mame/%s/%s",arc_info->partzipname,arc_info->partname);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (arc_info->zipname[0]=='/')
|
||||
sprintf(fname,"arcade%s/%s",arc_info->zipname,arc_info->partname);
|
||||
else
|
||||
sprintf(fname,"arcade/mame/%s/%s",arc_info->zipname,arc_info->partname);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//user_io_file_tx_body_filepart(getFullPath(fname),0,0);
|
||||
if (strlen(arc_info->partname)) {
|
||||
printf("user_io_file_tx_body_filepart(const char *name[%s],int start[%d], int len[%d])\n",fname,start,length);
|
||||
for (int i=0;i<repeat;i++) {
|
||||
int result=user_io_file_tx_body_filepart(fname,start,length,&arc_info->context);
|
||||
// we should check file not found error for the zip
|
||||
if (result==0)
|
||||
{
|
||||
int skip=0;
|
||||
if (!strncasecmp(fname,"arcade/mame/",strlen("arcade/mame/")))
|
||||
skip=strlen("arcade/mame/");
|
||||
printf("%s does not exist\n",fname);
|
||||
snprintf(arc_info->error_msg,kBigTextSize,"%s\n"
|
||||
"\x81\x81\x81\x81\x81\x81\x81\x81\x81\x81\x81\x81\x81\x81\x81\x81\x81\x81\x81\x81\x81\x81\x81\x81\x81\x81\n"
|
||||
"File Not Found",fname+skip);
|
||||
}
|
||||
}
|
||||
}
|
||||
else // we have binary data?
|
||||
{
|
||||
//printf("we have bin.hex data [%s]\n",arc_info->data->content);
|
||||
size_t len=0;
|
||||
unsigned char* binary=hexstr_to_char(arc_info->data->content,&len);
|
||||
//printf("len %d:\n",len);
|
||||
//for (size_t i=0;i<len;i++) {
|
||||
// printf(" %d ",binary[i]);
|
||||
//}
|
||||
//printf("\n");
|
||||
for (int i=0;i<repeat;i++) {
|
||||
user_io_file_tx_body(binary,len,&arc_info->context);
|
||||
}
|
||||
if (binary) free(binary);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
case XML_EVENT_ERROR:
|
||||
printf("XML parse: %s: ERROR %d\n", text, n);
|
||||
snprintf(arc_info->error_msg,kBigTextSize,"XML parse: %s: ERROR %d\n", text, n);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
static int xml_scan_rbf(XMLEvent evt, const XMLNode* node, SXML_CHAR* text, const int n, SAX_Data* sd)
|
||||
{
|
||||
static int insiderbf=0;
|
||||
char bigtext[kBigTextSize];
|
||||
char *rbf = (char *)sd->user;
|
||||
|
||||
switch (evt)
|
||||
{
|
||||
case XML_EVENT_START_NODE:
|
||||
bigtext[0]=0;
|
||||
if (!strcasecmp(node->tag,"rbf")) {
|
||||
insiderbf=1;
|
||||
}
|
||||
printf("XML_EVENT_START_NODE: tag [%s]\n",node->tag);
|
||||
for (int i = 0; i < node->n_attributes; i++)
|
||||
{
|
||||
printf("attribute %d name [%s] value [%s]\n",i,node->attributes[i].name,node->attributes[i].value);
|
||||
}
|
||||
|
||||
break;
|
||||
case XML_EVENT_TEXT:
|
||||
if (insiderbf) {
|
||||
strncat(bigtext,text,kBigTextSize-strlen(bigtext)-1);
|
||||
printf("XML_EVENT_TEXT: text [%s]\n",text);
|
||||
}
|
||||
break;
|
||||
case XML_EVENT_END_NODE:
|
||||
if (!strcasecmp(node->tag,"rbf"))
|
||||
{
|
||||
insiderbf=0;
|
||||
//printf("bigtext [%s]\n",bigtext);
|
||||
strncpy(rbf,bigtext,kBigTextSize);
|
||||
//printf("got rbf tag [%s]\n",rbf);
|
||||
}
|
||||
printf("XML_EVENT_END_NODE: tag [%s]\n",node->tag );
|
||||
break;
|
||||
|
||||
case XML_EVENT_ERROR:
|
||||
printf("XML parse: %s: ERROR %d\n", text, n);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
int arcade_send_rom(const char *xml)
|
||||
{
|
||||
SAX_Callbacks sax;
|
||||
SAX_Callbacks_init(&sax);
|
||||
|
||||
sax.all_event = xml_send_rom;
|
||||
|
||||
// create the structure we use for the XML parser
|
||||
struct arc_struct arc_info;
|
||||
arc_info.data=buffer_init(kBigTextSize);
|
||||
arc_info.error_msg[0]=0;
|
||||
arc_info.validrom0=0;
|
||||
|
||||
// parse
|
||||
XMLDoc_parse_file_SAX(xml, &sax, &arc_info);
|
||||
if (arc_info.validrom0==0 && strlen(arc_info.error_msg))
|
||||
{
|
||||
strcpy(global_error_msg,arc_info.error_msg);
|
||||
printf("arcade_send_rom: pretty error: [%s]\n",global_error_msg);
|
||||
}
|
||||
buffer_destroy(arc_info.data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CheckArcadeError(void)
|
||||
{
|
||||
if (global_error_msg[0]!=0) {
|
||||
printf("ERROR: [%s]\n",global_error_msg);
|
||||
Info(global_error_msg,1000*30);
|
||||
global_error_msg[0]=0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int arcade_scan_xml_for_rbf(const char *xml,char *rbfname)
|
||||
{
|
||||
char rbfname_fragment[kBigTextSize];
|
||||
rbfname_fragment[0]=0;
|
||||
rbfname[0]=0;
|
||||
SAX_Callbacks sax;
|
||||
SAX_Callbacks_init(&sax);
|
||||
|
||||
sax.all_event = xml_scan_rbf;
|
||||
XMLDoc_parse_file_SAX(xml, &sax, rbfname_fragment);
|
||||
strcpy(rbfname,rbfname_fragment);
|
||||
|
||||
//printf("arcade_scan_xml_for_rbf [%s]\n",xml);
|
||||
/* once we have the rbfname fragment from the MRA xml file
|
||||
* search the arcade folder for the match */
|
||||
struct dirent *entry;
|
||||
DIR *dir=NULL;
|
||||
//printf("opendir(%s)\n",getFullPath("arcade"));
|
||||
if (!(dir = opendir(getFullPath("arcade"))))
|
||||
{
|
||||
printf("arcade directory not found\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
while ((entry = readdir(dir)) != NULL) {
|
||||
if (entry->d_type == DT_DIR) {
|
||||
}
|
||||
else {
|
||||
char newstring[kBigTextSize];
|
||||
//printf("entry name: %s\n",entry->d_name);
|
||||
snprintf(newstring,kBigTextSize,"Arcade-%s_",rbfname_fragment);
|
||||
if (!strncasecmp(newstring,entry->d_name,strlen(newstring))) {
|
||||
closedir(dir);
|
||||
strcpy(rbfname,entry->d_name);
|
||||
return 0;
|
||||
|
||||
}
|
||||
snprintf(newstring,kBigTextSize,"%s_",rbfname_fragment);
|
||||
if (!strncasecmp(newstring,entry->d_name,strlen(newstring))) {
|
||||
closedir(dir);
|
||||
strcpy(rbfname,entry->d_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (dir) closedir(dir);
|
||||
strcpy(rbfname,rbfname_fragment);
|
||||
return 0;
|
||||
}
|
||||
|
||||
5
support/arcade/romutils.h
Normal file
5
support/arcade/romutils.h
Normal file
@@ -0,0 +1,5 @@
|
||||
#include "../../file_io.h"
|
||||
|
||||
int arcade_send_rom(const char *xml);
|
||||
int arcade_scan_xml_for_rbf(const char *xml,char *rbfname);
|
||||
int CheckArcadeError(void);
|
||||
119
user_io.cpp
119
user_io.cpp
@@ -12,6 +12,8 @@
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include "lib/lodepng/lodepng.h"
|
||||
#include "md5.h"
|
||||
|
||||
#include "hardware.h"
|
||||
#include "osd.h"
|
||||
#include "user_io.h"
|
||||
@@ -691,16 +693,26 @@ int user_io_is_dualsdr()
|
||||
return dual_sdr;
|
||||
}
|
||||
|
||||
void user_io_init(const char *path)
|
||||
void user_io_init(const char *path, const char *xml)
|
||||
{
|
||||
char *name;
|
||||
static char mainpath[512];
|
||||
core_name[0] = 0;
|
||||
disable_osd = 0;
|
||||
|
||||
// we need to set the directory to where the XML file (MRA) is
|
||||
// not the RBF. The RBF will be in arcade, which the user shouldn't
|
||||
// browse
|
||||
if (strlen(xml)) {
|
||||
//printf("USER_IO_INIT got XML: [%s] [%s]\n",path,xml);
|
||||
strcpy(core_path, getFullPath(xml));
|
||||
} else {
|
||||
strcpy(core_path, path);
|
||||
}
|
||||
//printf("USER_IO_INIT core_path: [%s] \n",core_path);
|
||||
|
||||
memset(sd_image, 0, sizeof(sd_image));
|
||||
|
||||
strcpy(core_path, path);
|
||||
core_type = (fpga_core_id() & 0xFF);
|
||||
fio_size = fpga_get_fio_size();
|
||||
io_ver = fpga_get_io_version();
|
||||
@@ -857,6 +869,14 @@ void user_io_init(const char *path)
|
||||
if (user_io_use_cheats()) cheats_init("", user_io_get_file_crc());
|
||||
}
|
||||
|
||||
/* AJS -- NOT SURE THIS IS THE BEST PLACE */
|
||||
if (strlen(xml)) {
|
||||
//sprintf(mainpath, "%s/%s", user_io_get_core_path(), xml);
|
||||
printf("USER_IO_INIT got XML: [%s]\n",xml);
|
||||
//printf("USER_IO_INIT got XML: [%s]\n",mainpath);
|
||||
arcade_send_rom(getFullPath(xml));
|
||||
}
|
||||
|
||||
if (is_cpc_core())
|
||||
{
|
||||
for (int m = 0; m < 3; m++)
|
||||
@@ -1579,6 +1599,101 @@ static void check_status_change()
|
||||
}
|
||||
}
|
||||
|
||||
#define DEBUG_ROM_BINARY 0
|
||||
#if DEBUG_ROM_BINARY
|
||||
FILE *rombinary;
|
||||
#endif
|
||||
|
||||
int user_io_file_tx_start(const char *name,unsigned char index)
|
||||
{
|
||||
// set index byte (0=bios rom, 1-n=OSD entry index)
|
||||
user_io_set_index(index);
|
||||
|
||||
int len = strlen(name);
|
||||
const char *p = name + len - 4;
|
||||
EnableFpga();
|
||||
spi8(UIO_FILE_INFO);
|
||||
spi_w(toupper(p[0]) << 8 | toupper(p[1]));
|
||||
spi_w(toupper(p[2]) << 8 | toupper(p[3]));
|
||||
DisableFpga();
|
||||
|
||||
// prepare transmission of new file
|
||||
EnableFpga();
|
||||
spi8(UIO_FILE_TX);
|
||||
spi8(0xff);
|
||||
DisableFpga();
|
||||
|
||||
file_crc = 0;
|
||||
#if DEBUG_ROM_BINARY
|
||||
rombinary=fopen("/media/fat/this.rom","wb");
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
int user_io_file_tx_body(const uint8_t *buf,uint16_t chunk,struct MD5Context *md5context)
|
||||
{
|
||||
printf(".");
|
||||
|
||||
EnableFpga();
|
||||
spi8(UIO_FILE_TX_DAT);
|
||||
|
||||
spi_write(buf, chunk, fio_size);
|
||||
DisableFpga();
|
||||
|
||||
file_crc = crc32(file_crc, buf ,chunk );
|
||||
if (md5context) MD5Update (md5context, buf,chunk);
|
||||
#if DEBUG_ROM_BINARY
|
||||
fwrite(buf,1,chunk,rombinary);
|
||||
#endif
|
||||
|
||||
return 1;
|
||||
}
|
||||
int user_io_file_tx_body_filepart(const char *name,int start, int len,struct MD5Context *md5context)
|
||||
{
|
||||
char mute=0;
|
||||
fileTYPE f = {};
|
||||
static uint8_t buf[4096];
|
||||
if (!FileOpen(&f, name, mute)) return 0;
|
||||
if (start) FileSeek(&f, start, SEEK_SET);
|
||||
unsigned long bytes2send = f.size;
|
||||
if (len>0 && len < bytes2send) bytes2send=len;
|
||||
/* transmit the entire file using one transfer */
|
||||
printf("Selected file %s with %lu bytes to send \n", name, bytes2send);
|
||||
while (bytes2send)
|
||||
{
|
||||
printf(".");
|
||||
|
||||
uint16_t chunk = (bytes2send > sizeof(buf)) ? sizeof(buf) : bytes2send;
|
||||
|
||||
FileReadAdv(&f, buf, chunk);
|
||||
user_io_file_tx_body(buf,chunk,md5context);
|
||||
|
||||
|
||||
bytes2send -= chunk;
|
||||
}
|
||||
|
||||
|
||||
return 1;
|
||||
}
|
||||
int user_io_file_tx_finish()
|
||||
{
|
||||
// check if core requests some change while downloading
|
||||
check_status_change();
|
||||
|
||||
printf("\n");
|
||||
printf("CRC32: %08X\n", file_crc);
|
||||
#if DEBUG_ROM_BINARY
|
||||
fclose(rombinary);
|
||||
#endif
|
||||
|
||||
// signal end of transmission
|
||||
EnableFpga();
|
||||
spi8(UIO_FILE_TX);
|
||||
spi8(0x00);
|
||||
DisableFpga();
|
||||
printf("\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
static char pchar[] = { 0x8C, 0x8F, 0x7F };
|
||||
|
||||
#define PROGRESS_CNT 28
|
||||
|
||||
@@ -199,7 +199,7 @@ typedef struct {
|
||||
uint8_t fifo_stat; // space in cores input fifo
|
||||
} __attribute__((packed)) serial_status_t;
|
||||
|
||||
void user_io_init(const char *path);
|
||||
void user_io_init(const char *path, const char *xml);
|
||||
unsigned char user_io_core_type();
|
||||
void user_io_poll();
|
||||
char user_io_menu_button();
|
||||
@@ -210,6 +210,13 @@ void user_io_read_confstr();
|
||||
char *user_io_get_confstr(int index);
|
||||
uint32_t user_io_8bit_set_status(uint32_t, uint32_t, int ex = 0);
|
||||
int user_io_file_tx(const char* name, unsigned char index = 0, char opensave = 0, char mute = 0, char composite = 0);
|
||||
|
||||
int user_io_file_tx_start(const char *name,unsigned char index=0);
|
||||
int user_io_file_tx_body(const uint8_t *buf,uint16_t chunk,struct MD5Context *md5context=NULL);
|
||||
int user_io_file_tx_body_filepart(const char *name,int start=0, int len=0,struct MD5Context *md5context=NULL);
|
||||
int user_io_file_tx_finish();
|
||||
|
||||
|
||||
uint32_t user_io_get_file_crc();
|
||||
int user_io_file_mount(char *name, unsigned char index = 0, char pre = 0);
|
||||
char user_io_serial_status(serial_status_t *, uint8_t);
|
||||
|
||||
Reference in New Issue
Block a user