static void write_game_table_entry (FILE *destfile, int file_no, int totalsize, int size) { long int fpos = ftell (destfile); // save file pointer int n; unsigned char name[0x1c]; const char *p; fseek (destfile, 0xb000 + (file_no - 1) * 0x20, SEEK_SET); fputc (0xff, destfile); // 0x0 = 0xff (= valid entry) memset (name, ' ', 0x1c); p = basename2 (ucon64.fname); 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] = (unsigned char) toupper (name[n]); // loader only supports upper case characters } fwrite (name, 1, 0x1c, destfile); // 0x1 - 0x1c = name fputc (totalsize / MBIT, destfile); // 0x1d = bank code fputc (size / MBIT, destfile); // 0x1e = ROM size (not used by loader) fputc (0, destfile); // 0x1f = flags (x, D (reserved), x, x, x, x, x, x) fseek (destfile, fpos, SEEK_SET); // restore file pointer }
char * mkbak (const char *filename, backup_t type) { static char buf[FILENAME_MAX]; if (access (filename, R_OK) != 0) return (char *) filename; strcpy (buf, filename); set_suffix (buf, ".bak"); if (strcmp (filename, buf) != 0) { remove (buf); // *try* to remove or rename() will fail if (rename (filename, buf)) // keep file attributes like date, etc. { fprintf (stderr, "ERROR: Can't rename \"%s\" to \"%s\"\n", filename, buf); exit (1); } } else // handle the case where filename has the suffix ".bak". { char buf2[FILENAME_MAX]; if (!dirname2 (filename, buf)) { fprintf (stderr, "INTERNAL ERROR: dirname2() returned NULL\n"); exit (1); } if (buf[0] != 0) if (buf[strlen (buf) - 1] != FILE_SEPARATOR) strcat (buf, FILE_SEPARATOR_S); strcat (buf, basename2 (tmpnam2 (buf2))); if (rename (filename, buf)) { fprintf (stderr, "ERROR: Can't rename \"%s\" to \"%s\"\n", filename, buf); exit (1); } } switch (type) { case BAK_MOVE: return buf; case BAK_DUPE: default: if (fcopy (buf, 0, fsizeof (buf), filename, "wb")) { fprintf (stderr, "ERROR: Can't open \"%s\" for writing\n", filename); exit (1); } sync (); return buf; } }
const char * get_suffix (const char *filename) // Note that get_suffix() never returns NULL. Other code relies on that! { const char *p, *s; if (!(p = basename2 (filename))) p = filename; if (!(s = strrchr (p, '.'))) s = strchr (p, 0); // strchr(p, 0) and NOT "" is the if (s == p) // suffix of a file without suffix s = strchr (p, 0); // files can start with '.' return s; }
void ucon64_fname_arch (const char *fname) { char name[FILENAME_MAX]; unzFile file = unzOpen (fname); unzip_goto_file (file, unzip_current_file_nr); unzGetCurrentFileInfo (file, NULL, name, FILENAME_MAX, NULL, 0, NULL, 0); unzClose (file); #if defined _WIN32 || defined __MSDOS__ { int n, l = strlen (name); for (n = 0; n < l; n++) if (name[n] == '/') name[n] = FILE_SEPARATOR; } #endif strncpy (ucon64.fname_arch, basename2 (name), FILENAME_MAX)[FILENAME_MAX - 1] = 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; }
st_strpath_t * strpath (st_strpath_t *path, const char *path_s) { // TODO: compare this with splitpath() if (path_s == NULL) return NULL; realpath2 (path_s, path->realpath); #if defined DJGPP || defined __CYGWIN__ || defined _WIN32 if (isalpha (path->realpath[0]) && path->realpath[1] == ':' && path->realpath[2] == FILE_SEPARATOR) sprintf (path->drive, "%c:\\", toupper (path->realpath[0])); #else strcpy (path->drive, FILE_SEPARATOR_S); #endif dirname2 (path_s, path->dirname); strcpy (path->basename, basename2 (path_s)); strcpy (path->suffix, get_suffix (path_s)); return path; }
int ucon64_rom_handling (void) { int no_rom = 0; static st_rominfo_t rominfo; struct stat fstate; ucon64_rom_flush (&rominfo); // a ROM (file)? if (!ucon64.rom) no_rom = 1; else if (!ucon64.rom[0]) no_rom = 1; else if (access (ucon64.rom, F_OK | R_OK) == -1 && (!(ucon64.flags & WF_NO_ROM))) { fprintf (stderr, "ERROR: Could not open %s\n", ucon64.rom); no_rom = 1; } else if (stat (ucon64.rom, &fstate) == -1) no_rom = 1; else if (S_ISREG (fstate.st_mode) != TRUE) no_rom = 1; #if 0 // printing the no_rom error message for files of 0 bytes only confuses people else if (!fstate.st_size) no_rom = 1; #endif if (no_rom) { if (!(ucon64.flags & WF_NO_ROM)) { fputs ("ERROR: This option requires a file argument (ROM/image/SRAM file/directory)\n", stderr); return -1; } return 0; } // The next statement is important and should be executed as soon as // possible (and sensible) in this function ucon64.file_size = fsizeof (ucon64.rom); // We have to do this here, because we don't know the file size until now if (ucon64.buheader_len > ucon64.file_size) { fprintf (stderr, "ERROR: A backup unit header length was specified that is larger than the file\n" " size (%d > %d)\n", ucon64.buheader_len, ucon64.file_size); return -1; } if (!(ucon64.flags & WF_INIT)) return 0; // "walk through" <console>_init() if (ucon64.flags & WF_PROBE) { if (ucon64.rominfo) { // Restore any overrides from st_ucon64_t // We have to do this *before* calling ucon64_probe(), *not* afterwards if (UCON64_ISSET (ucon64.buheader_len)) rominfo.buheader_len = ucon64.buheader_len; if (UCON64_ISSET (ucon64.interleaved)) rominfo.interleaved = ucon64.interleaved; // ucon64.rominfo = (st_rominfo_t *) &rominfo; } ucon64.rominfo = ucon64_probe (&rominfo); // determines console type #ifdef USE_DISCMAGE // check for disc image only if ucon64_probe() failed or --disc was used if (ucon64.discmage_enabled) // if (!ucon64.rominfo || ucon64.force_disc) if (ucon64.force_disc) ucon64.image = dm_reopen (ucon64.rom, 0, (dm_image_t *) ucon64.image); #endif } // end of WF_PROBE // Does the option allow split ROMs? if (ucon64.flags & WF_NO_SPLIT) /* Test for split files only if the console type knows about split files at all. However we only know the console type after probing. */ if (ucon64.console == UCON64_NES || ucon64.console == UCON64_SNES || ucon64.console == UCON64_GEN || ucon64.console == UCON64_NG) if ((UCON64_ISSET (ucon64.split)) ? ucon64.split : ucon64_testsplit (ucon64.rom)) { fprintf (stderr, "ERROR: %s seems to be split. You have to join it first\n", basename2 (ucon64.rom)); return -1; } /* CRC32 Calculating the CRC32 checksum for the ROM data of a UNIF file (NES) shouldn't be done with ucon64_fcrc32(). nes_init() uses crc32(). The CRC32 checksum is used to search in the DAT files, but at the time of this writing (Februari the 7th 2003) all DAT files contain checksums of files in only one format. This matters for SNES and Genesis ROMs in interleaved format and Nintendo 64 ROMs in non-interleaved format. The corresponding initialization functions calculate the CRC32 checksum of the data in the format of which the checksum is stored in the DAT files. For these "problematic" files, their "real" checksum is stored in ucon64.fcrc32. */ if (ucon64.crc32 == 0) if (!ucon64.force_disc) // NOT for disc images if (!(ucon64.flags & WF_NO_CRC32) && ucon64.file_size <= MAXROMSIZE) ucon64_chksum (NULL, NULL, &ucon64.crc32, ucon64.rom, ucon64.rominfo ? ucon64.rominfo->buheader_len : 0); // DATabase ucon64.dat = NULL; if (ucon64.crc32 != 0 && ucon64.dat_enabled) { ucon64.dat = ucon64_dat_search (ucon64.crc32, NULL); if (ucon64.dat) { // detected file size must match DAT file size int size = ucon64.rominfo ? UCON64_ISSET (ucon64.rominfo->data_size) ? ucon64.rominfo->data_size : ucon64.file_size - ucon64.rominfo->buheader_len : ucon64.file_size; if ((int) (((st_ucon64_dat_t *) ucon64.dat)->fsize) != size) ucon64.dat = NULL; } if (ucon64.dat) switch (ucon64.console) { case UCON64_SNES: case UCON64_GEN: case UCON64_GB: case UCON64_GBA: case UCON64_N64: // These ROMs have internal headers with name, country, maker, etc. break; default: // Use ucon64.dat instead of ucon64.dat_enabled in case the index // file could not be created/opened -> no segmentation fault if (ucon64.dat && ucon64.rominfo) { if (!ucon64.rominfo->name[0]) strcpy (ucon64.rominfo->name, NULL_TO_EMPTY (((st_ucon64_dat_t *) ucon64.dat)->name)); else if (ucon64.console == UCON64_NES) { // override the three-character FDS or FAM name int t = nes_get_file_type (); if (t == FDS || t == FAM) strcpy (ucon64.rominfo->name, NULL_TO_EMPTY (((st_ucon64_dat_t *) ucon64.dat)->name)); } if (!ucon64.rominfo->country) ucon64.rominfo->country = NULL_TO_EMPTY (((st_ucon64_dat_t *) ucon64.dat)->country); } break; } } // display info if ((ucon64.flags & WF_NFO || ucon64.flags & WF_NFO_AFTER) && ucon64.quiet < 1) ucon64_nfo (); return 0; }
void ucon64_usage (int argc, char *argv[]) { int x = 0, y = 0, c = 0, single = 0; const char *name_exe = basename2 (argv[0]); #ifdef USE_DISCMAGE char *name_discmage; #endif (void) argc; // warning remover #ifdef USE_ZLIB printf ("Usage: %s [OPTION]... [ROM|IMAGE|SRAM|FILE|DIR|ARCHIVE]...\n\n", name_exe); #else printf ("Usage: %s [OPTION]... [ROM|IMAGE|SRAM|FILE|DIR]...\n\n", name_exe); #endif // single usage for (x = 0; arg[x].val; x++) if (arg[x].console) // IS console for (y = 0; option[y]; y++) for (c = 0; option[y][c].name || option[y][c].help; c++) if (option[y][c].object) if (((st_ucon64_obj_t *) option[y][c].object)->console == arg[x].console) { getopt2_usage (option[y]); single = 1; break; } if (!single) getopt2_usage (options); fputc ('\n', stdout); printf ("DATabase: %d known ROMs (DAT files: %s)\n\n", ucon64_dat_total_entries (), ucon64.datdir); #ifdef USE_DISCMAGE name_discmage = #ifdef DLOPEN ucon64.discmage_path; #else #if defined __MSDOS__ "discmage.dxe"; #elif defined __CYGWIN__ || defined _WIN32 "discmage.dll"; #elif defined __APPLE__ // Mac OS X actually "libdiscmage.dylib"; #elif defined __unix__ || defined __BEOS__ "libdiscmage.so"; #else "unknown"; #endif #endif if (!ucon64.discmage_enabled) { printf (ucon64_msg[NO_LIB], name_discmage); fputc ('\n', stdout); } #endif #ifdef USE_PARALLEL puts ("NOTE: You only need to specify PORT if uCON64 doesn't detect the (right)\n" " parallel port. If that is the case give a hardware address. For example:\n" " ucon64 " OPTION_LONG_S "xswc \"rom.swc\" " OPTION_LONG_S "port=0x378\n" " In order to connect a copier to a PC's parallel port you need a standard\n" " bidirectional parallel cable\n"); #endif printf ("TIP: %s " OPTION_LONG_S "help " OPTION_LONG_S "snes (would show only SNES related help)\n", name_exe); #if defined __MSDOS__ || defined _WIN32 printf (" %s " OPTION_LONG_S "help|more (to see everything in more)\n", name_exe); #else printf (" %s " OPTION_LONG_S "help|less (to see everything in less)\n", name_exe); // less is more ;-) #endif puts (" Give the force recognition switch a try if something went wrong\n" "\n" "Please report any problems/ideas/fixes to [email protected] or\n" "[email protected] or visit http://ucon64.sf.net\n"); }