Results 1 to 5 of 5

Thread: CE Checksum Algorithm

Threaded View

Previous Post Previous Post   Next Post Next Post
  1. #1
    Senior Member Btcc22's Avatar
    Join Date
    Sep 2012
    Posts
    564

    CE Checksum Algorithm

    Needed the map checksum algorithm but couldn't find any information on it so I had to reverse it. Posting an example implementation should anybody else find themselves wanting it for any of their projects (hint: map editors that update the checksum). Shouldn't be a problem to port it to other languages.

    • Error checks removed for brevity.
    • Make sure invalid data isn't going to make your code do something stupid.
    • Longs and pointers are 32 bits here.
    • You'll also be better off using a memory mapped file for this rather than all of the seeks and reads but I wanted the example to be easy to follow.

    Code:
    //typedef unsigned int DWORD;
    //typedef unsigned char BYTE;
    
    struct TagEntry {
        DWORD Class0;
        DWORD Class1;
        DWORD Class2;
        long TagID;
        char* TagNameAddress;
        long TagStruct;
        char Unknown[8];
    };
    
    struct TagTableHeader {
        long TagTableEntryPointer;
        long FirstTagID;
        long MapID;
        long TagCount;
        long VerticesCount;
        long VerticesOffset;
        long IndicesCount;
        long IndicesOffset;
        long ModelDataSize;
        long Signature;
    };
    
    struct BSPChunkMeta {
        DWORD offset;
        DWORD size;
    };
    
    //Just made this up
    struct SceneryTag {
        DWORD sections;
        DWORD address;
    };
    
    struct MapHeader {
        long Signature0; // head = "daeh"
        short Game; // Xbox = 5 / Trial = 6 / PC = 7 / CE = 0x261
        short Unknown0;
        long MapSize;
        char Unknown1[4];
        long IndexOffset;
        long MetaSize;
        char Unknown3[8];
        char MapName[14];
        char Unknown4[18];
        char Build[12]; // PC = 01.00.00.0564 / CE = 01.00.00.0609
        char Unknown5[20];
        char MapType; // SP = 0 / MP = 1 / UI = 2
        char Unknown6;
        short Unknown7;
        int checksum;
        char Unknown8[1940];
        long Signature1; // foot = "toof"
    };
    
    DWORD xorChunk(DWORD checksum, BYTE* data, DWORD length, DWORD* xorBuff) {
        for(DWORD i = 0; i < length; i++) {
            int byte = data[i];
            byte ^= checksum;
            byte &= 255;
            byte = xorBuff[byte];
            checksum /= 256;
            checksum ^= byte;
        }
        return checksum;
    }
    
    void generateXorBuff(DWORD* buffer) {
        for(DWORD i = 0, val = 0; i < 256; i++, val = i) {
            for(int j = 0; j < 8; j++) {
                if(val % 2 == 1) {
                    val /= 2;
                    val ^= 0xEDB88320;
                } else {
                    val /= 2;
                }
            }
            buffer[i] = val;
        }
    }
    
    DWORD checksum(FILE* handle) {
        MapHeader header;
        TagEntry tag;
        SceneryTag scenery;
        BSPChunkMeta bspMeta;
        DWORD checksum = -1;
        BYTE* chunk;
        DWORD* xorBuffer = new DWORD[256];
    
        generateXorBuff(xorBuffer);
    
        //Read the map header
        rewind(handle);
        fread(&header, sizeof(MapHeader), 1, handle);
        
        //Read the index
        TagTableHeader index;
        fseek(handle, header.IndexOffset, SEEK_SET);
        fread(&index, sizeof(TagTableHeader), 1, handle);
    
        //Calculate 'rebase' value
        DWORD magic = (index.TagTableEntryPointer - header.IndexOffset) - 40;
    
        //Checksum SBSPs - bless this mess
        DWORD scenario = index.TagTableEntryPointer - magic;
        fseek(handle, scenario, SEEK_SET);
        fread(&tag, sizeof(TagEntry), 1, handle);
        DWORD scnrMetaOffset = (tag.TagStruct - magic) + 0x5A4;
    
        fseek(handle, scnrMetaOffset, SEEK_SET);
        fread(&scenery, sizeof(SceneryTag), 1, handle);
    
        for(DWORD i = 0; i < scenery.sections; i++) {
            DWORD bspMetaOffset = ((scenery.address - magic) + (i * 32));
            fseek(handle, bspMetaOffset, SEEK_SET);
            fread(&bspMeta, sizeof(bspMeta), 1, handle);
        
            //Read BSP
            fseek(handle, bspMeta.offset, SEEK_SET);
            chunk = new BYTE[bspMeta.size];
            fread(chunk, bspMeta.size, 1, handle);
            
            //Checksum BSP
            checksum = xorChunk(checksum, chunk, bspMeta.size, xorBuffer);
            delete[] chunk;
        }
    
        //Load model data
        fseek(handle, index.VerticesOffset, SEEK_SET);
        chunk = new BYTE[index.ModelDataSize];
        fread(chunk, index.ModelDataSize, 1, handle);
    
        //Checksum model data
        checksum = xorChunk(checksum, chunk, index.ModelDataSize, xorBuffer);
        delete[] chunk;
    
        //Load tag index
        DWORD tagOffset = header.IndexOffset;
        chunk = new BYTE[header.MetaSize];
        fseek(handle, tagOffset, SEEK_SET);
        fread(chunk, 1, header.MetaSize, handle);
    
        //Checksum tag index
        checksum = xorChunk(checksum, chunk, header.MetaSize, xorBuffer);
        delete[] chunk;
    
        delete[] xorBuffer;
    
        return checksum;
    }
    Last edited by Btcc22; December 13th, 2012 at 04:33 PM.
    Reply With Quote

Thread Information

Users Browsing this Thread

There are currently 1 users browsing this thread. (0 members and 1 guests)

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •