/***************************************************************************** 
* GROM Versione 0.75 Ita                                                     * 
* Bart Trzynadlowski, 2000, dominio pubblico.                                *
*     Traduzione:                                                            *
* ev0 aka DarkDreAm, 2003                                                    *
*         http://ancoranncelho.bho?                                          *
*****************************************************************************/ 
 
/* 
 * grom.c:  
 * 
 * Semplice utility per giocare con le ROM Genesis. Supporta la conversione dal 
 * formato ROM, SMD a BIN. Visualizza anche le informazioni dall'header 
 * Sega cartridge. 
 * 
 * Thanx a Kuwanger (http://members.tripod.com/~Kuwanger), XnaK, e
 * Later Dude. 
 */ 
 
/* per DOS: ricordati di  mettere un #define DOS qui */ 
#define DOS 
#include <stdio.h> 
#include <string.h> 
 
#define VERSIONE "0.75 Ita" 
#define error(str1, str2)					\
	{							\
		printf(str1, str2);				\
		return 1;					\
	}
#define lower(str, i, j)					\
	{							\
		for (i = 0; str[i] != '\0'; i++)		\
			for (j = 0; j < 6; j++)			\
				if (str[i] == ltab[j])		\
				{				\
					str[i] = ltab[j + 6];	\
					break;			\
				}				\
	}
 
/* funzioni */ 
int convert_smd_bin(char *); 
int show_info(char *); 
void smd_bin(unsigned char *, unsigned char *); 
int check_format(FILE *, char *, char *); 
 
/* ambiente */ 
int nochk = 0; 
 
/* tabella conversione lettere */
char ltab[] = { 'B', 'I', 'N', 'S', 'M', 'D', 'b', 'i', 'n', 's', 'm', 'd' }; 
 
/***************************************************************************** 
 int main(int, char **): 
                Smettila di leggere questo codice sorgente se non conosci
                ke significa main(). La tua testa potrebbe saltare. 
 Input:         Ovvio. 
 Returns:       Ovvio. 
*****************************************************************************/ 
int main(int argc, char **argv) 
{ 
        int i, j, f = 0; 
#ifdef DOS 
        int k; 
#endif 
 
        /* mostra help */ 
        if (argc <= 1) 
        { 
                printf("GROM Versione %s by ev0 aka DarkDreAm, 2003\n", 
                       VERSIONE); 
                printf("Un'utility multi funzione per ROM Sega Genesis\n"); 
                printf("\n"); 
                printf("Uso:    grom [file] [commandi] [opzioni]\n"); 
#ifdef DOS 
                printf("File:     File Genesis ROM, formato BIN o SMD\n"); 
#endif 
#ifndef DOS 
                printf("File:     File Genesis ROM, formato BIN o SMD. " \
                       "\nDeve avere estensione in minuscolo\n"); 
#endif 
                printf("Commandi: -bin    Converte il/i file in formato BIN\n"); 
                printf("          -info   Show information about file(s)\n"); 
                printf("Opzioni:  -chk    Abilità ROM check dettagliati\n"); 
                printf("          -nochk  Disabilità ROM check dettagliati\n"); 
                return 0; 
        } 
        else if (argc <= 2)     /* se non viene specificata nessuna opzione */ 
        { 
                printf("main: non ci sono abbastanza argomenti\n"); 
                return 0; 
        } 
 
        /* opzione ricerca, non rimuovere da argv[] */ 
        for (i = 1; i < argc; i++)    
                if (strcmp(argv[i], "-chk") == 0) 
                        nochk = 0; 
                else if (strcmp(argv[i], "-nochk") == 0) 
                        nochk = 1;                 
 
#ifdef DOS 
        /* passa oltre la linea di comando, converte lettere s, m, d, e b, i, n 
           in miniscolo per prevenire problemi con strstr() in seguito */ 
        for (i = 1; i < argc; i++) 
	{
                lower(argv[i], j, k); 
	}
#endif 
 
        /* attuale comando processo, quando uno viene processato, noi lo 
           rimuoviamo dall'array argv[]. */ 
        for (i = 1; i < argc; i++) 
        { 
                if (strcmp(argv[i], "-bin") == 0)       /* SMD a BIN */ 
                { 
                        f = 1; 
 
                        /* converte ogni file in bin */ 
                        for (j = 1; j < argc; j++) 
                        { 
                                if (*argv[j] == '-')    /* - significa opzioni */ 
                                        ; 
                                else 
                                        convert_smd_bin(argv[j]); 
                        } 
                } 
                else if (strcmp(argv[i], "-info") == 0) /* mostra info */ 
                { 
                        f = 1; 
 
                        /* stampa informazioni su ogni file */ 
                        for (j = 1; j < argc; j++) 
                        { 
                                if (*argv[j] == '-') 
                                        ; 
                                else 
                                        show_info(argv[j]); 
                        } 
                } 
        } 
 
        /* opzione non trovata */ 
        if (!f) 
                printf("main: Nessun comando specificato\n"); 
 
        return 0; 
} 
 
