Checksum Calculation Source
/* This source code contains routines to manipulate GameBoy ROM images. It is meant that source to be used as a learning tool and not a tool of piracy. *BorlandC 3.1 was used to compile this successfully. It is a crime to redistribute these routines in a commercial venture of any kind without permission or licensing agreement. Contact us at our web page for more information on licensing. (C)opyright 1995,96 Damaged Cybernetics If you have any questions or comments, please contact the following ppl via the Internet: Donald Moore (MindRape) mindrape@goodnet.com Donald Staheli (Royce) staheli@goodnet.com Web Page: www.futureone.com/~damaged Things that still need to be done is to calculate the compliment of the GameBoy ROM image. I'd like to thank DiskDude for his addtional help! */ #include <stdio.h> #include "gameboy.h" // Magic string to check for unsigned char DETECT_GAMEBOY_MAJIC[] = { 0xCE,0xED,0x66,0x66,0xCC,0x0D,0x00,0x0B,0x03,0x73,0x00,0x83, 0x00,0x0C,0x00,0x0D,0x00,0x08,0x11,0x1F,0x88,0x89,0x00,0x0E, 0xDC,0xCC,0x6E,0xE6,0xDD,0xDD,0xD9,0x99,0xBB,0xBB,0x67,0x63, 0x6E,0x0E,0xEC,0xCC,0xDD,0xDC,0x99,0x9F,0xBB,0xB9,0x33,0x3E }; /* unsigned int swapint(unsigned int uiValue) ENT: unsigned int uiValue - Value to swap bytes RET: unsigned int Swap a 16 bit integer value bytes around. */ unsigned int swapint(unsigned int uiValue) {return(uiValue = (uiValue << 8) | (uiValue >> 8));} /* void PutGBCheckSum(FILE *source,unsigned uiCheckSum) ENT: FILE *source - Stream handle to get the GameBoy checksum unsigned int uiCheckSum - checksum value to write out to Gameboy image RET: <nothing> Put the GameBoy checksum value into the rom image. Please make sure your in write mode, or update mode. Lots of people make this mistake. This routine preserves the original offset in the stream. */ void PutGBCheckSum(FILE *source,unsigned int uiCheckSum) { unsigned long ulOldOffset = 0L; // save the old offset in the file ulOldOffset = ftell(source); // jump to CheckSum Location fseek(source,(long) GB_CHECKSUM_OFFSET1,SEEK_SET); /* We need to swap the 2 bytes around on Little Edian machines since the GameBoy is Big Edian. */ uiCheckSum = swapint(uiCheckSum); // the checksum is 2 bytes fwrite(&uiCheckSum,1,2,source); // jump back to the old offset in the file fseek(source,ulOldOffset,SEEK_SET); } /* unsigned int GetGBCheckSum(FILE *source,unsigned int uiOffset) ENT: FILE *source - Stream handle to get the GameBoy checksum unsigned int uiOffset - correct offset to grab checksum RET: GameBoy Rom checksum from the file. Grab the GameBoy checksum value form the rom image. This routine preserves the original offset in the stream. */ unsigned int GetGBCheckSum(FILE *source,unsigned int uiOffset) { unsigned long ulOldOffset = 0L; unsigned int uiCheckSum = 0; // save the old offset in the file ulOldOffset = ftell(source); // Jump to CheckSum Location fseek(source,(long) GB_CHECKSUM_OFFSET1+uiOffset,SEEK_SET); // the checksum is 2 bytes fread(&uiCheckSum,2,1,source); /* We need to swap the 2 bytes around on Little Edian machines since the GameBoy is Big Edian. */ uiCheckSum = swapint(uiCheckSum); // jump back to the old offset in the file fseek(source,ulOldOffset,SEEK_SET); // return the Checksum we found return(uiCheckSum); } /* unsigned char Check4GameBoy (unsigned char *szStr2check,unsigned int uiOffset) ENT: unsigned char *szStr2check - Buffer holding area to search unsigned int uiOffset - Starting position to start looking in string RET:TRUE - valid GameBoy image FALSE - invalid GameBoy image Compare szStr2check with DETECT_GAMEBOY_MAJIC. If szStr2check matches the majic value then we have a real gameboy image. */ unsigned char Check4GameBoy (unsigned char *szStr2check,unsigned int uiOffset) {int i; for (i=0;i < DETECT_GAMEBOY_MAJIC_SIZE;i++) if (szStr2check[i+uiOffset] != DETECT_GAMEBOY_MAJIC[i]) return(FALSE); return(TRUE); } /* char DetectGameBoy(FILE *source) ENT: FILE *source - Stream handle to get the GameBoy checksum RET: DETECT_GAMEBOY_HEADER - Found a GameBoy image w/header DETECT_GAMEBOY_RAW - Found a Gameboy image w/o header DETECT_GAMEBOY_INVALID - Invalid GameBoy image Try to detect if we have a valid gameboy image. This routine preserves the original offset in the stream. */ char DetectGameBoy(FILE *source) { unsigned char ucBuffer[DETECT_GAMEBOY_BUFFER_SIZE]; // hold our old offset in the stream unsigned long ulOldOffset = 0L; // hold our majic signature value unsigned ucMajic; // hold our return value unsigned int uiRetVal; // save the old offset in the file ulOldOffset = ftell(source); // rewind back file position 0 rewind(source); fseek(source,0L,SEEK_SET); fread(ucBuffer,1,DETECT_GAMEBOY_BUFFER_SIZE,source); /* Ok since the FIG header format is impossible to detect dued to lack of information about the format and the intial information didn't really look possible. Also many GB copiers don't do the header correctly anyways =(. Next solution check for the Majic signature that MUST exist in all GB games, the Nintendo character area. What we do is look for it in it's normal place, if that fails look in the same place offseted by 512 bytes. */ // Check for without header if (Check4GameBoy(ucBuffer,DETECT_GAMEBOY_MAJIC_RAW_POS)) uiRetVal = DETECT_GAMEBOY_RAW; else { // check for with header if (Check4GameBoy(ucBuffer,DETECT_GAMEBOY_MAJIC_HEADR_POS)) uiRetVal = DETECT_GAMEBOY_HEADER; // not a valid GB image! else uiRetVal = DETECT_GAMEBOY_INVALID; } // ok back to the old file position fseek(source,ulOldOffset,SEEK_SET); return(uiRetVal); } /* unsigned int CalculateGBCheckSum(FILE *source,unsigned int uiOffset) ENT: FILE *source - Stream handle of file to calculate GameBoy checksum unsigned int uiOffset - The offset to start calculating at RET: GB Checksum Calculate the Gameboy ROM Image checksum value. unsigned int CalculateGBCheckSum(FILE *source,unsigned int uiOffset) { // hold our old offset in the stream unsigned long ulOldOffset = 0L; // store our calculated checksum here unsigned int uiCheckSum = 0; unsigned char ucBuffer[BUFFER_SIZE]; unsigned int i; // keep track of our buffer size unsigned int uiSize; // keep track of our position in the file unsigned long ulTotalFileSize = 0L; // save the old offset in the file ulOldOffset = ftell(source); // seek to the correct offset to start fseek(source,uiOffset,SEEK_SET); /* The gameboy calculates it's checksum by adding each byte up in the ROM image, except for it's checksum bytes. The checksum bytes are located at offsets GB_CHECKSUM_OFFSET1 and GB_CHECKSUM_OFFSET2. The checksum is a 32bit value. Calculate it by adding every byte up in the ROM (don't include the copier header if there is one). Once we are finished we take the lower 16bits and return it. In this following piece of code we use a 16bit integer and let it overflow (quite a few times :>) so we don't have to do an xor 0xFFFF later on. */ while (!feof(source)) { uiSize = fread(ucBuffer,1,BUFFER_SIZE,source); for (i=0;i < uiSize;i++) { if (ulTotalFileSize != GB_CHECKSUM_OFFSET1 && ulTotalFileSize != GB_CHECKSUM_OFFSET2) uiCheckSum += ucBuffer[i]; // keep track of our position in the file we could use ftell() // but its too slow ulTotalFileSize++; } } // ok back to the old file position fseek(source,ulOldOffset,SEEK_SET); // return our checksum return(uiCheckSum); }

Damaged Cybernetics is not connected or affiliated with any mentioned company in any way. The opinions of Damaged Cybernetics do not reflect the views of the various companies mentioned here. Companies and all products pertaining to that company are trademarks of that company. Please contact that company for trademark and copyright information.

© 1996 Damaged Cybernetics All Rights Reserved