int lynx_n (st_rominfo_t *rominfo, const char *name) { st_lnx_header_t header; char dest_name[FILENAME_MAX]; if (!rominfo->buheader_len) { fprintf (stderr, "ERROR: This is no LNX file\n\n"); return -1; } ucon64_fread (&header, 0, sizeof (st_lnx_header_t), ucon64.rom); memset (header.cartname, 0, sizeof (header.cartname)); strncpy (header.cartname, name, sizeof (header.cartname)); strcpy (dest_name, ucon64.rom); ucon64_file_handler (dest_name, NULL, 0); fcopy (ucon64.rom, 0, ucon64.file_size, dest_name, "wb"); ucon64_fwrite (&header, 0, sizeof (st_lnx_header_t), dest_name, "r+b"); printf (ucon64_msg[WROTE], dest_name); return 0; }
int pce_f (st_ucon64_nfo_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.fname); strcpy (dest_name, ucon64.fname); 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->backup_header_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->backup_header_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; }
int pce_swap (st_ucon64_nfo_t *rominfo) { char src_name[FILENAME_MAX], dest_name[FILENAME_MAX]; unsigned char *rom_buffer; int size = ucon64.file_size - rominfo->backup_header_len; if ((rom_buffer = (unsigned char *) malloc (size)) == NULL) { fprintf (stderr, ucon64_msg[ROM_BUFFER_ERROR], size); return -1; } strcpy (src_name, ucon64.fname); strcpy (dest_name, ucon64.fname); ucon64_file_handler (dest_name, src_name, 0); if (rominfo->backup_header_len) // copy header (if present) fcopy (src_name, 0, rominfo->backup_header_len, dest_name, "wb"); ucon64_fread (rom_buffer, rominfo->backup_header_len, size, src_name); swapbits (rom_buffer, size); ucon64_fwrite (rom_buffer, rominfo->backup_header_len, size, dest_name, rominfo->backup_header_len ? "ab" : "wb"); free (rom_buffer); printf (ucon64_msg[WROTE], dest_name); remove_temp_file (); return 0; }
static int lynx_b (st_rominfo_t *rominfo, int bank, const char *value) { st_lnx_header_t header; short int *bankvar; char dest_name[FILENAME_MAX]; if (!rominfo->buheader_len) { fprintf (stderr, "ERROR: This is no LNX file\n\n"); return -1; } ucon64_fread (&header, 0, sizeof (st_lnx_header_t), ucon64.rom); bankvar = (bank == 0 ? &header.page_size_bank0 : &header.page_size_bank1); if ((atol (value) % 64) != 0 || (atol (value) > 512)) *bankvar = 0; else #ifdef WORDS_BIGENDIAN *bankvar = bswap_16 (atol (value) * 4); #else *bankvar = atol (value) * 4; #endif strcpy (dest_name, ucon64.rom); ucon64_file_handler (dest_name, NULL, 0); fcopy (ucon64.rom, 0, ucon64.file_size, dest_name, "wb"); ucon64_fwrite (&header, 0, sizeof (st_lnx_header_t), dest_name, "r+b"); printf (ucon64_msg[WROTE], dest_name); return 0; }
int dc_parse (const char *templ_file) { char ip[0x8000], dest_name[FILENAME_MAX]; if (access (templ_file, F_OK) == -1) { int i = 0; printf ("Creating empty template file: \"%s\"\n", templ_file); for (i = 0; templ[i].name; i++) set_property (templ_file, templ[i].name, templ[i].def, templ[i].comment); printf (ucon64_msg[WROTE], templ_file); } if (parse_templ (templ_file, ip) == -1) return -1; update_crc (ip); strcpy (dest_name, "ip.bin"); ucon64_file_handler (dest_name, NULL, 0); ucon64_fwrite (ip, 0, 0x8000, dest_name, "wb"); printf (ucon64_msg[WROTE], dest_name); return 0; }
int ppf_set_fid (const char *ppf, const char *fidname) { int fidsize, ppfsize, pos; char ppfname[FILENAME_MAX], fidbuf[MAX_ID_SIZE + 34 + 1] = "@BEGIN_FILE_ID.DIZ"; // +1 for string terminator strcpy (ppfname, ppf); ucon64_file_handler (ppfname, NULL, 0); fcopy (ppf, 0, fsizeof (ppf), ppfname, "wb"); // no copy if one file printf ("Adding FILE_ID.DIZ (%s)...\n", fidname); fidsize = ucon64_fread (fidbuf + 18, 0, MAX_ID_SIZE, fidname); memcpy (fidbuf + 18 + fidsize, "@END_FILE_ID.DIZ", 16); ppfsize = fsizeof (ppfname); pos = ucon64_find (ppfname, 0, ppfsize, "@BEGIN_FILE_ID.DIZ", 18, MEMCMP2_CASE | UCON64_FIND_QUIET); if (pos == -1) pos = ppfsize; truncate (ppfname, pos); ucon64_fwrite (fidbuf, pos, fidsize + 18 + 16, ppfname, "r+b"); pos += fidsize + 18 + 16; #ifdef WORDS_BIGENDIAN fidsize = bswap_32 (fidsize); // Write file size in little-endian format #endif ucon64_fwrite (&fidsize, pos, 4, ppfname, "r+b"); printf (ucon64_msg[WROTE], ppfname); return 0; }
int mccl_read (const char *filename, unsigned int parport) { unsigned char buffer[0x1760], inbyte; char dest_name[FILENAME_MAX]; int count = 0; time_t starttime; parport_print_info (); puts ("Resetting device"); do { outportb (CONTROL, 0x24); while ((inportb (STATUS) & 0x20) == 0) ; } while ((inportw (DATA) & 0xf) != 4); outportb (CONTROL, 0x22); while ((inportb (STATUS) & 0x20) != 0) ; outportb (CONTROL, 0x26); printf ("Receive: %d Bytes (%.4f Mb)\n\n", 0x1760, (float) 0x1760 / MBIT); starttime = time (NULL); do { outportb (CONTROL, 0x26); while ((inportb (STATUS) & 0x20) == 0) ; inbyte = (unsigned char) (inportw (DATA) & 0xf); outportb (CONTROL, 0x22); while ((inportb (STATUS) & 0x20) != 0) ; outportb (CONTROL, 0x26); while ((inportb (STATUS) & 0x20) == 0) ; inbyte |= (unsigned char) ((inportw (DATA) & 0xf) << 4); outportb (CONTROL, 0x22); while ((inportb (STATUS) & 0x20) != 0) ; buffer[count++] = inbyte; if ((count & 0x1f) == 0) ucon64_gauge (starttime, count, 0x1760); } while (count < 0x1760); strcpy (dest_name, filename); ucon64_file_handler (dest_name, NULL, 0); ucon64_fwrite (buffer, 0, count, dest_name, "wb"); printf (ucon64_msg[WROTE], dest_name); return 0; }
int dc_unscramble (void) { char dest_name[FILENAME_MAX]; strcpy (dest_name, ucon64.fname); ucon64_file_handler (dest_name, NULL, 0); if (!descramble (ucon64.fname, ucon64.file_size, dest_name)) printf (ucon64_msg[WROTE], dest_name); else fprintf (stderr, ucon64_msg[WRITE_ERROR], dest_name); return 0; }
int ppf_set_desc (const char *ppf, const char *description) { char desc[50], ppfname[FILENAME_MAX]; strcpy (ppfname, ppf); memset (desc, ' ', 50); strncpy (desc, description, strlen (description)); ucon64_file_handler (ppfname, NULL, 0); fcopy (ppf, 0, fsizeof (ppf), ppfname, "wb"); // no copy if one file ucon64_fwrite (desc, 6, 50, ppfname, "r+b"); printf (ucon64_msg[WROTE], ppfname); return 0; }
int lynx_lnx (st_rominfo_t *rominfo) { st_lnx_header_t header; char dest_name[FILENAME_MAX]; int size = ucon64.file_size; if (rominfo->buheader_len != 0) { fprintf (stderr, "ERROR: This seems to already be an LNX file\n\n"); return -1; } header.page_size_bank0 = size > 4 * MBIT ? 4 * MBIT / 256 : size / 256; header.page_size_bank1 = size > 4 * MBIT ? (size - (4 * MBIT)) / 256 : 0; #ifdef WORDS_BIGENDIAN header.page_size_bank0 = bswap_16 (header.page_size_bank0); header.page_size_bank1 = bswap_16 (header.page_size_bank1); #endif memset (header.cartname, 0, sizeof (header.cartname)); memset (header.manufname, 0, sizeof (header.manufname)); memset (header.spare, 0, sizeof (header.spare)); #ifdef WORDS_BIGENDIAN header.version = bswap_16 (1); #else header.version = 1; #endif memcpy (header.magic, "LYNX", 4); header.rotation = 0; strncpy (header.cartname, ucon64.rom, sizeof (header.cartname)); strcpy (header.manufname, "Atari"); strcpy (dest_name, ucon64.rom); set_suffix (dest_name, ".lnx"); ucon64_file_handler (dest_name, NULL, 0); ucon64_fwrite (&header, 0, sizeof (st_lnx_header_t), dest_name, "wb"); fcopy (ucon64.rom, 0, ucon64.file_size, dest_name, "ab"); printf (ucon64_msg[WROTE], dest_name); return 0; }
// header format is specified in src/backup/ffe.h int pce_msg (st_ucon64_nfo_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->backup_header_len; if (rominfo->interleaved) if ((rom_buffer = (unsigned char *) malloc (size)) == NULL) { fprintf (stderr, ucon64_msg[ROM_BUFFER_ERROR], size); return -1; } memset (&header, 0, MSG_HEADER_LEN); header.size = (unsigned char) (size / 8192); header.emulation = size == 3 * MBIT ? 1 : 0; header.id1 = 0xaa; header.id2 = 0xbb; header.type = 2; strcpy (src_name, ucon64.fname); strcpy (dest_name, ucon64.fname); 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->backup_header_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->backup_header_len, size, dest_name, "ab"); printf (ucon64_msg[WROTE], dest_name); remove_temp_file (); return 0; }
int lynx_lyx (st_rominfo_t *rominfo) { char dest_name[FILENAME_MAX]; if (!rominfo->buheader_len) { fprintf (stderr, "ERROR: This is no LNX file\n\n"); return -1; } strcpy (dest_name, ucon64.rom); set_suffix (dest_name, ".lyx"); ucon64_file_handler (dest_name, NULL, 0); fcopy (ucon64.rom, rominfo->buheader_len, ucon64.file_size, dest_name, "wb"); printf (ucon64_msg[WROTE], dest_name); return 0; }
// see src/backup/mgd.h for the file naming scheme int pce_mgd (st_ucon64_nfo_t *rominfo) { char src_name[FILENAME_MAX], dest_name[FILENAME_MAX]; unsigned char *rom_buffer = NULL; int size = ucon64.file_size - rominfo->backup_header_len; if (!rominfo->interleaved) if ((rom_buffer = (unsigned char *) malloc (size)) == NULL) { fprintf (stderr, ucon64_msg[ROM_BUFFER_ERROR], size); return -1; } strcpy (src_name, ucon64.fname); mgd_make_name (ucon64.fname, 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->backup_header_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->backup_header_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; }
static int lynx_rot (st_rominfo_t *rominfo, int rotation) { st_lnx_header_t header; char dest_name[FILENAME_MAX]; if (!rominfo->buheader_len) { fprintf (stderr, "ERROR: This is no LNX file\n\n"); return -1; } ucon64_fread (&header, 0, sizeof (st_lnx_header_t), ucon64.rom); header.rotation = rotation; // header.rotation is an 8-bit field strcpy (dest_name, ucon64.rom); ucon64_file_handler (dest_name, NULL, 0); fcopy (ucon64.rom, 0, ucon64.file_size, dest_name, "wb"); ucon64_fwrite (&header, 0, sizeof (st_lnx_header_t), dest_name, "r+b"); printf (ucon64_msg[WROTE], dest_name); return 0; }
// based on sourcecode of MakePPF v2.0 Linux/Unix by Icarus/Paradox int ppf_create (const char *orgname, const char *modname) { FILE *orgfile, *modfile, *ppffile; char ppfname[FILENAME_MAX], buffer[MAX_ID_SIZE], obuf[512], mbuf[512]; #if 0 char *fidname = "FILE_ID.DIZ"; #endif int x, osize, msize, blocksize, n_changes, total_changes = 0; unsigned int seekpos = 0, pos; osize = fsizeof (orgname); msize = fsizeof (modname); #ifndef DIFF_FSIZE if (osize != msize) { fprintf (stderr, "ERROR: File sizes do not match\n"); return -1; } #endif if ((orgfile = fopen (orgname, "rb")) == NULL) { fprintf (stderr, ucon64_msg[OPEN_READ_ERROR], orgname); exit (1); } if ((modfile = fopen (modname, "rb")) == NULL) { fprintf (stderr, ucon64_msg[OPEN_READ_ERROR], modname); exit (1); } strcpy (ppfname, modname); set_suffix (ppfname, ".ppf"); ucon64_file_handler (ppfname, NULL, 0); if ((ppffile = fopen (ppfname, "wb")) == NULL) { fprintf (stderr, ucon64_msg[OPEN_WRITE_ERROR], ppfname); exit (1); } // creating PPF 2.0 header fwrite ("PPF20", 5, 1, ppffile); // magic fputc (1, ppffile); // encoding method memset (buffer, ' ', 50); fwrite (buffer, 50, 1, ppffile); // description line #ifdef WORDS_BIGENDIAN x = bswap_32 (osize); fwrite (&x, 4, 1, ppffile); #else fwrite (&osize, 4, 1, ppffile); // orgfile size #endif fseek (orgfile, 0x9320, SEEK_SET); memset (buffer, 0, 1024); // one little hack that makes PPF fread (buffer, 1024, 1, orgfile); // suitable for files < 38688 bytes fwrite (buffer, 1024, 1, ppffile); // 1024 byte block printf ("Writing patch data, please wait...\n"); // finding changes fseek (orgfile, 0, SEEK_SET); fseek (modfile, 0, SEEK_SET); while ((blocksize = fread (obuf, 1, 255, orgfile))) { blocksize = fread (mbuf, 1, blocksize, modfile); #ifdef DIFF_FSIZE if (blocksize == 0) break; #endif pos = seekpos; x = 0; while (x != blocksize) { if (obuf[x] != mbuf[x]) { pos = seekpos + x; n_changes = 0; do { buffer[n_changes] = mbuf[x]; n_changes++; x++; } while (x != blocksize && obuf[x] != mbuf[x]); total_changes += n_changes; #ifdef WORDS_BIGENDIAN pos = bswap_32 (pos); #endif fwrite (&pos, 4, 1, ppffile); fputc (n_changes, ppffile); fwrite (buffer, n_changes, 1, ppffile); } else x++; } seekpos += blocksize; } #ifdef DIFF_FSIZE if (msize > osize) { pos = seekpos; while ((blocksize = fread (buffer, 1, 255, modfile))) { total_changes += blocksize; #ifdef WORDS_BIGENDIAN x = bswap_32 (pos); fwrite (&x, 4, 1, ppffile); #else fwrite (&pos, 4, 1, ppffile); #endif fputc (blocksize, ppffile); fwrite (buffer, blocksize, 1, ppffile); pos += blocksize; } } else if (msize < osize) printf ("WARNING: %s is smaller than %s\n" " PPF can't store information about that fact\n", modname, orgname); #endif fclose (orgfile); fclose (modfile); if (total_changes == 0) { printf ("%s and %s are identical\n" "Removing: %s\n", orgname, modname, ppfname); fclose (ppffile); remove (ppfname); return -1; } #if 0 if (fidname) { int fsize = fsizeof (fidname); if (fsize > MAX_ID_SIZE) fsize = MAX_ID_SIZE; // File id only up to 3072 bytes! printf ("Adding FILE_ID.DIZ (%s)...\n", fidname); ucon64_fread (buffer, 0, fsize, fidname); fwrite ("@BEGIN_FILE_ID.DIZ", 18, 1, ppffile); fwrite (buffer, fsize, 1, ppffile); fwrite ("@END_FILE_ID.DIZ", 16, 1, ppffile); #ifdef WORDS_BIGENDIAN fsize = bswap_32 (fsize); // Write file size in little-endian format #endif fwrite (&fsize, 4, 1, ppffile); } #endif fclose (ppffile); printf (ucon64_msg[WROTE], ppfname); return 0; }
// based on source code of ApplyPPF v2.0 for Linux/Unix by Icarus/Paradox int ppf_apply (const char *mod, const char *ppfname) { FILE *modfile, *ppffile; char desc[50 + 1], diz[MAX_ID_SIZE + 1], buffer[1024], ppfblock[1024], modname[FILENAME_MAX]; int x, method, dizlen = 0, modlen, ppfsize, bytes_to_skip = 0, n_changes; unsigned int pos; strcpy (modname, mod); ucon64_file_handler (modname, NULL, 0); fcopy (mod, 0, fsizeof (mod), modname, "wb"); // no copy if one file if ((modfile = fopen (modname, "r+b")) == NULL) { fprintf (stderr, ucon64_msg[OPEN_WRITE_ERROR], modname); exit (1); } if ((ppffile = fopen (ppfname, "rb")) == NULL) { fprintf (stderr, ucon64_msg[OPEN_READ_ERROR], ppfname); exit (1); } // Is it a PPF File? fread (buffer, 3, 1, ppffile); if (strncmp ("PPF", buffer, 3)) { fprintf (stderr, "ERROR: %s is not a valid PPF file\n", ppfname); exit (1); } // What encoding method? PPF 1.0 or PPF 2.0? fseek (ppffile, 5, SEEK_SET); method = fgetc (ppffile); if (method != 0 && method != 1) { fprintf (stderr, "ERROR: Unknown encoding method! Check for updates\n"); exit (1); } ppfsize = fsizeof (ppfname); // Show PPF information fseek (ppffile, 6, SEEK_SET); // Read description line fread (desc, 50, 1, ppffile); desc[50] = 0; // terminate string printf ("\n" // print a newline between "Filename : %s\n", ppfname); // backup message and PPF info printf ("Encoding method : %d (PPF %d.0)\n", method, method + 1); printf ("Description : %s\n", desc); if (method == 0) // PPF 1.0 { printf ("FILE_ID.DIZ : No\n\n"); x = 56; // file pointer is at right position (56) } else // method == 1 // PPF 2.0 { fseek (ppffile, ppfsize - 8, SEEK_SET); fread (buffer, 4, 1, ppffile); // Is there a file id? if (strncmp (".DIZ", buffer, 4)) printf ("FILE_ID.DIZ : No\n\n"); else { printf ("FILE_ID.DIZ : Yes, showing...\n"); fread (&dizlen, 4, 1, ppffile); #ifdef WORDS_BIGENDIAN dizlen = bswap_32 (dizlen); // FILE_ID.DIZ size is in little-endian format #endif fseek (ppffile, ppfsize - dizlen - (16 + 4), SEEK_SET); bytes_to_skip = dizlen + 18 + 16 + 4; // +4 for FILE_ID.DIZ size integer if (dizlen > MAX_ID_SIZE) dizlen = MAX_ID_SIZE; // do this after setting bytes_to_skip! fread (diz, dizlen, 1, ppffile); diz[dizlen] = 0; // terminate string puts (diz); } // Do the file size check fseek (ppffile, 56, SEEK_SET); fread (&x, 4, 1, ppffile); #ifdef WORDS_BIGENDIAN x = bswap_32 (x); // file size is stored in little-endian format #endif modlen = fsizeof (modname); if (x != modlen) { fprintf (stderr, "ERROR: The size of %s is not %d bytes\n", modname, x); exit (1); } // Do the binary block check fseek (ppffile, 60, SEEK_SET); fread (ppfblock, 1024, 1, ppffile); fseek (modfile, 0x9320, SEEK_SET); memset (buffer, 0, 1024); // one little hack that makes PPF fread (buffer, 1024, 1, modfile); // suitable for files < 38688 bytes if (memcmp (ppfblock, buffer, 1024)) { fprintf (stderr, "ERROR: This patch does not belong to this image\n"); exit (1); } fseek (ppffile, 1084, SEEK_SET); x = 1084; } // Patch the image printf ("Patching...\n"); for (; x < ppfsize - bytes_to_skip; x += 4 + 1 + n_changes) { fread (&pos, 4, 1, ppffile); // Get position for modfile #ifdef WORDS_BIGENDIAN pos = bswap_32 (pos); #endif n_changes = fgetc (ppffile); // How many bytes do we have to write? fread (buffer, n_changes, 1, ppffile); // And this is what we have to write fseek (modfile, pos, SEEK_SET); // Go to the right position in the modfile fwrite (buffer, n_changes, 1, modfile); // Write n_changes bytes to that pos } printf ("Done\n"); fclose (ppffile); fclose (modfile); printf (ucon64_msg[WROTE], modname); return 0; }
int bsl_apply (const char *mod, const char *bslname) { FILE *modfile, *bslfile; unsigned char byte; char buf[4096], modname[FILENAME_MAX]; int data, nbytes, offset; strcpy (modname, mod); ucon64_file_handler (modname, NULL, 0); fcopy (mod, 0, fsizeof (mod), modname, "wb"); // no copy if one file if ((modfile = fopen (modname, "r+b")) == NULL) { fprintf (stderr, ucon64_msg[OPEN_WRITE_ERROR], modname); return -1; } if ((bslfile = fopen (bslname, "rb")) == NULL) { fprintf (stderr, ucon64_msg[OPEN_WRITE_ERROR], bslname); return -1; } printf ("Applying BSL/Baseline patch...\n"); while (!feof (bslfile)) // we could use 1, but feof() makes it fail-safe { fscanf (bslfile, "%d\n", &offset); fscanf (bslfile, "%d\n", &data); if ((offset == -1) && (data == -1)) break; fseek (modfile, offset, SEEK_SET); fputc (data, modfile); } fscanf (bslfile, "%d\n", &offset); fscanf (bslfile, "%d\n", &nbytes); fseek (modfile, offset, SEEK_SET); if (nbytes > 0) { while (nbytes > 4096) { fread (buf, 4096, 1, bslfile); fwrite (buf, 4096, 1, modfile); nbytes -= 4096; } while (nbytes-- >= 0) // yes, one byte more than the { // _value_ read from the BSL file byte = (unsigned char) fgetc (bslfile); fputc (byte, modfile); } } printf ("Patching complete\n\n"); printf (ucon64_msg[WROTE], modname); printf ("\n" "NOTE: Sometimes you have to add/strip a 512 bytes header when you patch a ROM\n" " This means you must modify for example a SNES ROM with -swc or -stp or\n" " the patch will not work\n"); fclose (bslfile); fclose (modfile); return 0; }
int pce_multi (int truncate_size, char *fname) { #define BUFSIZE (32 * 1024) int n, n_files, file_no, bytestowrite, byteswritten, done, truncated = 0, totalsize = 0, size, 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: Cannot 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.fname = ucon64.argv[n]; ucon64.file_size = fsizeof (ucon64.fname); // DON'T use fstate.st_size, because file could be compressed ucon64.do_not_calc_crc = 1; if (pce_init (ucon64.nfo) != 0) printf ("WARNING: %s does not appear to be a PC-Engine ROM\n", ucon64.fname); if ((srcfile = fopen (ucon64.fname, "rb")) == NULL) { fprintf (stderr, ucon64_msg[OPEN_READ_ERROR], ucon64.fname); continue; } if (ucon64.nfo->backup_header_len) fseek (srcfile, ucon64.nfo->backup_header_len, SEEK_SET); size = ucon64.file_size - ucon64.nfo->backup_header_len; if (file_no == 0) { printf ("Loader: %s\n", ucon64.fname); if (size != PCE_PRO_LOADER_SIZE) printf ("WARNING: Are you sure %s is a loader binary?\n", ucon64.fname); } else { printf ("ROM%d: %s\n", file_no, ucon64.fname); write_game_table_entry (destfile, file_no, totalsize, size); } 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 needs %d Mbit on flash card, truncating %s, skipping %d bytes\n", truncate_size / MBIT, ucon64.fname, size - (byteswritten + bytestowrite)); } totalsize += bytestowrite; if (bytestowrite == 0) done = 1; fwrite (buffer, 1, bytestowrite, destfile); byteswritten += bytestowrite; } // Be sure the ROM size is a multiple of the buffer size used in // pce_write_rom(), which is 0x4000 (16 kB, so using "buffer" is OK). bytestowrite = ((size + 0x3fff) & ~0x3fff) - size; if (bytestowrite) { memset (buffer, 0xff, bytestowrite); totalsize += bytestowrite; fwrite (buffer, 1, bytestowrite, destfile); } // pce_write_rom() handles alignment. Games have to be aligned to a Mbit // boundary. totalsize = (totalsize + MBIT - 1) & ~(MBIT - 1); if (size == 3 * MBIT || size == 4 * MBIT) totalsize += 2 * MBIT; fclose (srcfile); 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 // Make it possible for pce_write_rom() to detect that the file is a // multi-game file. fseek (destfile, 0xb3f4, SEEK_SET); strncpy ((char *) buffer, "uCON64 " UCON64_VERSION_S, 12); buffer[12] = 0; fwrite (buffer, 1, strlen ((char *) buffer), destfile); fclose (destfile); ucon64.console = UCON64_PCE; ucon64.do_not_calc_crc = org_do_not_calc_crc; return 0; }