This has been sitting around my hard drive for several weeks, and the
recent mention i saw of someone else working on a rom merger prompted me
to release it... Feel free to include this in the xmame distribution if
desired.
Right now it makes no attempt to remove unneeded files from within a zip,
or correct filenames, but it does strip out unneeded paths and makes names
lowercase, as well as changing them to mode 644 before repacking. It also
skips over any archives/files that happened to be in the same directory
which didnt show up on listinfo (useful if you've downloaded roms for some
other emulator and they've accidentally made their way into your mame dir
by mistake. heh.)
I ran this safely on my rom collection. No neogeo roms in the directory
though. Its not actually desirable to merge the neogeo bios and roms all
together, which i suspect is what'd happen. So for now, probably best to
keep the neogeo games in their own seperate directory for now. (Expect a
simpler 'repack only with no merge' option for handling that directory
soon...)
Basically, it takes a listinfo file. Place in current dir with the roms,
make sure the temp and output dirs are properly defined and present, and
let it go. You may want to redirect the output to a file so you can review
the statistics and warnings later. Anyway, it creates a batch file which
should unzip each game and its clones, and repacks them all into a single
zip... Ignore messages about zip files that are not present (this happens
when the roms for the clone were already in the master file, perhaps I'll
stick an additional check in here later not to generate an unzip request
for missing archives)...
Yes, the code DOES make an incredible lot of assumptions about the layout
of the output of both unzip and xmame. Lets face it, its not overly likely
to change, and if it does the corrections will amount to less code
overhead than any more flexible parser. I'll fix it if it breaks, I'm
using it myself as of the past couple mame releases to repack new rom
arrivals...
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define OUT "/e/out"
#define TMP "/tmp/romprocess"
struct Game
{
unsigned char name[9];
unsigned char parent[9];
unsigned int hasclone, isclone;
struct Rom *roms;
struct Game *next;
};
struct Rom
{
unsigned char name[13];
unsigned long size, crc;
unsigned int present, invert;
struct Rom *next;
};
int main()
{
FILE *listinfo;
struct Game *head=0, *index=0, *temp;
struct Rom *rom, *romindex;
unsigned char line[120]; // some lines are a bit long. allow plenty space
unsigned char *linepos; // for parsing roms
unsigned int gamecount=0, romcount, romtotal=0, removethis, removed=0;
unsigned int haveclones=0, areclones=0, found;
unsigned long crc;
listinfo=fopen("listinfo", "r");
if(listinfo==0) { printf("listinfo not found\n"); exit(-1L); }
parsing:
if(fgets(line, 119, listinfo)==0) { printf("end of listinfo reached\n");
fclose(listinfo); goto action; }
if(strncmp(line, "game", 4)) goto parsing; // discard garbage
romcount=0; romindex=0;
gamecount++; temp=index;
index=malloc(sizeof(struct Game));
index->hasclone=0; index->isclone=0; index->roms=0; index->next=0;
if(head==0) head=index;
else temp->next=index;
gathergameinfo:
if(fgets(line, 119, listinfo)==0) { printf("end of listinfo reached without closing
game record!!\n"); fclose(listinfo); goto action; }
if(strncmp(line, "\tname", 5)==0)
{
line[strlen(line)-1]=0;
printf("Game name: %s", line+6);
strcpy(index->name, line+6);
}
else if(strncmp(line, "\tromof", 6)==0)
{
line[strlen(line)-1]=0;
printf("\tParent: %s", line+7);
strcpy(index->parent, line+7); index->isclone=1; areclones++;
for(temp=head; temp; temp=temp->next)
{
if(strcmp(temp->name, index->parent)==0)
{
if (temp->hasclone==0) { temp->hasclone=1; haveclones++; }
break;
}
}
}
else if(strncmp(line, "\trom", 4)==0)
{
romcount++; romtotal++;
rom=malloc(sizeof(struct Rom));
rom->present=0; rom->next=0; rom->size=0; rom->crc=0;
// code to fill in structure
linepos=strchr(line+12, ' '); *linepos++=0; strcpy(rom->name, line+12);
if(*linepos=='m') { linepos+=6; linepos=strchr(linepos, ' ')+1; }
linepos+=5; rom->size=atol(linepos); linepos=strchr(linepos, ' ')+5;
sscanf(linepos, "%lx", &rom->crc);
if(index->roms==0) index->roms=rom;
else romindex->next=rom;
romindex=rom;
}
else if(line[0]==')') { printf("\tRoms used: %d\n", romcount); goto parsing; }
goto gathergameinfo;
action:
printf("Total...\tGames: %d\tRoms: %d\tHaveclones: %d\tAreclones %d\n",
gamecount, romtotal, haveclones, areclones);
// now let's run thru unzip -v real quick to fill in the linked list with
// what's present (based purely on crc for the moment)
listinfo=popen("unzip -v \\*.zip", "r");
ziploop1:
if (fgets(line, 119, listinfo)==0) { fclose(listinfo); goto donezip1; }
if(line[29]!='%') goto ziploop1;
sscanf(line+48, "%lx", &crc);
found=0; *(strchr(line+58, '\n'))=0;
for(index=head; index; index=index->next)
{
for(romindex=index->roms; romindex; romindex=romindex->next)
{
if(romindex->crc==crc)
{
romindex->present=1; found=1;
if(strcmp(romindex->name, line+58))
printf("Warning: crc %0lx matched filename %s (expected %s)\n",
crc, line+58, romindex->name);
}
else if(romindex->crc==~crc)
{
romindex->invert=1;
romindex->present=1; found=1;
if(strcmp(romindex->name, line+58))
printf("Warning: crc %0lx matched filename %s (expected %s)\n",
crc, line+58, romindex->name);
}
}
}
if(found==0)
printf("Warning: file %s crc %0lx did not match anything.\n", line+58, crc);
goto ziploop1;
donezip1:
// run thru the linked list and remove any game with roms missing.
// (cheat and just null-out the game title)
for(index=head; index; index=index->next)
{
removethis=0;
for(romindex=index->roms; romindex; romindex=romindex->next)
{
if(romindex->present==0 && romindex->crc)
{
if(removethis==0)
{
printf("Game %s is missing roms:\n", index->name); removethis=1;
}
printf("%s %ld %0lx\n", romindex->name, romindex->size, romindex->crc);
}
}
if(removethis)
{
printf("Removing game from list (rom(s) missing)\n");
*(index->name)=0; removed++;
}
}
printf("Games removed from list: %d\n", removed);
printf("Building batch file... standby...\n");
listinfo=fopen("processroms", "w");
fprintf(listinfo, "mkdir %s\n", TMP);
fprintf(listinfo, "TMPFILE=%s\n", TMP);
for(index=head; index; index=index->next)
{
if(*(index->name)==0 || index->isclone) continue;
fprintf(listinfo, "unzip -j -d $TMPFILE %s.zip\n", index->name);
if(index->hasclone)
{
for(temp=head; temp; temp=temp->next)
{
if(*(temp->name) && strcmp(index->name, temp->parent)==0)
{
fprintf(listinfo, "unzip -j -d $TMPFILE %s.zip\n", temp->name);
*(temp->name)=0; // mark it as being done already
}
}
}
fprintf(listinfo, "for a in $TMPFILE/*; do mv $a $TMPFILE/zxcvzxcv; mv
$TMPFILE/zxcvzxcv `echo $a|tr [:upper:] [:lower:]`; done\n");
fprintf(listinfo, "chmod 644 $TMPFILE/*\n");
fprintf(listinfo, "zip -X -9 -m -j %s/%s.zip $TMPFILE/*\n", OUT, index->name);
*(index->name)=0; // mark it as being done already
}
fprintf(listinfo, "rmdir $TMPFILE\n"); fclose(listinfo);
return 0;
}