123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456 |
- /*
- mgd.c - Multi Game Doctor/Hunter support for uCON64
- Copyright (c) 1999 - 2001 NoisyB
- Copyright (c) 2001 - 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.
- */
- #include <stdlib.h>
- #include "misc/archive.h"
- #include "misc/file.h"
- #include "misc/string.h"
- #include "ucon64.h"
- #include "ucon64_misc.h"
- #include "backup/mgd.h"
- const st_getopt2_t mgd_usage[] =
- {
- {
- NULL, 0, 0, 0,
- NULL, "Multi Game Doctor (2)/Multi Game Hunter/MGH"
- /*"19XX Bung Enterprises Ltd http://www.bung.com.hk\n" "?Makko Toys Co., Ltd.?"*/,
- NULL
- },
- #if 0
- {
- "xmgd", 0, 0, UCON64_XMGD,
- NULL, "(TODO) send/receive ROM to/from Multi Game* /MGD2/MGH; " OPTION_LONG_S "port=PORT\n"
- "receives automatically when " OPTION_LONG_S "rom does not exist",
- NULL
- },
- #endif
- {NULL, 0, 0, 0, NULL, NULL, NULL}
- };
- // the following four functions are used by non-transfer code in genesis.c
- void
- mgd_interleave (unsigned char **buffer, int size)
- {
- int n;
- unsigned char *src = *buffer;
- if ((*buffer = (unsigned char *) malloc (size)) == NULL)
- {
- fprintf (stderr, ucon64_msg[BUFFER_ERROR], size);
- exit (1);
- }
- for (n = 0; n < size / 2; n++)
- {
- (*buffer)[n] = src[n * 2 + 1];
- (*buffer)[size / 2 + n] = src[n * 2];
- }
- free (src);
- }
- void
- mgd_deinterleave (unsigned char **buffer, int data_size, int buffer_size)
- {
- int n = 0, offset;
- unsigned char *src = *buffer;
- if ((*buffer = (unsigned char *) malloc (buffer_size)) == NULL)
- {
- fprintf (stderr, ucon64_msg[BUFFER_ERROR], buffer_size);
- exit (1);
- }
- for (offset = 0; offset < data_size / 2; offset++)
- {
- (*buffer)[n++] = src[data_size / 2 + offset];
- (*buffer)[n++] = src[offset];
- }
- free (src);
- }
- int
- fread_mgd (void *buffer, size_t size, size_t number, FILE *fh)
- /*
- This function is used to handle a Genesis MGD file as if it wasn't
- interleaved, without the overhead of reading the entire file into memory.
- This is important for genesis_init(). When the file turns out to be a Genesis
- dump in MGD format it is much more efficient for compressed files to read the
- entire file into memory and then deinterleave it (as load_rom() does).
- In order to speed this function up a bit ucon64.file_size is used. That means
- it can't be used for an arbitrary file.
- */
- {
- int n = 0, bpos = 0, fpos, fpos_org, block_size, bytesread = 0,
- len = number * size, fsize = ucon64.file_size /* fsizeof (filename) */;
- unsigned char tmp1[MAXBUFSIZE], tmp2[MAXBUFSIZE];
- fpos = fpos_org = ftell (fh);
- if (fpos >= fsize)
- return 0;
- if (len == 0)
- return 0;
- else if (len == 1)
- {
- if (fpos_org & 1)
- {
- fseek (fh, fpos / 2, SEEK_SET);
- *((unsigned char *) buffer) = (unsigned char) fgetc (fh);
- }
- else
- {
- fseek (fh, fpos / 2 + fsize / 2, SEEK_SET);
- *((unsigned char *) buffer) = (unsigned char) fgetc (fh);
- }
- fseek (fh, fpos_org + 1, SEEK_SET);
- return 1;
- }
- while (len > 0 && !feof (fh))
- {
- block_size = len > MAXBUFSIZE ? MAXBUFSIZE : len;
- fseek (fh, fpos / 2, SEEK_SET);
- bytesread += fread (tmp1, 1, block_size / 2, fh); // read odd bytes
- fseek (fh, (fpos + 1) / 2 + fsize / 2, SEEK_SET);
- bytesread += fread (tmp2, 1, block_size / 2, fh); // read even bytes
- if (fpos_org & 1)
- for (n = 0; n < block_size / 2; n++)
- {
- ((unsigned char *) buffer)[bpos + n * 2] = tmp1[n];
- ((unsigned char *) buffer)[bpos + n * 2 + 1] = tmp2[n];
- }
- else
- for (n = 0; n < block_size / 2; n++)
- {
- ((unsigned char *) buffer)[bpos + n * 2] = tmp2[n];
- ((unsigned char *) buffer)[bpos + n * 2 + 1] = tmp1[n];
- }
- fpos += block_size;
- bpos += block_size;
- len -= block_size;
- }
- fseek (fh, fpos_org + bytesread, SEEK_SET);
- return bytesread / size;
- }
- int
- q_fread_mgd (void *buffer, size_t start, size_t len, const char *filename)
- {
- int result;
- FILE *fh;
- if ((fh = fopen (filename, "rb")) == NULL)
- return -1;
- fseek (fh, start, SEEK_SET);
- result = (int) fread_mgd (buffer, 1, len, fh);
- fclose (fh);
- return result;
- }
- static void
- remove_mgd_id (char *name, const char *id)
- {
- char *p = name;
- while ((p = strstr (p, id)) != NULL)
- {
- *p = 'X';
- *(p + 1) = 'X';
- p += 2;
- }
- }
- void
- mgd_make_name (const char *filename, int console, int size, char *name)
- // these characters are also valid in MGD file names: !@#$%^&_
- {
- char *prefix = 0, *p, *size_str = 0, *suffix = 0;
- const char *fname;
- int n;
- switch (console)
- {
- default: // falling through
- case UCON64_SNES:
- prefix = "SF";
- suffix = ".048";
- if (size <= 1 * MBIT)
- size_str = "1";
- else if (size <= 2 * MBIT)
- size_str = "2";
- else if (size <= 4 * MBIT)
- size_str = "4";
- else if (size <= 8 * MBIT)
- {
- size_str = "8";
- suffix = ".058";
- }
- else
- {
- suffix = ".078";
- if (size <= 10 * MBIT)
- size_str = "10";
- else if (size <= 12 * MBIT)
- size_str = "12";
- else if (size <= 16 * MBIT)
- size_str = "16";
- else if (size <= 20 * MBIT)
- size_str = "20";
- else if (size <= 24 * MBIT)
- size_str = "24";
- else // MGD supports SNES games with sizes up to 32 Mbit
- size_str = "32";
- }
- break;
- case UCON64_GEN:
- prefix = "MD";
- suffix = ".000";
- if (size <= 1 * MBIT)
- size_str = "1";
- else if (size <= 2 * MBIT)
- size_str = "2";
- else if (size <= 4 * MBIT)
- size_str = "4";
- else
- {
- if (size <= 8 * MBIT)
- {
- size_str = "8";
- suffix = ".008";
- }
- else if (size <= 16 * MBIT)
- {
- size_str = "16";
- suffix = ".018";
- }
- else
- {
- suffix = ".038";
- if (size <= 20 * MBIT)
- size_str = "20";
- else if (size <= 24 * MBIT)
- size_str = "24";
- else // MGD supports Genesis games with sizes up to 32 Mbit
- size_str = "32";
- }
- }
- break;
- case UCON64_PCE:
- prefix = "PC";
- suffix = ".040";
- if (size <= 1 * MBIT)
- size_str = "1";
- else if (size <= 2 * MBIT)
- size_str = "2";
- else if (size <= 3 * MBIT)
- {
- size_str = "3";
- suffix = ".030";
- }
- else if (size <= 4 * MBIT)
- {
- size_str = "4";
- suffix = ".048";
- }
- else
- {
- suffix = ".058";
- if (size <= 6 * MBIT)
- size_str = "6";
- else // MGD supports PC-Engine games with sizes up to 8 Mbit
- size_str = "8";
- }
- break;
- case UCON64_SMS:
- prefix = "GG";
- suffix = ".060";
- if (size < 1 * MBIT)
- size_str = "0";
- else if (size == 1 * MBIT)
- size_str = "1";
- else if (size <= 2 * MBIT)
- size_str = "2";
- else
- {
- suffix = ".078";
- if (size <= 3 * MBIT)
- size_str = "3";
- else if (size <= 4 * MBIT)
- size_str = "4";
- else if (size <= 6 * MBIT)
- size_str = "6";
- else // MGD supports Sega Master System games with sizes up to 8 Mbit
- size_str = "8";
- }
- break;
- case UCON64_GAMEGEAR:
- prefix = "GG";
- suffix = ".040";
- if (size < 1 * MBIT)
- size_str = "0";
- else if (size == 1 * MBIT)
- size_str = "1";
- else if (size <= 2 * MBIT)
- size_str = "2";
- else
- {
- suffix = ".048";
- if (size <= 3 * MBIT)
- size_str = "3";
- else if (size <= 4 * MBIT)
- size_str = "4";
- else
- {
- suffix = ".078";
- if (size <= 6 * MBIT)
- size_str = "6";
- else // MGD supports Game Gear games with sizes up to 8 Mbit
- size_str = "8";
- }
- }
- break;
- case UCON64_GB:
- prefix = "GB";
- /*
- What is the maximum game size the MGD2 supports for GB (color) games?
- At least one 64 Mbit game exists, Densha De Go! 2 (J) [C][!].
- */
- suffix = ".040";
- if (size < 1 * MBIT)
- size_str = "0";
- else if (size == 1 * MBIT)
- size_str = "1";
- else if (size <= 2 * MBIT)
- size_str = "2";
- else if (size <= 3 * MBIT)
- {
- size_str = "3";
- suffix = ".030";
- }
- else if (size <= 4 * MBIT)
- {
- size_str = "4";
- suffix = ".048";
- }
- else
- {
- suffix = ".058";
- if (size <= 6 * MBIT)
- size_str = "6";
- else
- size_str = "8";
- }
- break;
- }
- fname = basename2 (filename);
- // Do NOT mess with prefix (strupr()/strlwr()). See below (remove_mgd_id()).
- sprintf (name, "%s%s%s", prefix, size_str, fname);
- if (size >= 10 * MBIT)
- {
- if (!strnicmp (name, fname, 4))
- strcpy (name, fname);
- }
- else
- {
- if (!strnicmp (name, fname, 3))
- strcpy (name, fname);
- }
- if ((p = strchr (name, '.')) != NULL)
- *p = 0;
- n = strlen (name);
- if (size >= 10 * MBIT)
- {
- if (n < 7)
- strcat (name, "XXX"); // in case fname is 1 character long
- n = 7;
- }
- else
- {
- if (n < 6)
- strcat (name, "XX");
- n = 6;
- }
- name[n] = '0'; // last character must be a number
- name[n + 1] = 0;
- for (n = 3; n < 8; n++) // we can skip the prefix
- if (name[n] == ' ')
- name[n] = 'X';
- /*
- the transfer program "pclink" contains a bug in that it looks at the
- entire file name for an ID string (it should look only at the first 2
- characters).
- */
- strupr (name);
- remove_mgd_id (name + 3, "SF");
- remove_mgd_id (name + 3, "MD");
- remove_mgd_id (name + 3, "PC");
- remove_mgd_id (name + 3, "GG");
- remove_mgd_id (name + 3, "GB");
- set_suffix (name, suffix);
- }
- void
- mgd_write_index_file (void *ptr, int n_names)
- {
- char buf[100 * 10], *p, name[16], dest_name[FILENAME_MAX];
- // one line in the index file takes 10 bytes at max (name (8) + "\r\n" (2)),
- // so buf is large enough for 44 files of 1/4 Mbit (max for 1 diskette)
- if (n_names == 1)
- {
- strcpy (name, (char *) ptr);
- if ((p = strrchr (name, '.')) != NULL)
- *p = 0;
- sprintf (buf, "%s\r\n", name); // DOS text file format
- }
- else if (n_names > 1)
- {
- int n = 0, offset = 0;
- for (; n < n_names; n++)
- {
- strcpy (name, ((char **) ptr)[n]);
- if ((p = strrchr (name, '.')) != NULL)
- *p = 0;
- sprintf (buf + offset, "%s\r\n", name);
- offset += strlen (name) + 2; // + 2 for "\r\n"
- }
- }
- else // n_names <= 0
- return;
- strcpy (dest_name, "MULTI-GD");
- ucon64_file_handler (dest_name, NULL, OF_FORCE_BASENAME);
- ucon64_fwrite (buf, 0, strlen (buf), dest_name, "wb");
- printf (ucon64_msg[WROTE], dest_name);
- }
|