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;
}
Bookmarks