/***************************************************************************** 
 int convert_smd_bin(char *): 
                Converte un file SMD ROM (<filename>.smd) in un file BIN ROM 
                (<filename>.bin). 
 Input:         Percorso file. 
 Returns:       Niente. 
*****************************************************************************/ 
int convert_smd_bin(char *file) 
{ 
        int i, num_blocks, meter = 0; 
        FILE *in_fp, *out_fp; 
        unsigned char smd_block[16384]; 
        unsigned char bin_block[16384]; 
 
        /* open SMD file, open BIN file, get number of blocks, read header */ 
        if ((in_fp = fopen(file, "rb")) == NULL) 
                error("convert_smd_bin: impossibile aprire il file SMD: %s\n", 
                      file); 
        if (check_format(in_fp, file, "smd"))   /* check if it is SMD */ 
                return 1; 
        if ((out_fp = fopen(strcat(strtok(file, "."), ".bin"), "wb")) == NULL) 
                error("convert_smd_bin: impossibile aprire il file BIN: %s\n", 
                       file); 
        fseek(in_fp, 0, SEEK_END); 
        fgetpos(in_fp, (void *) &num_blocks); 
        num_blocks = ((num_blocks + 1) - 512) / 16384; 
        fseek(in_fp, 512, SEEK_SET); 
        
        /* spegne il line buffering su stdout così possiamo vedere i progressi*/ 
        setvbuf(stdout, NULL, _IONBF, NULL); 
 
        printf("convert_smd_bin: Converzione %s in formato BIN", 
               strcat(strtok(file, "."), ".smd")); 
 
        /* converte smd in bin */ 
        for (i = 0; i < num_blocks; i++) 
        { 
                fread(smd_block, 1, 16384, in_fp); 
                smd_bin(bin_block, smd_block); 
                fwrite(bin_block, 1, 16384, out_fp); 
 
                /* aumente il metro ogni 1/10th blocchi totali */ 
                meter++; 
                if (meter == (num_blocks / 10)) 
                { 
                        printf("."); 
                        meter = 0; 
                } 
        } 
 
        printf(" fatto\n"); 
 
        setvbuf(stdout, NULL, _IOLBF, NULL);   /* line buffering torna dietro */ 
 
        /* chiudi i file ed esci */ 
        fclose(in_fp); 
        fclose(out_fp); 
 
        return 0; 
} 
 
/***************************************************************************** 
 int show_info(char *file): 
                Mostra informazioni su un file dato. Se è un file binario le   
                informazioni saranno mostrate dall'header SEGA, comunque
                mostreremeo qualsiasi informazione che possiamo avere. 
 Input:         Percorso file.
 Returns:       Niente. 
*****************************************************************************/ 
int show_info(char *file) 
{ 
        FILE *fp; 
        unsigned char header[16384]; 
        unsigned char smd[16384]; 
        char string[49]; 
 
        /* check to see if it a BIN or SMD file */ 
        if ((strstr(file, ".bin") != NULL) || (strstr(file, ".smd") != NULL)) 
        { 
                /* open file and read the header */ 
                if ((fp = fopen(file, "rb")) == NULL) 
                        error("show_info: Impossibile aprire il file: %s\n", 
                              file); 
 
                if (strstr(file, ".bin") != NULL)       /* file bin */ 
                        fread(header, 1, 512, fp); 
                else                                    /* file smd */ 
                { 
                        /* get first block of SMD */ 
                        fread(smd, 1, 512, fp);         /* salta header */ 
                        fread(smd, 1, 16384, fp); 
                        smd_bin(header, smd);           /* decodifica */ 
                } 
 
                printf("Mostra informazioni dai dati della cartuccia...\n"); 
 
                /* print info from Sega header */ 
                printf("                    File: %s\n", file); 
                string[16] = '\0'; 
                strncpy(string, &header[0x100], 16); 
                printf("                 Sistema: %s\n", string); 
                strncpy(string, &header[0x110], 16); 
                printf("               Copyright: %s\n", string); 
                string[48] = '\0'; 
                strncpy(string, &header[0x120], 48); 
                printf("    Nome gioco (domestic): %s\n", string); 
                strncpy(string, &header[0x150], 48); 
                printf("    Nome gioco (overseas): %s\n", string); 
                if (header[0x180] == 'G' && header[0x181] == 'M') 
                        printf("           Tipo software: gioco\n"); 
                else if (header[0x180] == 'A' && header[0x181] == 'l') 
                        printf("           Tipo software: educativo\n"); 
                else 
                        printf("           Tipo software: %c%c", 
                               header[0x180], header[0x181]); 

                string[11] = '\0'; 
                strncpy(string, &header[0x183], 11); 
                printf("Codice prodotto e versione: %s\n", string); 
                printf("                Checksum: %02X%02X\n", header[0x18e], 
                       header[0x18f]); 
                string[16] = '\0'; 
                strncpy(string, &header[0x190], 16); 
                printf("            supporto I/O: %s\n", string); 
                /* the meaning of these fields may have been misinterpreted */ 
                printf("indirizzo di start della ROM: %02X%02X%02X%02X\n", 
                       header[0x1a0], header[0x1a1], header[0x1a2], 
                       header[0x1a3]); 
                printf(" indirizzo di fine della ROM: %02X%02X%02X%02X\n", 
                       header[0x1a4], header[0x1a5], header[0x1a6], 
                       header[0x1a7]); 
                /* il modem data field è realmente 20 byte? XnaK's doc sembra
                   indicare che sia solo 10... */ 
                string[20] = '\0'; 
                strncpy(string, &header[0x1bc], 20);                 
                printf("              Modem data: %s\n", string); 
                string[40] = '\0'; 
                strncpy(string, &header[0x1c8], 40); 
                printf("                 Memoria: %s\n", string); 
                string[3] = '\0'; 
                strncpy(string, &header[0x1f0], 3); 
                printf("               Countries: %s\n", string); 
 
                fclose(fp); 
        } 
        else 
                printf("show_info: Formato file non riconosciuto: %s\n", file); 
 
        return 0; 
} 
 
