| 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 |
|