1 /*
2  * cartconv - Cartridge Conversion utility.
3  *
4  * Written by
5  *  Marco van den heuvel <blackystardust68@yahoo.com>
6  *  groepaz <groepaz@gmx.net>
7  *
8  * This file is part of VICE, the Versatile Commodore Emulator.
9  * See README for copyright notice.
10  *
11  *  This program is free software; you can redistribute it and/or modify
12  *  it under the terms of the GNU General Public License as published by
13  *  the Free Software Foundation; either version 2 of the License, or
14  *  (at your option) any later version.
15  *
16  *  This program is distributed in the hope that it will be useful,
17  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
18  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  *  GNU General Public License for more details.
20  *
21  *  You should have received a copy of the GNU General Public License
22  *  along with this program; if not, write to the Free Software
23  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
24  *  02111-1307  USA.
25  *
26  */
27 
28 #include "vice.h"
29 
30 #include <assert.h>
31 #include <ctype.h>
32 #include <stdlib.h>
33 #include <stdio.h>
34 #include <string.h>
35 
36 #ifdef HAVE_STRINGS_H
37 #include <strings.h>
38 #endif
39 
40 #ifdef HAVE_UNISTD_H
41 #include <unistd.h>
42 #endif
43 
44 #if defined(WATCOM_COMPILE) && defined(HAVE_IO_H)
45 #include <io.h>
46 #endif
47 
48 
49 #include "version.h"
50 
51 #ifdef USE_SVN_REVISION
52 # include "svnversion.h"
53 #endif
54 
55 #include "cartridge.h"
56 
57 static FILE *infile, *outfile;
58 static int load_address = 0;
59 static int loadfile_offset = 0;
60 static unsigned int loadfile_size = 0;
61 static char *output_filename = NULL;
62 static char *input_filename[33];
63 static char *cart_name = NULL;
64 static signed char cart_type = -1;
65 static char convert_to_bin = 0;
66 static char convert_to_prg = 0;
67 static char convert_to_ultimax = 0;
68 static unsigned char input_filenames = 0;
69 static char loadfile_is_crt = 0;
70 static char loadfile_is_ultimax = 0;
71 static int loadfile_cart_type = 0;
72 static unsigned char filebuffer[(1024 * 1024) + 2];
73 static unsigned char headerbuffer[0x40];
74 static unsigned char extra_buffer_32kb[0x8000];
75 static unsigned char chipbuffer[16];
76 static int repair_mode = 0;
77 static int input_padding = 0;
78 static int quiet_mode = 0;
79 static int omit_empty_banks = 1;
80 
81 static int load_input_file(char *filename);
82 
83 typedef struct cart_s {
84     unsigned char exrom;
85     unsigned char game;
86     unsigned int sizes;
87     unsigned int bank_size;
88     unsigned int load_address;
89     unsigned char banks;   /* 0 means the amount of banks need to be taken from the load-size and bank-size */
90     unsigned int data_type;
91     char *name;
92     char *opt;
93     void (*save)(unsigned int p1, unsigned int p2, unsigned int p3, unsigned int p4, unsigned char gameline, unsigned char exromline);
94 } cart_t;
95 
96 typedef struct sorted_cart_s {
97     char *opt;
98     char *name;
99     int crt_id;
100     int insertion;
101 } sorted_cart_t;
102 
103 /* some prototypes to save routines */
104 static void save_regular_crt(unsigned int p1, unsigned int p2, unsigned int p3, unsigned int p4, unsigned char game, unsigned char exrom);
105 static void save_fcplus_crt(unsigned int p1, unsigned int p2, unsigned int p3, unsigned int p4, unsigned char game, unsigned char exrom);
106 static void save_2_blocks_crt(unsigned int p1, unsigned int p2, unsigned int p3, unsigned int p4, unsigned char game, unsigned char exrom);
107 static void save_generic_crt(unsigned int p1, unsigned int p2, unsigned int p3, unsigned int p4, unsigned char p5, unsigned char p6);
108 static void save_easyflash_crt(unsigned int p1, unsigned int p2, unsigned int p3, unsigned int p4, unsigned char game, unsigned char exrom);
109 static void save_ocean_crt(unsigned int p1, unsigned int p2, unsigned int p3, unsigned int p4, unsigned char game, unsigned char exrom);
110 static void save_funplay_crt(unsigned int p1, unsigned int p2, unsigned int p3, unsigned int p4, unsigned char game, unsigned char exrom);
111 static void save_zaxxon_crt(unsigned int p1, unsigned int p2, unsigned int p3, unsigned int p4, unsigned char game, unsigned char exrom);
112 static void save_stardos_crt(unsigned int p1, unsigned int p2, unsigned int p3, unsigned int p4, unsigned char game, unsigned char exrom);
113 static void save_delaep64_crt(unsigned int p1, unsigned int p2, unsigned int p3, unsigned int p4, unsigned char game, unsigned char exrom);
114 static void save_delaep256_crt(unsigned int p1, unsigned int p2, unsigned int p3, unsigned int p4, unsigned char game, unsigned char exrom);
115 static void save_delaep7x8_crt(unsigned int p1, unsigned int p2, unsigned int p3, unsigned int p4, unsigned char game, unsigned char exrom);
116 static void save_rexep256_crt(unsigned int p1, unsigned int p2, unsigned int p3, unsigned int p4, unsigned char game, unsigned char exrom);
117 static void save_easycalc_crt(unsigned int p1, unsigned int p2, unsigned int p3, unsigned int p4, unsigned char game, unsigned char exrom);
118 
119 /* this table must be in correct order so it can be indexed by CRT ID */
120 /*
121     exrom, game, sizes, bank size, load addr, num banks, data type, name, option, saver
122 
123     num banks == 0 - take number of banks from input file size
124 */
125 static const cart_t cart_info[] = {
126 /*  {0, 1, CARTRIDGE_SIZE_8KB, 0x2000, 0x8000, 1, 0, "Generic 8kb", NULL, NULL}, */ /* 8k game config */
127 /*  {0, 0, CARTRIDGE_SIZE_12KB, 0x3000, 0x8000, 1, 0, "Generic 12kb", NULL, NULL}, */ /* 16k game config */
128 /*  {0, 0, CARTRIDGE_SIZE_16KB, 0x4000, 0x8000, 1, 0, "Generic 16kb", NULL, NULL}, */ /* 16k game config */
129 /*  {1, 0, CARTRIDGE_SIZE_4KB | CARTRIDGE_SIZE_16KB, 0, 0, 1, 0, "Ultimax", NULL, NULL}, */ /* ultimax config */
130 
131 /* FIXME: initial exrom/game values are often wrong in this table
132  *        don't forget to also update vice.texi accordingly */
133 
134     {0, 1, CARTRIDGE_SIZE_4KB | CARTRIDGE_SIZE_8KB | CARTRIDGE_SIZE_12KB | CARTRIDGE_SIZE_16KB, 0, 0, 0, 0, "Generic Cartridge", NULL, save_generic_crt},
135     {0, 1, CARTRIDGE_SIZE_32KB, 0x2000, 0x8000, 4, 0, CARTRIDGE_NAME_ACTION_REPLAY, "ar5", save_regular_crt}, /* this is NOT AR1, but 4.2,5,6 etc */
136     {0, 0, CARTRIDGE_SIZE_16KB, 0x2000, 0, 2, 0, CARTRIDGE_NAME_KCS_POWER, "kcs", save_2_blocks_crt},
137     {0, 0, CARTRIDGE_SIZE_64KB | CARTRIDGE_SIZE_256KB, 0x4000, 0x8000, 0, 0, CARTRIDGE_NAME_FINAL_III, "fc3", save_regular_crt},
138     {0, 0, CARTRIDGE_SIZE_16KB, 0x2000, 0, 2, 0, CARTRIDGE_NAME_SIMONS_BASIC, "simon", save_2_blocks_crt},
139     {0, 0, CARTRIDGE_SIZE_32KB | CARTRIDGE_SIZE_128KB | CARTRIDGE_SIZE_256KB | CARTRIDGE_SIZE_512KB, 0x2000, 0, 0, 0, CARTRIDGE_NAME_OCEAN, "ocean", save_ocean_crt},
140     {1, 0, CARTRIDGE_SIZE_8KB, 0x2000, 0x8000, 1, 2, CARTRIDGE_NAME_EXPERT, "expert", NULL},
141     {0, 1, CARTRIDGE_SIZE_128KB, 0x2000, 0x8000, 16, 0, CARTRIDGE_NAME_FUNPLAY, "fp", save_funplay_crt},
142     {0, 0, CARTRIDGE_SIZE_64KB, 0x4000, 0x8000, 4, 0, CARTRIDGE_NAME_SUPER_GAMES, "sg", save_regular_crt},
143     {0, 1, CARTRIDGE_SIZE_32KB, 0x2000, 0x8000, 4, 0, CARTRIDGE_NAME_ATOMIC_POWER, "ap", save_regular_crt},
144     {0, 1, CARTRIDGE_SIZE_8KB, 0x2000, 0x8000, 1, 0, CARTRIDGE_NAME_EPYX_FASTLOAD, "epyx", save_regular_crt},
145     {0, 0, CARTRIDGE_SIZE_16KB, 0x4000, 0x8000, 1, 0, CARTRIDGE_NAME_WESTERMANN, "wl", save_regular_crt},
146     {0, 1, CARTRIDGE_SIZE_8KB, 0x2000, 0x8000, 1, 0, CARTRIDGE_NAME_REX, "ru", save_regular_crt},
147     {0, 0, CARTRIDGE_SIZE_16KB, 0x4000, 0x8000, 1, 0, CARTRIDGE_NAME_FINAL_I, "fc1", save_regular_crt},
148     {1, 0, CARTRIDGE_SIZE_64KB | CARTRIDGE_SIZE_96KB | CARTRIDGE_SIZE_128KB, 0x2000, 0xe000, 0, 0, CARTRIDGE_NAME_MAGIC_FORMEL, "mf", save_regular_crt}, /* FIXME: 64k (v1), 96k (v2) and 128k (full) bins exist */
149     {0, 1, CARTRIDGE_SIZE_512KB, 0x2000, 0x8000, 64, 0, CARTRIDGE_NAME_GS, "gs", save_regular_crt},
150     {0, 0, CARTRIDGE_SIZE_16KB, 0x4000, 0x8000, 1, 0, CARTRIDGE_NAME_WARPSPEED, "ws", save_regular_crt},
151     {0, 1, CARTRIDGE_SIZE_128KB, 0x2000, 0x8000, 16, 0, CARTRIDGE_NAME_DINAMIC, "din", save_regular_crt},
152     {0, 0, CARTRIDGE_SIZE_20KB, 0, 0, 3, 0, CARTRIDGE_NAME_ZAXXON, "zaxxon", save_zaxxon_crt},
153     {0, 1, CARTRIDGE_SIZE_32KB | CARTRIDGE_SIZE_64KB | CARTRIDGE_SIZE_128KB | CARTRIDGE_SIZE_256KB | CARTRIDGE_SIZE_512KB | CARTRIDGE_SIZE_1024KB, 0x2000, 0x8000, 0, 0, CARTRIDGE_NAME_MAGIC_DESK, "md", save_regular_crt},
154     {0, 0, CARTRIDGE_SIZE_64KB, 0x4000, 0x8000, 4, 0, CARTRIDGE_NAME_SUPER_SNAPSHOT_V5, "ss5", save_regular_crt},
155     {0, 0, CARTRIDGE_SIZE_64KB | CARTRIDGE_SIZE_128KB, 0x4000, 0x8000, 0, 0, CARTRIDGE_NAME_COMAL80, "comal", save_regular_crt},
156     {1, 0, CARTRIDGE_SIZE_16KB, 0x2000, 0x8000, 2, 0, CARTRIDGE_NAME_STRUCTURED_BASIC, "sb", save_regular_crt},
157     {0, 0, CARTRIDGE_SIZE_16KB | CARTRIDGE_SIZE_32KB, 0x4000, 0x8000, 0, 0, CARTRIDGE_NAME_ROSS, "ross", save_regular_crt},
158     {0, 1, CARTRIDGE_SIZE_8KB, 0, 0x8000, 0, 0, CARTRIDGE_NAME_DELA_EP64, "dep64", save_delaep64_crt},
159     {0, 1, CARTRIDGE_SIZE_8KB, 0x2000, 0x8000, 0, 0, CARTRIDGE_NAME_DELA_EP7x8, "dep7x8", save_delaep7x8_crt},
160     {0, 1, CARTRIDGE_SIZE_8KB, 0x2000, 0x8000, 0, 0, CARTRIDGE_NAME_DELA_EP256, "dep256", save_delaep256_crt},
161     {0, 1, CARTRIDGE_SIZE_8KB, 0, 0x8000, 0, 0, CARTRIDGE_NAME_REX_EP256, "rep256", save_rexep256_crt},
162     {0, 1, CARTRIDGE_SIZE_8KB, 0x2000, 0x8000, 1, 0, CARTRIDGE_NAME_MIKRO_ASSEMBLER, "mikro", save_regular_crt},
163     {1, 0, CARTRIDGE_SIZE_24KB | CARTRIDGE_SIZE_32KB, 0x8000, 0x0000, 1, 0, CARTRIDGE_NAME_FINAL_PLUS, "fcp", save_fcplus_crt},
164     {0, 1, CARTRIDGE_SIZE_32KB, 0x2000, 0x8000, 4, 0, CARTRIDGE_NAME_ACTION_REPLAY4, "ar4", save_regular_crt},
165     {1, 0, CARTRIDGE_SIZE_16KB, 0x2000, 0, 4, 0, CARTRIDGE_NAME_STARDOS, "star", save_stardos_crt},
166     {1, 0, CARTRIDGE_SIZE_1024KB, 0x2000, 0, 128, 0, CARTRIDGE_NAME_EASYFLASH, "easy", save_easyflash_crt},
167     {0, 0, 0, 0, 0, 0, 0, CARTRIDGE_NAME_EASYFLASH_XBANK, NULL, NULL}, /* TODO ?? */
168     {1, 1, CARTRIDGE_SIZE_8KB, 0x2000, 0x8000, 1, 0, CARTRIDGE_NAME_CAPTURE, "cap", save_regular_crt},
169     {0, 1, CARTRIDGE_SIZE_16KB, 0x2000, 0x8000, 2, 0, CARTRIDGE_NAME_ACTION_REPLAY3, "ar3", save_regular_crt},
170     {0, 1, CARTRIDGE_SIZE_32KB | CARTRIDGE_SIZE_64KB | CARTRIDGE_SIZE_128KB, 0x2000, 0x8000, 0, 0, CARTRIDGE_NAME_RETRO_REPLAY, "rr", save_regular_crt},
171     {0, 1, CARTRIDGE_SIZE_8KB, 0x2000, 0x8000, 1, 0, CARTRIDGE_NAME_MMC64, "mmc64", save_regular_crt},
172     {0, 0, CARTRIDGE_SIZE_64KB | CARTRIDGE_SIZE_512KB, 0x2000, 0x8000, 0, 0, CARTRIDGE_NAME_MMC_REPLAY, "mmcr", save_regular_crt},
173     {0, 1, CARTRIDGE_SIZE_64KB | CARTRIDGE_SIZE_128KB | CARTRIDGE_SIZE_512KB, 0x4000, 0x8000, 0, 2, CARTRIDGE_NAME_IDE64, "ide64", save_regular_crt},
174     {0, 0, CARTRIDGE_SIZE_32KB, 0x4000, 0x8000, 2, 0, CARTRIDGE_NAME_SUPER_SNAPSHOT, "ss4", save_regular_crt},
175     {0, 1, CARTRIDGE_SIZE_4KB, 0x1000, 0x8000, 1, 0, CARTRIDGE_NAME_IEEE488, "ieee", save_regular_crt},
176     {1, 0, CARTRIDGE_SIZE_8KB, 0x2000, 0xe000, 1, 0, CARTRIDGE_NAME_GAME_KILLER, "gk", save_regular_crt},
177     {0, 1, CARTRIDGE_SIZE_256KB, 0x2000, 0x8000, 32, 0, CARTRIDGE_NAME_P64, "p64", save_regular_crt},
178     {1, 0, CARTRIDGE_SIZE_8KB, 0x2000, 0xe000, 1, 0, CARTRIDGE_NAME_EXOS, "exos", save_regular_crt},
179     {0, 1, CARTRIDGE_SIZE_8KB, 0x2000, 0x8000, 1, 0, CARTRIDGE_NAME_FREEZE_FRAME, "ff", save_regular_crt},
180     {0, 1, CARTRIDGE_SIZE_16KB | CARTRIDGE_SIZE_32KB, 0x4000, 0x8000, 0, 0, CARTRIDGE_NAME_FREEZE_MACHINE, "fm", save_regular_crt},
181     {0, 0, CARTRIDGE_SIZE_4KB, 0x1000, 0xe000, 1, 0, CARTRIDGE_NAME_SNAPSHOT64, "s64", save_regular_crt},
182     {0, 1, CARTRIDGE_SIZE_16KB, 0x2000, 0x8000, 2, 0, CARTRIDGE_NAME_SUPER_EXPLODE_V5, "se5", save_regular_crt},
183     {1, 0, CARTRIDGE_SIZE_16KB, 0x4000, 0x8000, 1, 0, CARTRIDGE_NAME_MAGIC_VOICE, "mv", save_regular_crt},
184     {0, 1, CARTRIDGE_SIZE_16KB, 0x2000, 0x8000, 2, 0, CARTRIDGE_NAME_ACTION_REPLAY2, "ar2", save_regular_crt},
185     {0, 1, CARTRIDGE_SIZE_4KB | CARTRIDGE_SIZE_8KB, 0x2000, 0x8000, 0, 0, CARTRIDGE_NAME_MACH5, "mach5", save_regular_crt},
186     {0, 1, CARTRIDGE_SIZE_8KB, 0x2000, 0x8000, 1, 0, CARTRIDGE_NAME_DIASHOW_MAKER, "dsm", save_regular_crt},
187     {0, 0, CARTRIDGE_SIZE_64KB, 0x4000, 0x8000, 4, 0, CARTRIDGE_NAME_PAGEFOX, "pf", save_regular_crt},
188     {0, 0, CARTRIDGE_SIZE_24KB, 0x2000, 0x8000, 3, 0, CARTRIDGE_NAME_KINGSOFT, "ks", save_regular_crt},
189     {0, 1, CARTRIDGE_SIZE_128KB, 0x2000, 0x8000, 16, 0, CARTRIDGE_NAME_SILVERROCK_128, "silver", save_regular_crt},
190     {1, 0, CARTRIDGE_SIZE_32KB, 0x2000, 0xe000, 4, 0, CARTRIDGE_NAME_FORMEL64, "f64", save_regular_crt},
191     {0, 1, CARTRIDGE_SIZE_64KB, 0x2000, 0x8000, 8, 0, CARTRIDGE_NAME_RGCD, "rgcd", save_regular_crt},
192     {0, 1, CARTRIDGE_SIZE_8KB, 0x2000, 0x8000, 1, 0, CARTRIDGE_NAME_RRNETMK3, "rrnet", save_regular_crt},
193     {0, 0, CARTRIDGE_SIZE_24KB, 0, 0, 3, 0, CARTRIDGE_NAME_EASYCALC, "ecr", save_easycalc_crt},
194     {0, 1, CARTRIDGE_SIZE_512KB, 0x2000, 0x8000, 64, 0, CARTRIDGE_NAME_GMOD2, "gmod2", save_regular_crt},
195     {0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL}
196 };
197 
198 #ifndef HAVE_MEMMOVE
199 #define memmove(x, y, z) bcopy(y, x, z)
200 #endif
201 
202 #ifndef HAVE_STRDUP
strdup(const char * string)203 char *strdup(const char *string)
204 {
205     char *new;
206 
207     new = malloc(strlen(string) + 1);
208     if (new != NULL) {
209         strcpy(new, string);
210     }
211     return new;
212 }
213 #endif
214 
215 #if !defined(HAVE_STRNCASECMP)
216 static const unsigned char charmap[] = {
217     '\000', '\001', '\002', '\003', '\004', '\005', '\006', '\007',
218     '\010', '\011', '\012', '\013', '\014', '\015', '\016', '\017',
219     '\020', '\021', '\022', '\023', '\024', '\025', '\026', '\027',
220     '\030', '\031', '\032', '\033', '\034', '\035', '\036', '\037',
221     '\040', '\041', '\042', '\043', '\044', '\045', '\046', '\047',
222     '\050', '\051', '\052', '\053', '\054', '\055', '\056', '\057',
223     '\060', '\061', '\062', '\063', '\064', '\065', '\066', '\067',
224     '\070', '\071', '\072', '\073', '\074', '\075', '\076', '\077',
225     '\100', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
226     '\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
227     '\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
228     '\170', '\171', '\172', '\133', '\134', '\135', '\136', '\137',
229     '\140', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
230     '\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
231     '\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
232     '\170', '\171', '\172', '\173', '\174', '\175', '\176', '\177',
233     '\200', '\201', '\202', '\203', '\204', '\205', '\206', '\207',
234     '\210', '\211', '\212', '\213', '\214', '\215', '\216', '\217',
235     '\220', '\221', '\222', '\223', '\224', '\225', '\226', '\227',
236     '\230', '\231', '\232', '\233', '\234', '\235', '\236', '\237',
237     '\240', '\241', '\242', '\243', '\244', '\245', '\246', '\247',
238     '\250', '\251', '\252', '\253', '\254', '\255', '\256', '\257',
239     '\260', '\261', '\262', '\263', '\264', '\265', '\266', '\267',
240     '\270', '\271', '\272', '\273', '\274', '\275', '\276', '\277',
241     '\300', '\341', '\342', '\343', '\344', '\345', '\346', '\347',
242     '\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357',
243     '\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367',
244     '\370', '\371', '\372', '\333', '\334', '\335', '\336', '\337',
245     '\340', '\341', '\342', '\343', '\344', '\345', '\346', '\347',
246     '\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357',
247     '\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367',
248     '\370', '\371', '\372', '\373', '\374', '\375', '\376', '\377',
249 };
250 
strncasecmp(const char * s1,const char * s2,size_t n)251 int strncasecmp(const char *s1, const char *s2, size_t n)
252 {
253     unsigned char u1, u2;
254 
255     for (; n != 0; --n) {
256         u1 = (unsigned char)*s1++;
257         u2 = (unsigned char)*s2++;
258         if (charmap[u1] != charmap[u2]) {
259             return charmap[u1] - charmap[u2];
260         }
261 
262         if (u1 == '\0') {
263             return 0;
264         }
265     }
266     return 0;
267 }
268 #endif
269 
cleanup(void)270 static void cleanup(void)
271 {
272     int i;
273 
274     if (output_filename != NULL) {
275         free(output_filename);
276     }
277     if (cart_name != NULL) {
278         free(cart_name);
279     }
280     for (i = 0; i < 33; i++) {
281         if (input_filename[i] != NULL) {
282             free(input_filename[i]);
283         }
284     }
285 }
286 
count_valid_option_elements(void)287 static unsigned int count_valid_option_elements(void)
288 {
289     unsigned int i = 1;
290     unsigned int amount = 0;
291 
292     while (cart_info[i].name) {
293         if (cart_info[i].opt) {
294             amount++;
295         }
296         i++;
297     }
298     return amount;
299 }
300 
compare_elements(const void * op1,const void * op2)301 static int compare_elements(const void *op1, const void *op2)
302 {
303     const sorted_cart_t *p1 = (const sorted_cart_t *)op1;
304     const sorted_cart_t *p2 = (const sorted_cart_t *)op2;
305 
306     return strcmp(p1->opt, p2->opt);
307 }
308 
usage_types(void)309 static void usage_types(void)
310 {
311     unsigned int i = 1;
312     int n = 0;
313     unsigned int amount;
314     sorted_cart_t *sorted_option_elements;
315 
316     cleanup();
317     printf("supported cart types:\n\n");
318 
319     printf("bin      Binary .bin file (Default crt->bin)\n");
320     printf("prg      Binary C64 .prg file with load-address\n\n");
321     printf("normal   Generic 8kb/12kb/16kb .crt file (Default bin->crt)\n");
322     printf("ulti     Ultimax mode 4kb/8kb/16kb .crt file\n\n");
323 
324     /* get the amount of valid options, excluding crt id 0 */
325     amount = count_valid_option_elements();
326 
327     sorted_option_elements = malloc(amount * sizeof(sorted_cart_t));
328 
329     /* fill in the array with the information needed */
330     while (cart_info[i].name) {
331         if (cart_info[i].opt) {
332             sorted_option_elements[n].opt = cart_info[i].opt;
333             sorted_option_elements[n].name = cart_info[i].name;
334             sorted_option_elements[n].crt_id = (int)i;
335             switch (i) {
336                 case CARTRIDGE_DELA_EP7x8:
337                 case CARTRIDGE_DELA_EP64:
338                 case CARTRIDGE_REX_EP256:
339                 case CARTRIDGE_DELA_EP256:
340                     sorted_option_elements[n].insertion = 1;
341                     break;
342                 default:
343                     sorted_option_elements[n].insertion = 0;
344                     break;
345             }
346             n++;
347         }
348         i++;
349     }
350 
351     qsort(sorted_option_elements, amount, sizeof(sorted_cart_t), compare_elements);
352 
353     /* output the sorted list */
354     for (i = 0; i < amount; i++) {
355         n = sorted_option_elements[i].insertion;
356         printf("%-8s %s .crt file%s\n", sorted_option_elements[i].opt, sorted_option_elements[i].name, n ? ", extra files can be inserted" : "");
357     }
358     free(sorted_option_elements);
359     exit(1);
360 }
361 
usage(void)362 static void usage(void)
363 {
364     cleanup();
365     printf("convert:    cartconv [-r] [-q] [-t cart type] -i \"input name\" -o \"output name\" [-n \"cart name\"] [-l load address]\n");
366     printf("print info: cartconv [-r] -f \"input name\"\n\n");
367     printf("-f <name>    print info on file\n");
368     printf("-r           repair mode (accept broken input files)\n");
369     printf("-p           accept non padded binaries as input\n");
370     printf("-b           output all banks (do not optimize the .crt file)\n");
371     printf("-t <type>    output cart type\n");
372     printf("-i <name>    input filename\n");
373     printf("-o <name>    output filename\n");
374     printf("-n <name>    crt cart name\n");
375     printf("-l <addr>    load address\n");
376     printf("-q           quiet\n");
377     printf("--types      show the supported cart types\n");
378     printf("--version    print cartconv version\n");
379     exit(1);
380 }
381 
382 
383 /** \brief  Dump cartconv version string on stdout
384  *
385  * Dumps the SVN revision as well, if compiled from SVN
386  */
dump_version(void)387 static void dump_version(void)
388 {
389 #ifdef USE_SVN_REVISION
390     printf("cartconv (VICE %s SVN r%d)\n", VERSION, VICE_SVN_REV_NUMBER);
391 #else
392     printf("cartconv (VICE %s)\n", VERSION);
393 #endif
394 }
395 
396 
printbanks(char * name)397 static void printbanks(char *name)
398 {
399     FILE *f;
400     unsigned char b[0x10];
401     long len, filelen;
402     long pos;
403     unsigned int type, bank, start, size;
404     char *typestr[4] = { "ROM", "RAM", "FLASH", "UNK" };
405     unsigned int numbanks;
406     unsigned long tsize;
407 
408     f = fopen(name, "rb");
409     fseek(f, 0, SEEK_END);
410     filelen = ftell(f);
411 
412     tsize = 0; numbanks = 0;
413     if (f) {
414         fseek(f, 0x40, SEEK_SET); /* skip crt header */
415         pos = 0x40;
416         printf("\noffset  sig  type  bank start size  chunklen\n");
417         while (!feof(f)) {
418             fseek(f, pos, SEEK_SET);
419             /* get chip header */
420             if (fread(b, 1, 0x10, f) < 0x10) {
421                 break;
422             }
423             len = (b[7] + (b[6] * 0x100) + (b[5] * 0x10000) + (b[4] * 0x1000000));
424             type = (unsigned int)((b[8] * 0x100) + b[9]);
425             bank = (unsigned int)((b[10] * 0x100) + b[11]);
426             start = (unsigned int)((b[12] * 0x100) + b[13]);
427             size = (unsigned int)((b[14] * 0x100) + b[15]);
428             if (type > 2) {
429                 type = 3; /* invalid */
430             }
431             printf("$%06lx %-1c%-1c%-1c%-1c %-5s #%03d $%04x $%04x $%04lx\n", pos, b[0], b[1], b[2], b[3], typestr[type], bank, start, size, len);
432             if ((size + 0x10) > len) {
433                 printf("  Error: data size exceeds chunk length\n");
434             }
435             if (len > (filelen - pos)) {
436                 printf("  Error: data size exceeds end of file\n");
437                 break;
438             }
439             pos += len;
440             numbanks++;
441             tsize += size;
442         }
443         fclose(f);
444         printf("\ntotal banks: %d size: $%06lx\n", numbanks, tsize);
445     }
446 }
447 
printinfo(char * name)448 static void printinfo(char *name)
449 {
450     int crtid;
451     char *idname, *modename;
452     char cartname[0x20 + 1];
453     char *exrom_warning = NULL;
454     char *game_warning = NULL;
455 
456     if (load_input_file(name) < 0) {
457         printf("Error: this file seems broken.\n\n");
458     }
459     crtid = headerbuffer[0x17] + (headerbuffer[0x16] << 8);
460     if (headerbuffer[0x17] & 0x80) {
461         /* handle our negative test IDs */
462         crtid -= 0x10000;
463     }
464     if ((crtid >= 0) && (crtid <= CARTRIDGE_LAST)) {
465         idname = cart_info[crtid].name;
466     } else {
467         idname = "unknown";
468     }
469     if ((headerbuffer[0x18] == 1) && (headerbuffer[0x19] == 0)) {
470         modename = "ultimax";
471     } else if ((headerbuffer[0x18] == 0) && (headerbuffer[0x19] == 0)) {
472         modename = "16k Game";
473     } else if ((headerbuffer[0x18] == 0) && (headerbuffer[0x19] == 1)) {
474         modename = "8k Game";
475     } else {
476         modename = "?";
477     }
478     if (crtid && headerbuffer[0x18] != cart_info[crtid].exrom) {
479         exrom_warning = "Warning: exrom in crt image set incorrectly.\n";
480     }
481     if (crtid && headerbuffer[0x19] != cart_info[crtid].game) {
482         game_warning = "Warning: game in crt image set incorrectly.\n";
483     }
484     memcpy(cartname, &headerbuffer[0x20], 0x20); cartname[0x20] = 0;
485     printf("CRT Version: %d.%d\n", headerbuffer[0x14], headerbuffer[0x15]);
486     printf("Name: %s\n", cartname);
487     printf("Hardware ID: %d (%s)\n", crtid, idname);
488     printf("Mode: exrom: %d game: %d (%s)\n", headerbuffer[0x18], headerbuffer[0x19], modename);
489     if (exrom_warning) {
490         printf("%s", exrom_warning);
491     }
492     if (game_warning) {
493         printf("%s", game_warning);
494     }
495     printbanks(name);
496     exit (0);
497 }
498 
checkarg(char * arg)499 static void checkarg(char *arg)
500 {
501     if (arg == NULL) {
502         usage();
503     }
504 }
505 
checkflag(char * flg,char * arg)506 static int checkflag(char *flg, char *arg)
507 {
508     int i;
509 
510     switch (tolower((int)(flg[1]))) {
511         case 'f':
512             printinfo(arg);
513             return 2;
514         case 'r':
515             repair_mode = 1;
516             return 1;
517         case 'b':
518             omit_empty_banks = 0;
519             return 1;
520         case 'q':
521             quiet_mode = 1;
522             return 1;
523         case 'p':
524             input_padding = 1;
525             return 1;
526         case 'o':
527             checkarg(arg);
528             if (output_filename == NULL) {
529                 output_filename = strdup(arg);
530             } else {
531                 usage();
532             }
533             return 2;
534         case 'n':
535             checkarg(arg);
536             if (cart_name == NULL) {
537                 cart_name = strdup(arg);
538             } else {
539                 usage();
540             }
541             return 2;
542         case 'l':
543             checkarg(arg);
544             if (load_address == 0) {
545                 load_address = atoi(arg);
546             } else {
547                 usage();
548             }
549             return 2;
550         case 't':
551             checkarg(arg);
552             if (cart_type != -1 || convert_to_bin != 0 || convert_to_prg != 0 || convert_to_ultimax != 0) {
553                 usage();
554             } else {
555                 for (i = 0; cart_info[i].name != NULL; i++) {
556                     if (cart_info[i].opt != NULL) {
557                         if (!strcasecmp(cart_info[i].opt, arg)) {
558                             cart_type = (signed char)i;
559                             break;
560                         }
561                     }
562                 }
563                 if (cart_type == -1) {
564                     if (!strcmp(arg, "bin")) {
565                         convert_to_bin = 1;
566                     } else if (!strcmp(arg, "normal")) {
567                         cart_type = CARTRIDGE_CRT;
568                     } else if (!strcmp(arg, "prg")) {
569                         convert_to_prg = 1;
570                     } else if (!strcmp(arg, "ulti")) {
571                         cart_type = CARTRIDGE_CRT;
572                         convert_to_ultimax = 1;
573                     } else {
574                         usage();
575                     }
576                 }
577             }
578             return 2;
579         case 'i':
580             checkarg(arg);
581             if (input_filenames == 33) {
582                 usage();
583             }
584             input_filename[input_filenames] = strdup(arg);
585             input_filenames++;
586             return 2;
587         default:
588             usage();
589             break;
590     }
591     return 1;
592 }
593 
too_many_inputs(void)594 static void too_many_inputs(void)
595 {
596     fprintf(stderr, "Error: too many input files\n");
597     cleanup();
598     exit(1);
599 }
600 
601 
602 /* this loads the easyflash cart and puts it as the interleaved way into
603    the buffer for easy binary saving */
load_easyflash_crt(void)604 static int load_easyflash_crt(void)
605 {
606     unsigned int load_position;
607 
608     memset(filebuffer, 0xff, 0x100000);
609     while (1) {
610         if (fread(chipbuffer, 1, 16, infile) != 16) {
611             if (loadfile_size == 0) {
612                 return -1;
613             } else {
614                 return 0;
615             }
616         }
617         loadfile_size = 0x100000;
618         if (chipbuffer[0] != 'C' || chipbuffer[1] != 'H' || chipbuffer[2] != 'I' || chipbuffer[3] != 'P') {
619             return -1;
620         }
621         if (load_address == 0) {
622             load_address = (chipbuffer[0xc] << 8) + chipbuffer[0xd];
623         }
624         load_position = (unsigned int)((chipbuffer[0xb] * 0x4000) + ((chipbuffer[0xc] == 0x80) ? 0 : 0x2000));
625         if (fread(filebuffer + load_position, 1, 0x2000, infile) != 0x2000) {
626             return -1;
627         }
628     }
629 }
630 
load_all_banks(void)631 static int load_all_banks(void)
632 {
633     unsigned int length, datasize, loadsize, pad;
634 
635     if (loadfile_cart_type == CARTRIDGE_EASYFLASH) {
636         return load_easyflash_crt();
637     }
638 
639     while (1) {
640         /* get CHIP header */
641         if (fread(chipbuffer, 1, 16, infile) != 16) {
642             if (loadfile_size == 0) {
643                 fprintf(stderr, "Error: could not read data from file.\n");
644                 return -1;
645             } else {
646                 return 0;
647             }
648         }
649         if (chipbuffer[0] != 'C' || chipbuffer[1] != 'H' || chipbuffer[2] != 'I' || chipbuffer[3] != 'P') {
650             fprintf(stderr, "Error: CHIP tag not found.\n");
651             return -1;
652         }
653         /* set load address to the load address of first CHIP in the file. this is not quite
654            correct, but works ok for the few cases when it matters */
655         if (load_address == 0) {
656             load_address = (chipbuffer[0xc] << 8) + chipbuffer[0xd];
657         }
658         length = (unsigned int)((chipbuffer[4] << 24) + (chipbuffer[5] << 16) + (chipbuffer[6] << 8) + chipbuffer[7]);
659         datasize = (unsigned int)((chipbuffer[14] * 0x100) + chipbuffer[15]);
660         loadsize = datasize;
661         if ((datasize + 0x10) > length) {
662             if (repair_mode) {
663                 fprintf(stderr, "Warning: data size exceeds chunk length. (data:%04x chunk:%04x)\n", datasize, length);
664                 loadsize = length - 0x10;
665             } else {
666                 fprintf(stderr, "Error: data size exceeds chunk length. (data:%04x chunk:%04x) (use -r to force)\n", datasize, length);
667                 return -1;
668             }
669         }
670         /* load data */
671         if (fread(filebuffer + loadfile_size, 1, loadsize, infile) != loadsize) {
672             if (repair_mode) {
673                 fprintf(stderr, "Warning: unexpected end of file.\n");
674                 loadfile_size += datasize;
675                 break;
676             }
677             fprintf(stderr, "Error: could not read data from file. (use -r to force)\n");
678             return -1;
679         }
680         /* if the chunk is larger than the contained data+chip header, skip the rest */
681         pad = length - (datasize + 0x10);
682         if (pad > 0) {
683             fprintf(stderr, "Warning: chunk length exceeds data size (data:%04x chunk:%04x), skipping %04x bytes.\n", datasize, length, pad);
684             fseek(infile, pad, SEEK_CUR);
685         }
686         loadfile_size += datasize;
687     }
688     return 0;
689 }
690 
save_binary_output_file(void)691 static int save_binary_output_file(void)
692 {
693     unsigned char address_buffer[2];
694 
695     outfile = fopen(output_filename, "wb");
696     if (outfile == NULL) {
697         fprintf(stderr, "Error: Can't open output file %s\n", output_filename);
698         return -1;
699     }
700     if (convert_to_prg == 1) {
701         address_buffer[0] = (unsigned char)(load_address & 0xff);
702         address_buffer[1] = (unsigned char)(load_address >> 8);
703         if (fwrite(address_buffer, 1, 2, outfile) != 2) {
704             fprintf(stderr, "Error: Can't write to file %s\n", output_filename);
705             fclose(outfile);
706             return -1;
707         }
708     }
709     if (fwrite(filebuffer, 1, loadfile_size, outfile) != loadfile_size) {
710         fprintf(stderr, "Error: Can't write to file %s\n", output_filename);
711         fclose(outfile);
712         return -1;
713     }
714     fclose(outfile);
715     if (!quiet_mode) {
716         printf("Input file : %s\n", input_filename[0]);
717         printf("Output file : %s\n", output_filename);
718         printf("Conversion from %s .crt to binary format successful.\n", cart_info[loadfile_cart_type].name);
719     }
720     return 0;
721 }
722 
write_crt_header(unsigned char gameline,unsigned char exromline)723 static int write_crt_header(unsigned char gameline, unsigned char exromline)
724 {
725     unsigned char crt_header[0x40] = "C64 CARTRIDGE   ";
726     int endofname = 0;
727     int i;
728 
729     crt_header[0x10] = 0;
730     crt_header[0x11] = 0;
731     crt_header[0x12] = 0;
732     crt_header[0x13] = 0x40;
733 
734     crt_header[0x14] = 1;
735     crt_header[0x15] = 0;
736 
737     crt_header[0x16] = 0;
738     crt_header[0x17] = (unsigned char)cart_type;
739 
740     crt_header[0x18] = exromline;
741     crt_header[0x19] = gameline;
742 
743     crt_header[0x1a] = 0;
744     crt_header[0x1b] = 0;
745     crt_header[0x1c] = 0;
746     crt_header[0x1d] = 0;
747     crt_header[0x1e] = 0;
748     crt_header[0x1f] = 0;
749 
750     if (cart_name == NULL) {
751         cart_name = strdup("VICE CART");
752     }
753 
754     for (i = 0; i < 32; i++) {
755         if (endofname == 1) {
756             crt_header[0x20 + i] = 0;
757         } else {
758             if (cart_name[i] == 0) {
759                 endofname = 1;
760             } else {
761                 crt_header[0x20 + i] = (unsigned char)toupper((int)cart_name[i]);
762             }
763         }
764     }
765 
766     outfile = fopen(output_filename, "wb");
767     if (outfile == NULL) {
768         fprintf(stderr, "Error: Can't open output file %s\n", output_filename);
769         return -1;
770     }
771     if (fwrite(crt_header, 1, 0x40, outfile) != 0x40) {
772         fprintf(stderr, "Error: Can't write crt header to file %s\n", output_filename);
773         fclose(outfile);
774         unlink(output_filename);
775         return -1;
776     }
777     return 0;
778 }
779 
write_chip_package(unsigned int length,unsigned int bankint,unsigned int address,unsigned char type)780 static int write_chip_package(unsigned int length, unsigned int bankint, unsigned int address, unsigned char type)
781 {
782     unsigned char chip_header[0x10] = "CHIP";
783     unsigned char bank = (unsigned char)bankint;
784 
785     /* make sure the above conversion did not remove significant bits */
786     assert(bankint == bank);
787 
788     chip_header[4] = 0;
789     chip_header[5] = 0;
790     chip_header[6] = (unsigned char)((length + 0x10) >> 8);
791     chip_header[7] = (unsigned char)((length + 0x10) & 0xff);
792 
793     chip_header[8] = 0;
794     chip_header[9] = type;
795 
796     chip_header[0xa] = 0;
797     chip_header[0xb] = bank;
798 
799     chip_header[0xc] = (unsigned char)(address >> 8);
800     chip_header[0xd] = (unsigned char)(address & 0xff);
801 
802     chip_header[0xe] = (unsigned char)(length >> 8);
803     chip_header[0xf] = (unsigned char)(length & 0xff);
804     if (fwrite(chip_header, 1, 0x10, outfile) != 0x10) {
805         fprintf(stderr, "Error: Can't write chip header to file %s\n", output_filename);
806         fclose(outfile);
807         unlink(output_filename);
808         return -1;
809     }
810     if (fwrite(filebuffer + loadfile_offset, 1, length, outfile) != length) {
811         fprintf(stderr, "Error: Can't write data to file %s\n", output_filename);
812         fclose(outfile);
813         unlink(output_filename);
814         return -1;
815     }
816     loadfile_offset += (int)length;
817     return 0;
818 }
819 
bin2crt_ok(void)820 static void bin2crt_ok(void)
821 {
822     if (!quiet_mode) {
823         printf("Input file : %s\n", input_filename[0]);
824         printf("Output file : %s\n", output_filename);
825         printf("Conversion from binary format to %s .crt successful.\n", cart_info[(unsigned char)cart_type].name);
826     }
827 }
828 
save_regular_crt(unsigned int length,unsigned int banks,unsigned int address,unsigned int type,unsigned char game,unsigned char exrom)829 static void save_regular_crt(unsigned int length, unsigned int banks, unsigned int address, unsigned int type, unsigned char game, unsigned char exrom)
830 {
831     unsigned int i;
832     unsigned int real_banks = banks;
833 
834     /* printf("save_regular_crt length: %d banks:%d address: %d\n", length, banks, address); */
835 
836     if (write_crt_header(game, exrom) < 0) {
837         cleanup();
838         exit(1);
839     }
840 
841     if (real_banks == 0) {
842         /* handle the case when a chip of half the regular size
843            is used on an otherwise identical hardware (eg 4k
844            chip on a 8k cart)
845         */
846         if (loadfile_size == (length / 2)) {
847             length /= 2;
848         }
849         real_banks = loadfile_size / length;
850     }
851 
852     for (i = 0; i < real_banks; i++) {
853         if (write_chip_package(length, i, address, (unsigned char)type) < 0) {
854             cleanup();
855             exit(1);
856         }
857     }
858     fclose(outfile);
859     bin2crt_ok();
860     cleanup();
861     exit(0);
862 }
863 
save_fcplus_crt(unsigned int length,unsigned int banks,unsigned int address,unsigned int type,unsigned char game,unsigned char exrom)864 static void save_fcplus_crt(unsigned int length, unsigned int banks, unsigned int address, unsigned int type, unsigned char game, unsigned char exrom)
865 {
866     unsigned int i;
867     unsigned int real_banks = banks;
868 
869     /* printf("save_fcplus_crt length: %d banks:%d address: %d\n", length, banks, address); */
870 
871     if (write_crt_header(game, exrom) < 0) {
872         cleanup();
873         exit(1);
874     }
875 
876     if (real_banks == 0) {
877         real_banks = loadfile_size / length;
878     }
879 
880     if (loadfile_size != 0x8000) {
881         memmove(filebuffer + 0x2000, filebuffer, 0x6000);
882         memset(filebuffer, 0xff, 0x2000);
883     }
884 
885     for (i = 0; i < real_banks; i++) {
886         if (write_chip_package(length, i, address, (unsigned char)type) < 0) {
887             cleanup();
888             exit(1);
889         }
890     }
891 
892     fclose(outfile);
893     bin2crt_ok();
894     cleanup();
895     exit(0);
896 }
897 
save_2_blocks_crt(unsigned int l1,unsigned int l2,unsigned int a1,unsigned int a2,unsigned char game,unsigned char exrom)898 static void save_2_blocks_crt(unsigned int l1, unsigned int l2, unsigned int a1, unsigned int a2, unsigned char game, unsigned char exrom)
899 {
900     if (write_crt_header(game, exrom) < 0) {
901         cleanup();
902         exit(1);
903     }
904 
905     if (write_chip_package(0x2000, 0, 0x8000, 0) < 0) {
906         cleanup();
907         exit(1);
908     }
909 
910     if (write_chip_package(0x2000, 0, (a2 == 0xe000) ? 0xe000 : 0xa000, 0) < 0) {
911         cleanup();
912         exit(1);
913     }
914 
915     fclose(outfile);
916     bin2crt_ok();
917     cleanup();
918     exit(0);
919 }
920 
check_empty_easyflash(void)921 static int check_empty_easyflash(void)
922 {
923     int i;
924 
925     for (i = 0; i < 0x2000; i++) {
926         if (filebuffer[loadfile_offset + i] != 0xff) {
927             return 0;
928         }
929     }
930     return 1;
931 }
932 
save_easyflash_crt(unsigned int p1,unsigned int p2,unsigned int p3,unsigned int p4,unsigned char p5,unsigned char p6)933 static void save_easyflash_crt(unsigned int p1, unsigned int p2, unsigned int p3, unsigned int p4, unsigned char p5, unsigned char p6)
934 {
935     unsigned int i, j;
936 
937     if (write_crt_header(0, 0) < 0) {
938         cleanup();
939         exit(1);
940     }
941 
942     for (i = 0; i < 64; i++) {
943         for (j = 0; j < 2; j++) {
944             if ((omit_empty_banks == 1) && (check_empty_easyflash() == 1)) {
945                 loadfile_offset += 0x2000;
946             } else {
947                 if (write_chip_package(0x2000, i, (j == 0) ? 0x8000 : 0xa000, 2) < 0) {
948                     cleanup();
949                     exit(1);
950                 }
951             }
952         }
953     }
954 
955     fclose(outfile);
956     bin2crt_ok();
957     cleanup();
958     exit(0);
959 }
960 
save_ocean_crt(unsigned int p1,unsigned int p2,unsigned int p3,unsigned int p4,unsigned char p5,unsigned char p6)961 static void save_ocean_crt(unsigned int p1, unsigned int p2, unsigned int p3, unsigned int p4, unsigned char p5, unsigned char p6)
962 {
963     unsigned int i;
964 
965     if (loadfile_size != CARTRIDGE_SIZE_256KB) {
966         save_regular_crt(0x2000, 0, 0x8000, 0, 0, 0);
967     } else {
968         if (write_crt_header(1, 0) < 0) {
969             cleanup();
970             exit(1);
971         }
972 
973         for (i = 0; i < 16; i++) {
974             if (write_chip_package(0x2000, i, 0x8000, 0) < 0) {
975                 cleanup();
976                 exit(1);
977             }
978         }
979 
980         for (i = 0; i < 16; i++) {
981             if (write_chip_package(0x2000, i + 16, 0xa000, 0) < 0) {
982                 cleanup();
983                 exit(1);
984             }
985         }
986 
987         fclose(outfile);
988         bin2crt_ok();
989         cleanup();
990         exit(0);
991     }
992 }
993 
save_funplay_crt(unsigned int p1,unsigned int p2,unsigned int p3,unsigned int p4,unsigned char p5,unsigned char p6)994 static void save_funplay_crt(unsigned int p1, unsigned int p2, unsigned int p3, unsigned int p4, unsigned char p5, unsigned char p6)
995 {
996     unsigned int i = 0;
997 
998     if (write_crt_header(1, 0) < 0) {
999         cleanup();
1000         exit(1);
1001     }
1002 
1003     while (i != 0x41) {
1004         if (write_chip_package(0x2000, i, 0x8000, 0) < 0) {
1005             cleanup();
1006             exit(1);
1007         }
1008         i += 8;
1009         if (i == 0x40) {
1010             i = 1;
1011         }
1012     }
1013 
1014     fclose(outfile);
1015     bin2crt_ok();
1016     cleanup();
1017     exit(0);
1018 }
1019 
save_easycalc_crt(unsigned int p1,unsigned int p2,unsigned int p3,unsigned int p4,unsigned char p5,unsigned char p6)1020 static void save_easycalc_crt(unsigned int p1, unsigned int p2, unsigned int p3, unsigned int p4, unsigned char p5, unsigned char p6)
1021 {
1022     if (write_crt_header(1, 1) < 0) {
1023         cleanup();
1024         exit(1);
1025     }
1026 
1027     if (write_chip_package(0x2000, 0, 0x8000, 0) < 0) {
1028         cleanup();
1029         exit(1);
1030     }
1031 
1032     if (write_chip_package(0x2000, 0, 0xa000, 0) < 0) {
1033         cleanup();
1034         exit(1);
1035     }
1036 
1037     if (write_chip_package(0x2000, 1, 0xa000, 0) < 0) {
1038         cleanup();
1039         exit(1);
1040     }
1041 
1042     fclose(outfile);
1043     bin2crt_ok();
1044     cleanup();
1045     exit(0);
1046 }
1047 
save_zaxxon_crt(unsigned int p1,unsigned int p2,unsigned int p3,unsigned int p4,unsigned char p5,unsigned char p6)1048 static void save_zaxxon_crt(unsigned int p1, unsigned int p2, unsigned int p3, unsigned int p4, unsigned char p5, unsigned char p6)
1049 {
1050     if (write_crt_header(0, 0) < 0) {
1051         cleanup();
1052         exit(1);
1053     }
1054 
1055     if (write_chip_package(0x1000, 0, 0x8000, 0) < 0) {
1056         cleanup();
1057         exit(1);
1058     }
1059 
1060     if (write_chip_package(0x2000, 0, 0xa000, 0) < 0) {
1061         cleanup();
1062         exit(1);
1063     }
1064 
1065     if (write_chip_package(0x2000, 1, 0xa000, 0) < 0) {
1066         cleanup();
1067         exit(1);
1068     }
1069 
1070     fclose(outfile);
1071     bin2crt_ok();
1072     cleanup();
1073     exit(0);
1074 }
1075 
save_stardos_crt(unsigned int p1,unsigned int p2,unsigned int p3,unsigned int p4,unsigned char p5,unsigned char p6)1076 static void save_stardos_crt(unsigned int p1, unsigned int p2, unsigned int p3, unsigned int p4, unsigned char p5, unsigned char p6)
1077 {
1078     if (write_crt_header(1, 0) < 0) {
1079         cleanup();
1080         exit(1);
1081     }
1082 
1083     if (write_chip_package(0x2000, 0, 0x8000, 0) < 0) {
1084         cleanup();
1085         exit(1);
1086     }
1087 
1088     if (write_chip_package(0x2000, 0, 0xe000, 0) < 0) {
1089         cleanup();
1090         exit(1);
1091     }
1092 
1093     fclose(outfile);
1094     bin2crt_ok();
1095     cleanup();
1096     exit(0);
1097 }
1098 
load_input_file(char * filename)1099 static int load_input_file(char *filename)
1100 {
1101     loadfile_offset = 0;
1102     infile = fopen(filename, "rb");
1103     if (infile == NULL) {
1104         fprintf(stderr, "Error: Can't open %s\n", filename);
1105         return -1;
1106     }
1107     if (fread(filebuffer, 1, 16, infile) != 16) {
1108         fprintf(stderr, "Error: Can't read %s\n", filename);
1109         fclose(infile);
1110         return -1;
1111     }
1112     if (!strncmp("C64 CARTRIDGE   ", (char *)filebuffer, 16)) {
1113         loadfile_is_crt = 1;
1114         if (fread(headerbuffer + 0x10, 1, 0x30, infile) != 0x30) {
1115             fprintf(stderr, "Error: Can't read the full header of %s\n", filename);
1116             fclose(infile);
1117             return -1;
1118         }
1119         if (headerbuffer[0x10] != 0 || headerbuffer[0x11] != 0 || headerbuffer[0x12] != 0 || headerbuffer[0x13] != 0x40) {
1120             fprintf(stderr, "Error: Illegal header size in %s\n", filename);
1121             if (!repair_mode) {
1122                 fclose(infile);
1123                 return -1;
1124             }
1125         }
1126         if (headerbuffer[0x18] == 1 && headerbuffer[0x19] == 0) {
1127             loadfile_is_ultimax = 1;
1128         } else {
1129             loadfile_is_ultimax = 0;
1130         }
1131 
1132         loadfile_cart_type = headerbuffer[0x17] + (headerbuffer[0x16] << 8);
1133         if (headerbuffer[0x17] & 0x80) {
1134             /* handle our negative test IDs */
1135             loadfile_cart_type -= 0x10000;
1136         }
1137         if (!((loadfile_cart_type >= 0) && (loadfile_cart_type <= CARTRIDGE_LAST))) {
1138             fprintf(stderr, "Error: Unknown CRT ID: %d\n", loadfile_cart_type);
1139             fclose(infile);
1140             return -1;
1141         }
1142 
1143         loadfile_size = 0;
1144         if (load_all_banks() < 0) {
1145             if (repair_mode) {
1146                 fprintf(stderr, "Warning: Can't load all banks of %s\n", filename);
1147                 fclose(infile);
1148                 return 0;
1149             } else {
1150                 fprintf(stderr, "Error: Can't load all banks of %s (use -r to force)\n", filename);
1151                 fclose(infile);
1152                 return -1;
1153             }
1154         } else {
1155             fclose(infile);
1156             return 0;
1157         }
1158     } else {
1159         loadfile_is_crt = 0;
1160         loadfile_size = (unsigned int)fread(filebuffer + 0x10, 1, 0x100000 - 14, infile) + 0x10;
1161         switch (loadfile_size) {
1162             case CARTRIDGE_SIZE_4KB:
1163             case CARTRIDGE_SIZE_8KB:
1164             case CARTRIDGE_SIZE_12KB:
1165             case CARTRIDGE_SIZE_16KB:
1166             case CARTRIDGE_SIZE_20KB:
1167             case CARTRIDGE_SIZE_24KB:
1168             case CARTRIDGE_SIZE_32KB:
1169             case CARTRIDGE_SIZE_64KB:
1170             case CARTRIDGE_SIZE_96KB:
1171             case CARTRIDGE_SIZE_128KB:
1172             case CARTRIDGE_SIZE_256KB:
1173             case CARTRIDGE_SIZE_512KB:
1174             case CARTRIDGE_SIZE_1024KB:
1175                 loadfile_offset = 0;
1176                 fclose(infile);
1177                 return 0;
1178                 break;
1179             case CARTRIDGE_SIZE_4KB + 2:
1180             case CARTRIDGE_SIZE_8KB + 2:
1181             case CARTRIDGE_SIZE_12KB + 2:
1182             case CARTRIDGE_SIZE_16KB + 2:
1183             case CARTRIDGE_SIZE_20KB + 2:
1184             case CARTRIDGE_SIZE_24KB + 2:
1185             case CARTRIDGE_SIZE_32KB + 2:
1186             case CARTRIDGE_SIZE_64KB + 2:
1187             case CARTRIDGE_SIZE_96KB + 2:
1188             case CARTRIDGE_SIZE_128KB + 2:
1189             case CARTRIDGE_SIZE_256KB + 2:
1190             case CARTRIDGE_SIZE_512KB + 2:
1191             case CARTRIDGE_SIZE_1024KB + 2:
1192                 loadfile_size -= 2;
1193                 loadfile_offset = 2;
1194                 fclose(infile);
1195                 return 0;
1196                 break;
1197             case CARTRIDGE_SIZE_32KB + 4:
1198                 loadfile_size -= 4;
1199                 loadfile_offset = 4;
1200                 fclose(infile);
1201                 return 0;
1202                 break;
1203             default:
1204                 fclose(infile);
1205                 if (input_padding) {
1206                     return 0;
1207                 }
1208                 fprintf(stderr, "Error: Illegal file size of %s\n", filename);
1209                 return -1;
1210                 break;
1211         }
1212     }
1213 }
1214 
close_output_cleanup(void)1215 static void close_output_cleanup(void)
1216 {
1217     fclose(outfile);
1218     unlink(output_filename);
1219     cleanup();
1220     exit(1);
1221 }
1222 
save_delaep64_crt(unsigned int p1,unsigned int p2,unsigned int p3,unsigned int p4,unsigned char p5,unsigned char p6)1223 static void save_delaep64_crt(unsigned int p1, unsigned int p2, unsigned int p3, unsigned int p4, unsigned char p5, unsigned char p6)
1224 {
1225     unsigned int i;
1226 
1227     if (loadfile_size != CARTRIDGE_SIZE_8KB) {
1228         fprintf(stderr, "Error: wrong size of Dela EP64 base file %s (%d)\n", input_filename[0], loadfile_size);
1229         cleanup();
1230         exit(1);
1231     }
1232 
1233     if (write_crt_header(1, 0) < 0) {
1234         cleanup();
1235         exit(1);
1236     }
1237 
1238     /* write base file */
1239     if (write_chip_package(0x2000, 0, 0x8000, 0) < 0) {
1240         cleanup();
1241         exit(1);
1242     }
1243 
1244     if (input_filenames > 1) {
1245         /* write user eproms */
1246         for (i = 0; i < input_filenames; i++) {
1247             if (load_input_file(input_filename[i]) < 0) {
1248                 close_output_cleanup();
1249             }
1250             if (loadfile_is_crt == 1) {
1251                 fprintf(stderr, "Error: to be inserted file can only be a binary for Dela EP64\n");
1252                 close_output_cleanup();
1253             }
1254             if (loadfile_size != CARTRIDGE_SIZE_32KB) {
1255                 fprintf(stderr, "Error: to be inserted file can only be 32KB in size for Dela EP64\n");
1256                 close_output_cleanup();
1257             }
1258             if (write_chip_package(0x8000, i + 1, 0x8000, 0) < 0) {
1259                 close_output_cleanup();
1260             }
1261         }
1262     }
1263 
1264     fclose(outfile);
1265     bin2crt_ok();
1266     cleanup();
1267     exit(0);
1268 }
1269 
save_delaep256_crt(unsigned int p1,unsigned int p2,unsigned int p3,unsigned int p4,unsigned char p5,unsigned char p6)1270 static void save_delaep256_crt(unsigned int p1, unsigned int p2, unsigned int p3, unsigned int p4, unsigned char p5, unsigned char p6)
1271 {
1272     unsigned int i, j;
1273     unsigned int insert_size = 0;
1274 
1275     if (loadfile_size != CARTRIDGE_SIZE_8KB) {
1276         fprintf(stderr, "Error: wrong size of Dela EP256 base file %s (%d)\n", input_filename[0], loadfile_size);
1277         cleanup();
1278         exit(1);
1279     }
1280 
1281     if (input_filenames == 1) {
1282         fprintf(stderr, "Error: no files to insert into Dela EP256 .crt\n");
1283         cleanup();
1284         exit(1);
1285     }
1286 
1287     if (write_crt_header(1, 0) < 0) {
1288         cleanup();
1289         exit(1);
1290     }
1291 
1292     if (write_chip_package(0x2000, 0, 0x8000, 0) < 0) {
1293         cleanup();
1294         exit(1);
1295     }
1296 
1297     for (i = 0; i < (unsigned int)input_filenames - 1; i++) {
1298         if (load_input_file(input_filename[i + 1]) < 0) {
1299             close_output_cleanup();
1300         }
1301 
1302         if (loadfile_size != CARTRIDGE_SIZE_32KB && loadfile_size != CARTRIDGE_SIZE_8KB) {
1303             fprintf(stderr, "Error: only 32KB binary files or 8KB bin/crt files can be inserted in Dela EP256\n");
1304             close_output_cleanup();
1305         }
1306 
1307         if (insert_size == 0) {
1308             insert_size = loadfile_size;
1309         }
1310 
1311         if (insert_size == CARTRIDGE_SIZE_32KB && input_filenames > 8) {
1312             fprintf(stderr, "Error: a maximum of 8 32KB images can be inserted\n");
1313             close_output_cleanup();
1314         }
1315 
1316         if (insert_size != loadfile_size) {
1317             fprintf(stderr, "Error: only one type of insertion is allowed at this time for Dela EP256\n");
1318             close_output_cleanup();
1319         }
1320 
1321         if (loadfile_is_crt == 1 && (loadfile_size != CARTRIDGE_SIZE_8KB || load_address != 0x8000 || loadfile_is_ultimax == 1)) {
1322             fprintf(stderr, "Error: you can only insert generic 8KB .crt files for Dela EP256\n");
1323             close_output_cleanup();
1324         }
1325 
1326         if (insert_size == CARTRIDGE_SIZE_32KB) {
1327             for (j = 0; j < 4; j++) {
1328                 if (write_chip_package(0x2000, (i * 4) + j + 1, 0x8000, 0) < 0) {
1329                     close_output_cleanup();
1330                 }
1331             }
1332             if (!quiet_mode) {
1333                 printf("inserted %s in banks %d-%d of the Dela EP256 .crt\n", input_filename[i + 1], (i * 4) + 1, (i * 4) + 4);
1334             }
1335         } else {
1336             if (write_chip_package(0x2000, i + 1, 0x8000, 0) < 0) {
1337                 close_output_cleanup();
1338             }
1339             if (!quiet_mode) {
1340                 printf("inserted %s in bank %d of the Dela EP256 .crt\n", input_filename[i + 1], i + 1);
1341             }
1342         }
1343     }
1344 
1345     fclose(outfile);
1346     bin2crt_ok();
1347     cleanup();
1348     exit(0);
1349 }
1350 
save_delaep7x8_crt(unsigned int p1,unsigned int p2,unsigned int p3,unsigned int p4,unsigned char p5,unsigned char p6)1351 static void save_delaep7x8_crt(unsigned int p1, unsigned int p2, unsigned int p3, unsigned int p4, unsigned char p5, unsigned char p6)
1352 {
1353     int inserted_size = 0;
1354     int name_counter = 1;
1355     unsigned int chip_counter = 1;
1356 
1357     if (loadfile_size != CARTRIDGE_SIZE_8KB) {
1358         fprintf(stderr, "Error: wrong size of Dela EP7x8 base file %s (%d)\n", input_filename[0], loadfile_size);
1359         cleanup();
1360         exit(1);
1361     }
1362 
1363     if (input_filenames == 1) {
1364         fprintf(stderr, "Error: no files to insert into Dela EP7x8 .crt\n");
1365         cleanup();
1366         exit(1);
1367     }
1368 
1369     if (write_crt_header(1, 0) < 0) {
1370         cleanup();
1371         exit(1);
1372     }
1373 
1374     if (write_chip_package(0x2000, 0, 0x8000, 0) < 0) {
1375         cleanup();
1376         exit(1);
1377     }
1378 
1379     while (name_counter != input_filenames) {
1380         if (load_input_file(input_filename[name_counter]) < 0) {
1381             close_output_cleanup();
1382         }
1383 
1384         if (loadfile_size == CARTRIDGE_SIZE_32KB) {
1385             if (loadfile_is_crt == 1) {
1386                 fprintf(stderr, "Error: (%s) only binary 32KB images can be inserted into a Dela EP7x8 .crt\n",
1387                         input_filename[name_counter]);
1388                 close_output_cleanup();
1389             } else {
1390                 if (inserted_size != 0) {
1391                     fprintf(stderr, "Error: (%s) only the first inserted image can be a 32KB image for Dela EP7x8\n",
1392                             input_filename[name_counter]);
1393                     close_output_cleanup();
1394                 } else {
1395                     if (write_chip_package(0x2000, chip_counter, 0x8000, 0) < 0) {
1396                         close_output_cleanup();
1397                     }
1398                     if (write_chip_package(0x2000, chip_counter + 1, 0x8000, 0) < 0) {
1399                         close_output_cleanup();
1400                     }
1401                     if (write_chip_package(0x2000, chip_counter + 2, 0x8000, 0) < 0) {
1402                         close_output_cleanup();
1403                     }
1404                     if (write_chip_package(0x2000, chip_counter + 3, 0x8000, 0) < 0) {
1405                         close_output_cleanup();
1406                     }
1407                     if (!quiet_mode) {
1408                         printf("inserted %s in banks %d-%d of the Dela EP7x8 .crt\n",
1409                                input_filename[name_counter], chip_counter, chip_counter + 3);
1410                     }
1411                     chip_counter += 4;
1412                     inserted_size += 0x8000;
1413                 }
1414             }
1415         }
1416 
1417         if (loadfile_size == CARTRIDGE_SIZE_16KB) {
1418             if (loadfile_is_crt == 1 && (loadfile_cart_type != 0 || loadfile_is_ultimax == 1)) {
1419                 fprintf(stderr, "Error: (%s) only generic 16KB .crt images can be inserted into a Dela EP7x8 .crt\n",
1420                         input_filename[name_counter]);
1421                 close_output_cleanup();
1422             } else {
1423                 if (inserted_size >= 0xc000) {
1424                     fprintf(stderr, "Error: (%s) no room to insert a 16KB binary file into the Dela EP7x8 .crt\n",
1425                             input_filename[name_counter]);
1426                     close_output_cleanup();
1427                 } else {
1428                     if (write_chip_package(0x2000, chip_counter, 0x8000, 0) < 0) {
1429                         close_output_cleanup();
1430                     }
1431                     if (write_chip_package(0x2000, chip_counter + 1, 0x8000, 0) < 0) {
1432                         close_output_cleanup();
1433                     }
1434                     if (!quiet_mode) {
1435                         printf("inserted %s in banks %d and %d of the Dela EP7x8 .crt\n",
1436                                input_filename[name_counter], chip_counter, chip_counter + 1);
1437                     }
1438                     chip_counter += 2;
1439                     inserted_size += 0x4000;
1440                 }
1441             }
1442         }
1443 
1444         if (loadfile_size == CARTRIDGE_SIZE_8KB) {
1445             if (loadfile_is_crt == 1 && (loadfile_cart_type != 0 || loadfile_is_ultimax == 1)) {
1446                 fprintf(stderr, "Error: (%s) only generic 8KB .crt images can be inserted into a Dela EP7x8 .crt\n",
1447                         input_filename[name_counter]);
1448                 close_output_cleanup();
1449             } else {
1450                 if (inserted_size >= 0xe000) {
1451                     fprintf(stderr, "Error: (%s) no room to insert a 8KB binary file into the Dela EP7x8 .crt\n",
1452                             input_filename[name_counter]);
1453                     close_output_cleanup();
1454                 } else {
1455                     if (write_chip_package(0x2000, chip_counter, 0x8000, 0) < 0) {
1456                         close_output_cleanup();
1457                     }
1458                     if (!quiet_mode) {
1459                         printf("inserted %s in bank %d of the Dela EP7x8 .crt\n", input_filename[name_counter], chip_counter);
1460                     }
1461                     chip_counter++;
1462                     inserted_size += 0x2000;
1463                 }
1464             }
1465         }
1466 
1467         name_counter++;
1468     }
1469 
1470     fclose(outfile);
1471     bin2crt_ok();
1472     cleanup();
1473     exit(0);
1474 }
1475 
save_rexep256_crt(unsigned int p1,unsigned int p2,unsigned int p3,unsigned int p4,unsigned char p5,unsigned char p6)1476 static void save_rexep256_crt(unsigned int p1, unsigned int p2, unsigned int p3, unsigned int p4, unsigned char p5, unsigned char p6)
1477 {
1478     int eprom_size_for_8kb = 0;
1479     int images_of_8kb_started = 0;
1480     int name_counter = 1;
1481     unsigned int chip_counter = 1;
1482     int subchip_counter = 1;
1483 
1484     if (loadfile_size != CARTRIDGE_SIZE_8KB) {
1485         fprintf(stderr, "Error: wrong size of Rex EP256 base file %s (%d)\n", input_filename[0], loadfile_size);
1486         cleanup();
1487         exit(1);
1488     }
1489 
1490     if (input_filenames == 1) {
1491         fprintf(stderr, "Error: no files to insert into Rex EP256 .crt\n");
1492         cleanup();
1493         exit(1);
1494     }
1495 
1496     if (write_crt_header(1, 0) < 0) {
1497         cleanup();
1498         exit(1);
1499     }
1500 
1501     if (write_chip_package(0x2000, 0, 0x8000, 0) < 0) {
1502         cleanup();
1503         exit(1);
1504     }
1505 
1506     while (name_counter != input_filenames) {
1507         if (load_input_file(input_filename[name_counter]) < 0) {
1508             close_output_cleanup();
1509         }
1510 
1511         if (chip_counter > 8) {
1512             fprintf(stderr, "Error: no more room for %s in the Rex EP256 .crt\n", input_filename[name_counter]);
1513         }
1514 
1515         if (loadfile_size == CARTRIDGE_SIZE_32KB) {
1516             if (loadfile_is_crt == 1) {
1517                 fprintf(stderr, "Error: (%s) only binary 32KB images can be inserted into a Rex EP256 .crt\n",
1518                         input_filename[name_counter]);
1519                 close_output_cleanup();
1520             } else {
1521                 if (images_of_8kb_started != 0) {
1522                     fprintf(stderr, "Error: (%s) only the first inserted images can be a 32KB image for Rex EP256\n",
1523                             input_filename[name_counter]);
1524                     close_output_cleanup();
1525                 } else {
1526                     if (write_chip_package(0x8000, chip_counter, 0x8000, 0) < 0) {
1527                         close_output_cleanup();
1528                     }
1529                     if (!quiet_mode) {
1530                         printf("inserted %s in bank %d as a 32KB eprom of the Rex EP256 .crt\n",
1531                                input_filename[name_counter], chip_counter);
1532                     }
1533                     chip_counter++;
1534                 }
1535             }
1536         }
1537 
1538         if (loadfile_size == CARTRIDGE_SIZE_8KB) {
1539             if (loadfile_is_crt == 1 && (loadfile_cart_type != 0 || loadfile_is_ultimax == 1)) {
1540                 fprintf(stderr, "Error: (%s) only generic 8KB .crt images can be inserted into a Rex EP256 .crt\n",
1541                         input_filename[name_counter]);
1542                 close_output_cleanup();
1543             } else {
1544                 if (images_of_8kb_started == 0) {
1545                     images_of_8kb_started = 1;
1546                     if ((9 - chip_counter) * 4 < (unsigned int)(input_filenames - name_counter)) {
1547                         fprintf(stderr, "Error: no room for the amount of input files given\n");
1548                         close_output_cleanup();
1549                     }
1550                     eprom_size_for_8kb = 1;
1551                     if ((9 - chip_counter) * 2 < (unsigned int)(input_filenames - name_counter)) {
1552                         eprom_size_for_8kb = 4;
1553                     }
1554                     if (9 - chip_counter < (unsigned int)(input_filenames - name_counter)) {
1555                         eprom_size_for_8kb = 2;
1556                     }
1557                 }
1558 
1559                 if (eprom_size_for_8kb == 1) {
1560                     if (write_chip_package(0x2000, chip_counter, 0x8000, 0) < 0) {
1561                         close_output_cleanup();
1562                         if (!quiet_mode) {
1563                             printf("inserted %s as an 8KB eprom in bank %d of the Rex EP256 .crt\n",
1564                                    input_filename[name_counter], chip_counter);
1565                         }
1566                         chip_counter++;
1567                     }
1568 
1569                     if (eprom_size_for_8kb == 4 && (subchip_counter == 4 || name_counter == input_filenames - 1)) {
1570                         memcpy(extra_buffer_32kb + ((subchip_counter - 1) * 0x2000), filebuffer + loadfile_offset, 0x2000);
1571                         memcpy(filebuffer, extra_buffer_32kb, 0x8000);
1572                         loadfile_offset = 0;
1573                         if (write_chip_package(0x8000, chip_counter, 0x8000, 0) < 0) {
1574                             close_output_cleanup();
1575                         }
1576                         if (!quiet_mode) {
1577                             if (subchip_counter == 1) {
1578                                 printf("inserted %s as a 32KB eprom in bank %d of the Rex EP256 .crt\n",
1579                                        input_filename[name_counter], chip_counter);
1580                             } else {
1581                                 printf(" and %s as a 32KB eprom in bank %d of the Rex EP256 .crt\n",
1582                                        input_filename[name_counter], chip_counter);
1583                             }
1584                         }
1585                         chip_counter++;
1586                         subchip_counter = 1;
1587                     }
1588 
1589                     if (eprom_size_for_8kb == 4 && (subchip_counter == 3 || subchip_counter == 2) &&
1590                         name_counter != input_filenames) {
1591                         memcpy(extra_buffer_32kb + ((subchip_counter - 1) * 0x2000), filebuffer + loadfile_offset, 0x2000);
1592                         if (!quiet_mode) {
1593                             printf(", %s", input_filename[name_counter]);
1594                         }
1595                         subchip_counter++;
1596                     }
1597 
1598                     if (eprom_size_for_8kb == 2) {
1599                         if (subchip_counter == 2 || name_counter == input_filenames - 1) {
1600                             memcpy(extra_buffer_32kb + ((subchip_counter - 1) * 0x2000),
1601                                    filebuffer + loadfile_offset, 0x2000);
1602                             memcpy(filebuffer, extra_buffer_32kb, 0x4000);
1603                             loadfile_offset = 0;
1604                             if (write_chip_package(0x4000, chip_counter, 0x8000, 0) < 0) {
1605                                 close_output_cleanup();
1606                             }
1607                             if (!quiet_mode) {
1608                                 if (subchip_counter == 1) {
1609                                     printf("inserted %s as a 16KB eprom in bank %d of the Rex EP256 .crt\n",
1610                                            input_filename[name_counter], chip_counter);
1611                                 } else {
1612                                     printf(" and %s as a 16KB eprom in bank %d of the Rex EP256 .crt\n",
1613                                            input_filename[name_counter], chip_counter);
1614                                 }
1615                             }
1616                             chip_counter++;
1617                             subchip_counter = 1;
1618                         } else {
1619                             memcpy(extra_buffer_32kb, filebuffer + loadfile_offset, 0x2000);
1620                             if (!quiet_mode) {
1621                                 printf("inserted %s", input_filename[name_counter]);
1622                             }
1623                             subchip_counter++;
1624                         }
1625                     }
1626 
1627                     if (eprom_size_for_8kb == 4 && subchip_counter == 1 && name_counter != input_filenames) {
1628                         memcpy(extra_buffer_32kb, filebuffer + loadfile_offset, 0x2000);
1629                         if (!quiet_mode) {
1630                             printf("inserted %s", input_filename[name_counter]);
1631                         }
1632                         subchip_counter++;
1633                     }
1634                 }
1635             }
1636         }
1637         name_counter++;
1638     }
1639 
1640     fclose(outfile);
1641     bin2crt_ok();
1642     cleanup();
1643     exit(0);
1644 }
1645 
save_generic_crt(unsigned int p1,unsigned int p2,unsigned int p3,unsigned int p4,unsigned char p5,unsigned char p6)1646 static void save_generic_crt(unsigned int p1, unsigned int p2, unsigned int p3, unsigned int p4, unsigned char p5, unsigned char p6)
1647 {
1648     /* printf("save_generic_crt ultimax: %d size: %08x\n", convert_to_ultimax, loadfile_size); */
1649     if (convert_to_ultimax == 1) {
1650         switch (loadfile_size) {
1651             case CARTRIDGE_SIZE_4KB:
1652                 save_regular_crt(0x1000, 1, 0xf000, 0, 0, 1);
1653                 break;
1654             case CARTRIDGE_SIZE_8KB:
1655                 save_regular_crt(0x2000, 1, 0xe000, 0, 0, 1);
1656                 break;
1657             case CARTRIDGE_SIZE_16KB:
1658                 save_2_blocks_crt(0x2000, 0x2000, 0x8000, 0xe000, 0, 1);
1659                 break;
1660             default:
1661                 break;
1662         }
1663     } else {
1664         switch (loadfile_size) {
1665             case CARTRIDGE_SIZE_4KB:
1666                 save_regular_crt(0x1000, 0, 0x8000, 0, 1, 0);
1667                 break;
1668             case CARTRIDGE_SIZE_8KB:
1669                 save_regular_crt(0x2000, 0, 0x8000, 0, 1, 0);
1670                 break;
1671             case CARTRIDGE_SIZE_12KB:
1672                 save_regular_crt(0x3000, 1, 0x8000, 0, 0, 0);
1673                 break;
1674             case CARTRIDGE_SIZE_16KB:
1675                 save_regular_crt(0x4000, 1, 0x8000, 0, 0, 0);
1676                 break;
1677             default:
1678                 break;
1679         }
1680     }
1681 }
1682 
main(int argc,char * argv[])1683 int main(int argc, char *argv[])
1684 {
1685     int i;
1686     int arg_counter = 1;
1687     char *flag, *argument;
1688 
1689     if (argc > 1) {
1690         if(strcmp(argv[1], "--types") == 0) {
1691             usage_types();
1692             return EXIT_SUCCESS;
1693         } else if (strcmp(argv[1], "--version") == 0) {
1694             dump_version();
1695             return EXIT_SUCCESS;
1696         }
1697     }
1698 
1699     if (argc < 3) {
1700         usage();
1701         return EXIT_FAILURE;
1702     }
1703 
1704     for (i = 0; i < 33; i++) {
1705         input_filename[i] = NULL;
1706     }
1707 
1708     while (arg_counter < argc) {
1709         flag = argv[arg_counter];
1710         argument = (arg_counter + 1 < argc) ? argv[arg_counter + 1] : NULL;
1711         if (flag[0] != '-') {
1712             usage();
1713         } else {
1714             arg_counter += checkflag(flag, argument);
1715         }
1716     }
1717 
1718     if (output_filename == NULL) {
1719         fprintf(stderr, "Error: no output filename\n");
1720         cleanup();
1721         exit(1);
1722     }
1723     if (input_filenames == 0) {
1724         fprintf(stderr, "Error: no input filename\n");
1725         cleanup();
1726         exit(1);
1727     }
1728     if (!strcmp(output_filename, input_filename[0])) {
1729         fprintf(stderr, "Error: output filename = input filename\n");
1730         cleanup();
1731         exit(1);
1732     }
1733     if (load_input_file(input_filename[0]) < 0) {
1734         cleanup();
1735         exit(1);
1736     }
1737     if (input_filenames > 1 && cart_type != CARTRIDGE_DELA_EP64 && cart_type != CARTRIDGE_DELA_EP256 &&
1738         cart_type != CARTRIDGE_DELA_EP7x8 && cart_type != CARTRIDGE_REX_EP256 && loadfile_cart_type != CARTRIDGE_DELA_EP64 &&
1739         loadfile_cart_type != CARTRIDGE_DELA_EP256 && loadfile_cart_type != CARTRIDGE_DELA_EP7x8 &&
1740         loadfile_cart_type != CARTRIDGE_REX_EP256) {
1741         too_many_inputs();
1742     }
1743     if ((cart_type == CARTRIDGE_DELA_EP64 || loadfile_cart_type == CARTRIDGE_DELA_EP64) && input_filenames > 3) {
1744         too_many_inputs();
1745     }
1746     if ((cart_type == CARTRIDGE_DELA_EP7x8 || loadfile_cart_type == CARTRIDGE_DELA_EP7x8) && input_filenames > 8) {
1747         too_many_inputs();
1748     }
1749     if (loadfile_is_crt == 1) {
1750         if (cart_type == CARTRIDGE_DELA_EP64 || cart_type == CARTRIDGE_DELA_EP256 || cart_type == CARTRIDGE_DELA_EP7x8 ||
1751             cart_type == CARTRIDGE_REX_EP256) {
1752             cart_info[(unsigned char)cart_type].save(0, 0, 0, 0, 0, 0);
1753         } else {
1754             if (cart_type == -1) {
1755                 if (save_binary_output_file() < 0) {
1756                     cleanup();
1757                     exit(1);
1758                 }
1759             } else {
1760                 fprintf(stderr, "Error: File is already .crt format\n");
1761                 cleanup();
1762                 exit(1);
1763             }
1764         }
1765     } else {
1766         if (cart_type == -1) {
1767             fprintf(stderr, "Error: File is already in binary format\n");
1768             cleanup();
1769             exit(1);
1770         }
1771         /* FIXME: the sizes are used in a bitfield, and also by their absolute values. this
1772                   check is doomed to fail because of that :)
1773         */
1774         if (input_padding) {
1775             while ((loadfile_size & cart_info[(unsigned char)cart_type].sizes) != loadfile_size) {
1776                 loadfile_size++;
1777             }
1778         } else {
1779             if ((loadfile_size & cart_info[(unsigned char)cart_type].sizes) != loadfile_size) {
1780                 fprintf(stderr, "Error: Input file size (%d) doesn't match %s requirements\n",
1781                         loadfile_size, cart_info[(unsigned char)cart_type].name);
1782                 cleanup();
1783                 exit(1);
1784             }
1785         }
1786         if (cart_info[(unsigned char)cart_type].save != NULL) {
1787             cart_info[(unsigned char)cart_type].save(cart_info[(unsigned char)cart_type].bank_size,
1788                                                      cart_info[(unsigned char)cart_type].banks,
1789                                                      cart_info[(unsigned char)cart_type].load_address,
1790                                                      cart_info[(unsigned char)cart_type].data_type,
1791                                                      cart_info[(unsigned char)cart_type].game,
1792                                                      cart_info[(unsigned char)cart_type].exrom);
1793         }
1794     }
1795     return 0;
1796 }
1797