/***************************************************************************** 
 void smd_bin(unsigned char *, unsigned char *): 
                Converti un clocco di 16KB SMD in BIN. 
 Input:         Buffer address di destinazione, buffer address sorgente.
                (Address=indirizzo :)
 Returns:       Niente. 
*****************************************************************************/ 
void smd_bin(unsigned char *bin_block, unsigned char *smd_block) 
{ 
        int i, o = 1, e = 0; 
 
        /* converte 16KB di SMD in BIN */ 
        for (i = 0; i < 8192; i++) 
        { 
                bin_block[o] = smd_block[i];                 
                bin_block[e] = smd_block[i+8192]; 
                o += 2; 
                e += 2; 
        } 
}         
 
/***************************************************************************** 
 int check_format(FILE *, char *, char *): 
                Controlla il file dato per essere sicuri che è il tipo di ROM
                dato. 
 Input:         Pointer file, nome file, una stringa descrive il formato: "bin" 
                o "smd". 
 Returns:       0 è okay, 1 no. 
 Note:          Assumere il file è a SEEK_SET. Ritorna con file a SEEK_SET 
                se check è di successo, altrimenti il pointer sarà a 512.                 
*****************************************************************************/ 
int check_format(FILE *fp, char *file, char *type) 
{ 
        unsigned char buffer[512]; 
 
        if (nochk)      /* non usa check se l'utente non vuole */ 
                return 0; 
 
        if (strcmp(type, "bin") == 0)           /* BIN */ 
        { 
                if (strstr(file, ".bin") == NULL)       /* estensione check */ 
                        error("check_formato: File %s potrebbe non essere in BIN" \
                              "formato, operazione cancellata\n", file); 
                fread(buffer, 1, 512, fp); 
                /* check for "SEGA" text */ 
                if (strncmp(buffer + 0x100, "SEGA", 4) != 0) 
                        error("check_formato: File %s potrebbe non essere in BIN" \
                               "formato, operazione cancellata\n", file);
        } 
        else if (strcmp(type, "smd") == 0)      /* SMD */  
        { 
                if (strstr(file, ".smd") == NULL) 
                      error("check_formato: File %s potrebbe non essere in SMD" \
                            "formato, operazione cancellata\n", file); 
              fread(buffer, 1, 512, fp); 
              /* check for 0xaa at 8, 0xbb at 9 */ 
              if ((buffer[8] != 0xaa) || (buffer[9] != 0xbb)) 
                      error("check_formato: File %s potrebbe non essere in SMD" \
                            "formato, operazione cancellata\n", file); 
              /* if there is a "SEGA" text, it is probably in BIN format */ 
              if (strncmp(buffer + 0x100, "SEGA", 4) == 0) 
                      error("check_format: File %s potrebbe non essere in SMD" \
                            "formato, operazione cancellata\n", file); 
      } 
 
      rewind(fp); 
      return 0; 
} 
 
 
                                 
                          
 
 

