Develop and Download Open Source Software

Browse CVS Repository

Contents of /mame32jp/mame32jp/src/romcmp.c

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.6 - (show annotations) (download) (as text)
Tue May 7 00:17:30 2002 UTC (21 years, 11 months ago) by zero
Branch: MAIN
CVS Tags: ver_0_60_1, ver0_60_2, ver0_60_3, ver0_60_4, ver0_60_5, HEAD
Changes since 1.5: +7 -2 lines
File MIME type: text/x-csrc
*** empty log message ***

1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include "unzip.h"
5 #include "osdepend.h" /* for CLIB_DECL */
6 #include <stdarg.h>
7 #ifdef macintosh
8 # include "macromcmp.h"
9 #else
10 #ifndef WIN32
11 # include <dirent.h>
12 # ifdef __sgi
13 # include <errno.h>
14 # else
15 # include <sys/errno.h>
16 # endif
17 #else
18 # include "dirent.h"
19 #endif
20 #include <sys/stat.h>
21 #endif
22
23
24 #define MAX_FILES 100
25
26 #ifndef MAX_FILENAME_LEN
27 #define MAX_FILENAME_LEN 12 /* increase this if you are using a real OS... */
28 #endif
29
30 #ifndef PATH_DELIM
31 #define PATH_DELIM '/'
32 #endif
33
34
35 /* for unzip.c */
36 void CLIB_DECL logerror(const char *text,...)
37 {
38 }
39
40
41 /* compare modes when one file is twice as long as the other */
42 /* A = All file */
43 /* 12 = 1st half */
44 /* 22 = 2nd half */
45 /* E = Even bytes */
46 /* O = Odd bytes */
47 /* E1 = Even bytes 1st half */
48 /* O1 = Odd bytes 1st half */
49 /* E2 = Even bytes 2nd half */
50 /* O2 = Odd bytes 2nd half */
51 enum { MODE_A,
52 MODE_NIB1,MODE_NIB2,
53 MODE_12, MODE_22,
54 MODE_14, MODE_24, MODE_34, MODE_44,
55 MODE_E, MODE_O,
56 MODE_E12, MODE_O12, MODE_E22, MODE_O22,
57 TOTAL_MODES };
58 char *modenames[] =
59 {
60 " ",
61 "[bits 0-3]",
62 "[bits 4-7]",
63 "[1/2] ",
64 "[2/2] ",
65 "[1/4] ",
66 "[2/4] ",
67 "[3/4] ",
68 "[4/4] ",
69 "[even] ",
70 "[odd] ",
71 "[even 1/2]",
72 "[odd 1/2] ",
73 "[even 2/2]",
74 "[odd 2/2] ",
75 };
76
77 static void compatiblemodes(int mode,int *start,int *end)
78 {
79 if (mode == MODE_A)
80 {
81 *start = MODE_A;
82 *end = MODE_A;
83 }
84 if (mode >= MODE_NIB1 && mode <= MODE_NIB2)
85 {
86 *start = MODE_NIB1;
87 *end = MODE_NIB2;
88 }
89 if (mode >= MODE_12 && mode <= MODE_22)
90 {
91 *start = MODE_12;
92 *end = MODE_22;
93 }
94 if (mode >= MODE_14 && mode <= MODE_44)
95 {
96 *start = MODE_14;
97 *end = MODE_44;
98 }
99 if (mode >= MODE_E && mode <= MODE_O)
100 {
101 *start = MODE_E;
102 *end = MODE_O;
103 }
104 if (mode >= MODE_E12 && mode <= MODE_O22)
105 {
106 *start = MODE_E12;
107 *end = MODE_O22;
108 }
109 }
110
111 struct fileinfo
112 {
113 char name[MAX_FILENAME_LEN+1];
114 int size;
115 unsigned char *buf; /* file is read in here */
116 int listed;
117 };
118
119 struct fileinfo files[2][MAX_FILES];
120 float matchscore[MAX_FILES][MAX_FILES][TOTAL_MODES][TOTAL_MODES];
121
122
123 static void checkintegrity(const struct fileinfo *file,int side)
124 {
125 int i;
126 int mask0,mask1;
127 int addrbit;
128
129 if (file->buf == 0) return;
130
131 /* check for bad data lines */
132 mask0 = 0x0000;
133 mask1 = 0xffff;
134
135 for (i = 0;i < file->size;i+=2)
136 {
137 mask0 |= ((file->buf[i] << 8) | file->buf[i+1]);
138 mask1 &= ((file->buf[i] << 8) | file->buf[i+1]);
139 if (mask0 == 0xffff && mask1 == 0x0000) break;
140 }
141
142 if (mask0 != 0xffff || mask1 != 0x0000)
143 {
144 int fixedmask;
145 int bits;
146
147
148 fixedmask = (~mask0 | mask1) & 0xffff;
149
150 if (((mask0 >> 8) & 0xff) == (mask0 & 0xff) && ((mask1 >> 8) & 0xff) == (mask1 & 0xff))
151 bits = 8;
152 else bits = 16;
153
154 printf("%-23s %-23s FIXED BITS (",side ? "" : file->name,side ? file->name : "");
155 for (i = 0;i < bits;i++)
156 {
157 if (~mask0 & 0x8000) printf("0");
158 else if (mask1 & 0x8000) printf("1");
159 else printf("x");
160
161 mask0 <<= 1;
162 mask1 <<= 1;
163 }
164 printf(")\n");
165
166 /* if the file contains a fixed value, we don't need to do the other */
167 /* validity checks */
168 if (fixedmask == 0xffff || fixedmask == 0x00ff || fixedmask == 0xff00)
169 return;
170 }
171
172
173 addrbit = 1;
174 mask0 = 0;
175 while (addrbit <= file->size/2)
176 {
177 for (i = 0;i < file->size;i++)
178 {
179 if (file->buf[i] != file->buf[i ^ addrbit]) break;
180 }
181
182 if (i == file->size)
183 mask0 |= addrbit;
184
185 addrbit <<= 1;
186 }
187
188 if (mask0)
189 {
190 if (mask0 == file->size/2)
191 printf("%-23s %-23s FIRST AND SECOND HALF IDENTICAL\n",side ? "" : file->name,side ? file->name : "");
192 else
193 printf("%-23s %-23s BAD ADDRESS LINES (mask=%06x)\n",side ? "" : file->name,side ? file->name : "",mask0);
194 return;
195 }
196
197 mask0 = 0x000000;
198 mask1 = file->size-1;
199 for (i = 0;i < file->size;i++)
200 {
201 if (file->buf[i] != 0xff)
202 {
203 mask0 |= i;
204 mask1 &= i;
205 if (mask0 == file->size-1 && mask1 == 0x00) break;
206 }
207 }
208
209 if (mask0 != file->size-1 || mask1 != 0x00)
210 {
211 printf("%-23s %-23s ",side ? "" : file->name,side ? file->name : "");
212 for (i = 0;i < 24;i++)
213 {
214 if (file->size <= (1<<(23-i))) printf(" ");
215 else if (~mask0 & 0x800000) printf("1");
216 else if (mask1 & 0x800000) printf("0");
217 else printf("x");
218 mask0 <<= 1;
219 mask1 <<= 1;
220 }
221 printf(" = 0xFF\n");
222
223 return;
224 }
225
226
227 mask0 = 0x000000;
228 mask1 = file->size-1;
229 for (i = 0;i < file->size;i++)
230 {
231 if (file->buf[i] != 0x00)
232 {
233 mask0 |= i;
234 mask1 &= i;
235 if (mask0 == file->size-1 && mask1 == 0x00) break;
236 }
237 }
238
239 if (mask0 != file->size-1 || mask1 != 0x00)
240 {
241 printf("%-23s %-23s ",side ? "" : file->name,side ? file->name : "");
242 for (i = 0;i < 24;i++)
243 {
244 if (file->size <= (1<<(23-i))) printf(" ");
245 else if ((mask0 & 0x800000) == 0) printf("1");
246 else if (mask1 & 0x800000) printf("0");
247 else printf("x");
248 mask0 <<= 1;
249 mask1 <<= 1;
250 }
251 printf(" = 0x00\n");
252
253 return;
254 }
255
256
257 for (i = 0;i < file->size/4;i++)
258 {
259 if (file->buf[file->size/2 + 2*i+1] != 0xff) break;
260 if (file->buf[2*i+1] != file->buf[file->size/2 + 2*i]) break;
261 }
262
263 if (i == file->size/4)
264 printf("%-23s %-23s BAD NEOGEO DUMP - CUT 2ND HALF\n",side ? "" : file->name,side ? file->name : "");
265 }
266
267
268 static int usedbytes(const struct fileinfo *file,int mode)
269 {
270 switch (mode)
271 {
272 case MODE_A:
273 case MODE_NIB1:
274 case MODE_NIB2:
275 return file->size;
276 case MODE_12:
277 case MODE_22:
278 case MODE_E:
279 case MODE_O:
280 return file->size / 2;
281 case MODE_14:
282 case MODE_24:
283 case MODE_34:
284 case MODE_44:
285 case MODE_E12:
286 case MODE_O12:
287 case MODE_E22:
288 case MODE_O22:
289 return file->size / 4;
290 default:
291 return 0;
292 }
293 }
294
295 static void basemultmask(const struct fileinfo *file,int mode,int *base,int *mult,int *mask)
296 {
297 *mult = 1;
298 if (mode >= MODE_E) *mult = 2;
299
300 switch (mode)
301 {
302 case MODE_A:
303 case MODE_12:
304 case MODE_14:
305 case MODE_E:
306 case MODE_E12:
307 *base = 0; *mask = 0xff; break;
308 case MODE_NIB1:
309 *base = 0; *mask = 0x0f; break;
310 case MODE_NIB2:
311 *base = 0; *mask = 0xf0; break;
312 case MODE_O:
313 case MODE_O12:
314 *base = 1; *mask = 0xff; break;
315 case MODE_22:
316 case MODE_E22:
317 *base = file->size / 2; *mask = 0xff; break;
318 case MODE_O22:
319 *base = 1 + file->size / 2; *mask = 0xff; break;
320 case MODE_24:
321 *base = file->size / 4; *mask = 0xff; break;
322 case MODE_34:
323 *base = 2*file->size / 4; *mask = 0xff; break;
324 case MODE_44:
325 *base = 3*file->size / 4; *mask = 0xff; break;
326 }
327 }
328
329 static float filecompare(const struct fileinfo *file1,const struct fileinfo *file2,int mode1,int mode2)
330 {
331 int i;
332 int match = 0;
333 int size1,size2;
334 int base1,base2,mult1,mult2,mask1,mask2;
335
336
337 if (file1->buf == 0 || file2->buf == 0) return 0.0;
338
339 size1 = usedbytes(file1,mode1);
340 size2 = usedbytes(file2,mode2);
341
342 if (size1 != size2) return 0.0;
343
344 basemultmask(file1,mode1,&base1,&mult1,&mask1);
345 basemultmask(file2,mode2,&base2,&mult2,&mask2);
346
347 if (mask1 == mask2)
348 {
349 if (mask1 == 0xff)
350 {
351 /* normal compare */
352 for (i = 0;i < size1;i++)
353 if (file1->buf[base1 + mult1 * i] == file2->buf[base2 + mult2 * i]) match++;
354 }
355 else
356 {
357 /* nibble compare, abort if other half is not empty */
358 for (i = 0;i < size1;i++)
359 {
360 if (((file1->buf[base1 + mult1 * i] & ~mask1) != (0x00 & ~mask1) &&
361 (file1->buf[base1 + mult1 * i] & ~mask1) != (0xff & ~mask1)) ||
362 ((file2->buf[base1 + mult1 * i] & ~mask2) != (0x00 & ~mask2) &&
363 (file2->buf[base1 + mult1 * i] & ~mask2) != (0xff & ~mask2)))
364 {
365 match = 0;
366 break;
367 }
368 if ((file1->buf[base1 + mult1 * i] & mask1) == (file2->buf[base2 + mult2 * i] & mask2)) match++;
369 }
370 }
371 }
372
373 return (float)match / size1;
374 }
375
376
377 static void readfile(const char *path,struct fileinfo *file)
378 {
379 char fullname[256];
380 FILE *f = 0;
381
382
383 if (path)
384 {
385 char delim[2] = { PATH_DELIM, '\0' };
386 strcpy(fullname,path);
387 strcat(fullname,delim);
388 }
389 else fullname[0] = 0;
390 strcat(fullname,file->name);
391
392 if ((file->buf = malloc(file->size)) == 0)
393 {
394 printf("%s: out of memory!\n",file->name);
395 return;
396 }
397
398 if ((f = fopen(fullname,"rb")) == 0)
399 {
400 printf("%s: %s\n",fullname,strerror(errno));
401 return;
402 }
403
404 if (fread(file->buf,1,file->size,f) != file->size)
405 {
406 printf("%s: %s\n",fullname,strerror(errno));
407 fclose(f);
408 return;
409 }
410
411 fclose(f);
412
413 return;
414 }
415
416
417 static void freefile(struct fileinfo *file)
418 {
419 free(file->buf);
420 file->buf = 0;
421 }
422
423
424 static void printname(const struct fileinfo *file1,const struct fileinfo *file2,float score,int mode1,int mode2)
425 {
426 printf("%-12s %s %-12s %s ",file1 ? file1->name : "",modenames[mode1],file2 ? file2->name : "",modenames[mode2]);
427 if (score == 0.0) printf("NO MATCH\n");
428 else if (score == 1.0) printf("IDENTICAL\n");
429 else printf("%3.3f%%\n",score*100);
430 }
431
432
433 static int load_files(int i, int *found, const char *path)
434 {
435 struct stat st;
436
437
438 if (stat(path,&st) != 0)
439 {
440 printf("%s: %s\n",path,strerror(errno));
441 return 10;
442 }
443
444 if (S_ISDIR(st.st_mode))
445 {
446 DIR *dir;
447 struct dirent *d;
448
449 /* load all files in directory */
450 dir = opendir(path);
451 if (dir)
452 {
453 while((d = readdir(dir)) != NULL)
454 {
455 char buf[255+1];
456 struct stat st_file;
457
458 sprintf(buf, "%s%c%s", path, PATH_DELIM, d->d_name);
459 if(stat(buf, &st_file) == 0 && S_ISREG(st_file.st_mode))
460 {
461 unsigned size = st_file.st_size;
462 while (size && (size & 1) == 0) size >>= 1;
463 if (size & ~1)
464 printf("%-23s %-23s ignored (not a ROM)\n",i ? "" : d->d_name,i ? d->d_name : "");
465 else
466 {
467 strcpy(files[i][found[i]].name,d->d_name);
468 files[i][found[i]].size = st_file.st_size;
469 readfile(path,&files[i][found[i]]);
470 files[i][found[i]].listed = 0;
471 if (found[i] >= MAX_FILES)
472 {
473 printf("%s: max of %d files exceeded\n",path,MAX_FILES);
474 break;
475 }
476 found[i]++;
477 }
478 }
479 }
480 closedir(dir);
481 }
482 }
483 else
484 {
485 ZIP *zip;
486 struct zipent* zipent;
487
488 /* wasn't a directory, so try to open it as a zip file */
489 if ((zip = openzip(path)) == 0)
490 {
491 printf("Error, cannot open zip file '%s' !\n", path);
492 return 1;
493 }
494
495 /* load all files in zip file */
496 while ((zipent = readzip(zip)) != 0)
497 {
498 int size;
499
500 size = zipent->uncompressed_size;
501 while (size && (size & 1) == 0) size >>= 1;
502 if (zipent->uncompressed_size == 0 || (size & ~1))
503 printf("%-23s %-23s ignored (not a ROM)\n",
504 i ? "" : zipent->name, i ? zipent->name : "");
505 else
506 {
507 struct fileinfo *file = &files[i][found[i]];
508 const char *delim = strrchr(zipent->name,'/');
509
510 if (delim)
511 strcpy (file->name,delim+1);
512 else
513 strcpy(file->name,zipent->name);
514 file->size = zipent->uncompressed_size;
515 if ((file->buf = malloc(file->size)) == 0)
516 printf("%s: out of memory!\n",file->name);
517 else
518 {
519 if (readuncompresszip(zip, zipent, (char *)file->buf) != 0)
520 {
521 free(file->buf);
522 file->buf = 0;
523 }
524 }
525
526 file->listed = 0;
527 if (found[i] >= MAX_FILES)
528 {
529 printf("%s: max of %d files exceeded\n",path,MAX_FILES);
530 break;
531 }
532 found[i]++;
533 }
534 }
535 closezip(zip);
536 }
537 return 0;
538 }
539
540
541 int CLIB_DECL main(int argc,char **argv)
542 {
543 int err;
544 int total_modes = MODE_NIB2; /* by default, use only MODE_A, MODE_NIB1 and MODE_NIB2 */
545
546 if (argc >= 2 && strcmp(argv[1],"-d") == 0)
547 {
548 argc--;
549 argv++;
550 total_modes = TOTAL_MODES;
551 }
552
553 if (argc < 2)
554 {
555 printf("usage: romcmp [-d] [dir1 | zip1] [dir2 | zip2]\n");
556 printf("-d enables a slower, more comprehensive comparison.\n");
557 return 0;
558 }
559
560 {
561 int found[2];
562 int i,j,mode1,mode2;
563 int besti,bestj;
564
565
566 found[0] = found[1] = 0;
567 for (i = 0;i < 2;i++)
568 {
569 if (argc > i+1)
570 {
571 err = load_files (i, found, argv[i+1]);
572 if (err != 0)
573 return err;
574 }
575 }
576
577 if (argc >= 3)
578 printf("%d and %d files\n",found[0],found[1]);
579 else
580 printf("%d files\n",found[0]);
581
582 for (i = 0;i < found[0];i++)
583 {
584 checkintegrity(&files[0][i],0);
585 }
586
587 for (j = 0;j < found[1];j++)
588 {
589 checkintegrity(&files[1][j],1);
590 }
591
592 if (argc < 3)
593 {
594 /* find duplicates in one dir */
595 for (i = 0;i < found[0];i++)
596 {
597 for (j = i+1;j < found[0];j++)
598 {
599 for (mode1 = 0;mode1 < total_modes;mode1++)
600 {
601 for (mode2 = 0;mode2 < total_modes;mode2++)
602 {
603 if (filecompare(&files[0][i],&files[0][j],mode1,mode2) == 1.0)
604 printname(&files[0][i],&files[0][j],1.0,mode1,mode2);
605 }
606 }
607 }
608 }
609 }
610 else
611 {
612 /* compare two dirs */
613 for (i = 0;i < found[0];i++)
614 {
615 for (j = 0;j < found[1];j++)
616 {
617 fprintf(stderr,"%2d%%\r",100*(i*found[1]+j)/(found[0]*found[1]));
618 for (mode1 = 0;mode1 < total_modes;mode1++)
619 {
620 for (mode2 = 0;mode2 < total_modes;mode2++)
621 {
622 matchscore[i][j][mode1][mode2] = filecompare(&files[0][i],&files[1][j],mode1,mode2);
623 }
624 }
625 }
626 }
627 fprintf(stderr," \r");
628
629 do
630 {
631 float bestscore;
632 int bestmode1,bestmode2;
633
634 besti = -1;
635 bestj = -1;
636 bestscore = 0.0;
637 bestmode1 = bestmode2 = -1;
638
639 for (mode1 = 0;mode1 < total_modes;mode1++)
640 {
641 for (mode2 = 0;mode2 < total_modes;mode2++)
642 {
643 for (i = 0;i < found[0];i++)
644 {
645 for (j = 0;j < found[1];j++)
646 {
647 if (matchscore[i][j][mode1][mode2] > bestscore
648 || (matchscore[i][j][mode1][mode2] == 1.0 && mode2 == 0 && bestmode2 > 0))
649 {
650 bestscore = matchscore[i][j][mode1][mode2];
651 besti = i;
652 bestj = j;
653 bestmode1 = mode1;
654 bestmode2 = mode2;
655 }
656 }
657 }
658 }
659 }
660
661 if (besti != -1)
662 {
663 int start,end;
664
665 printname(&files[0][besti],&files[1][bestj],bestscore,bestmode1,bestmode2);
666 files[0][besti].listed = 1;
667 files[1][bestj].listed = 1;
668
669 matchscore[besti][bestj][bestmode1][bestmode2] = 0.0;
670
671 /* remove all matches using the same sections with a worse score */
672 for (j = 0;j < found[1];j++)
673 {
674 for (mode2 = 0;mode2 < total_modes;mode2++)
675 {
676 if (matchscore[besti][j][bestmode1][mode2] < bestscore)
677 matchscore[besti][j][bestmode1][mode2] = 0.0;
678 }
679 }
680 for (i = 0;i < found[0];i++)
681 {
682 for (mode1 = 0;mode1 < total_modes;mode1++)
683 {
684 if (matchscore[i][bestj][mode1][bestmode2] < bestscore)
685 matchscore[i][bestj][mode1][bestmode2] = 0.0;
686 }
687 }
688
689 /* remove all matches using incompatible sections */
690 compatiblemodes(bestmode1,&start,&end);
691 for (j = 0;j < found[1];j++)
692 {
693 for (mode2 = 0;mode2 < total_modes;mode2++)
694 {
695 for (mode1 = 0;mode1 < start;mode1++)
696 matchscore[besti][j][mode1][mode2] = 0.0;
697 for (mode1 = end+1;mode1 < total_modes;mode1++)
698 matchscore[besti][j][mode1][mode2] = 0.0;
699 }
700 }
701 compatiblemodes(bestmode2,&start,&end);
702 for (i = 0;i < found[0];i++)
703 {
704 for (mode1 = 0;mode1 < total_modes;mode1++)
705 {
706 for (mode2 = 0;mode2 < start;mode2++)
707 matchscore[i][bestj][mode1][mode2] = 0.0;
708 for (mode2 = end+1;mode2 < total_modes;mode2++)
709 matchscore[i][bestj][mode1][mode2] = 0.0;
710 }
711 }
712 }
713 } while (besti != -1);
714
715
716 for (i = 0;i < found[0];i++)
717 {
718 if (files[0][i].listed == 0) printname(&files[0][i],0,0.0,0,0);
719 freefile(&files[0][i]);
720 }
721 for (i = 0;i < found[1];i++)
722 {
723 if (files[1][i].listed == 0) printname(0,&files[1][i],0.0,0,0);
724 freefile(&files[1][i]);
725 }
726 }
727 }
728
729 return 0;
730 }
731

Back to OSDN">Back to OSDN
ViewVC Help
Powered by ViewVC 1.1.26