/* chksum64 V1.2, a program to calculate the ROM checksum of Nintendo64 ROMs. Copyright (C) 1997 Andreas Sterbenz (stan@sbox.tu-graz.ac.at) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include #include #include #define max2(a, b) ( (a)>(b) ? (a) : (b) ) #define min2(a, b) ( (a)<(b) ? (a) : (b) ) #define BUFSIZE 32768 #define CHECKSUM_START 0x1000 #define CHECKSUM_LENGTH 0x100000L #define CHECKSUM_HEADERPOS 0x10 #define CHECKSUM_END (CHECKSUM_START + CHECKSUM_LENGTH) #define CHECKSUM_STARTVALUE 0xf8ca4ddc #define ROL(i, b) (((i)<<(b)) | ((i)>>(32-(b)))) #define BYTES2LONG(b, s) ( (((b)[0^(s)] & 0xffL) << 24) | \ (((b)[1^(s)] & 0xffL) << 16) | \ (((b)[2^(s)] & 0xffL) << 8) | \ (((b)[3^(s)] & 0xffL)) ) #define LONG2BYTES(l, b, s) (b)[0^(s)] = ((l)>>24)&0xff; \ (b)[1^(s)] = ((l)>>16)&0xff; \ (b)[2^(s)] = ((l)>> 8)&0xff; \ (b)[3^(s)] = ((l) )&0xff; #define HEADER_MAGIC 0x80371240 void usage(char *progname) { fprintf(stderr, "Usage: %s [-r] [-o|-s] \n\n", progname); fprintf(stderr, "This program calculates the ROM checksum for Nintendo64 ROM images.\n"); fprintf(stderr, "Checksum code reverse engineered from Nagra's program.\n"); exit(2); } int main(int argc, char *argv[]) { FILE *file1; char *fname1=NULL, *progname=argv[0]; unsigned char buffer1[BUFSIZE]; unsigned int flen1; unsigned int sum1, sum2; int swapped=-1; int readonly = 0; printf("CHKSUM64 V1.2 Copyright (C) 1997 Andreas Sterbenz (stan@sbox.tu-graz.ac.at)\n"); printf("This program is released under the terms of the GNU public license. NO WARRANTY\n\n"); { int i; for( i=1; i 0 ) { n = fread(buffer1, 1, min2(BUFSIZE, clen), file1); if( (n & 0x03) != 0 ) { n += fread(buffer1+n, 1, 4-(n&3), file1); } } else { n = min2(BUFSIZE, clen); } if( (n == 0) || ((n&3) != 0) ) { if( (clen != 0) || (n != 0) ) { fprintf(stderr, "WARNING: Short read, checksum may be incorrect.\n"); } break; } for( i=0; i 0 ) { rlen -= n; if( rlen <= 0 ) memset(buffer1, 0, BUFSIZE); } clen -= n; } sum1 = t6 ^ t4 ^ t3; sum2 = t5 ^ t2 ^ t1; } LONG2BYTES(sum1, &buffer1[0], 0); LONG2BYTES(sum2, &buffer1[4], 0); fseek(file1, CHECKSUM_HEADERPOS, SEEK_SET); fread(buffer1+8, 1, 8, file1); printf("Old Checksum: "); printf("%02X %02X %02X %02X ", buffer1[ 8^swapped], buffer1[ 9^swapped], buffer1[10^swapped], buffer1[11^swapped]); printf("%02X %02X %02X %02X\n", buffer1[12^swapped], buffer1[13^swapped], buffer1[14^swapped], buffer1[15^swapped]); printf("Calculated Checksum: "); printf("%02X %02X %02X %02X ", buffer1[0], buffer1[1], buffer1[2], buffer1[3]); printf("%02X %02X %02X %02X\n", buffer1[4], buffer1[5], buffer1[6], buffer1[7]); if( readonly == 0 ) { fseek(file1, CHECKSUM_HEADERPOS, SEEK_SET); LONG2BYTES(sum1, &buffer1[16], swapped); LONG2BYTES(sum2, &buffer1[20], swapped); if( fwrite(buffer1+16, 1, 8, file1) != 8 ) { fprintf(stderr, "%s: Could not write new checksum to file '%s'!\n", progname, fname1); exit(1); } else { printf("New checksum successfully written.\n"); } } else { printf("File opened in read-only mode, new checksum not written.\n"); } fclose(file1); return 0; }