code to do xbox mapfile compression
Posted: Fri Jul 02, 2004 8:47 am
Ok, UltraMagnus asked me for the code to do mapfile compression to help someone make a tool that can automate NMP construction, so here it is. Credit goes to PfhorSlayer for helping me with the buffer alignments many moons ago. To use this, you need the zlib compression library
http://www.zlib.net/zlib121-dll.zip
You need to know the structure of the mapfile header:
The compression code (m_InputFile is uncompressed map file):
http://www.zlib.net/zlib121-dll.zip
You need to know the structure of the mapfile header:
Code: Select all
typedef struct STRUCT_MAPFILE_HDR
{
int id; // 'head'
int Version; // 5
int decomp_len; // Actual len of decompressed data. Halo sticks garbage on the end so that the file is one of several fixed sizes (35, etc).
int Unknown1;
int TagIndexOffset;
int TagIndexMetaLength;
int Reserved1[2]; // both always 0x0
char Name[32];
char BuildDate[32]; // Year.Month.Day.Build - I guess they use this to make sure that a certain build will only open that build's map files, because this string is in the app too
int MapType; // 0 = singleplayer, 1 = multiplayer, 2 = ui - this also determines the size of the cache file. UI = 35MB, multiplayer = 47MB, and singleplayer = 270MB
int Unknown4;
int Reserved2[485];
int Footer; // 'foot'
}MAPFILE_HDR; /* header_t */
Code: Select all
BOOL CHaloMapFile::CompressMapFile(CString output_file)
{
BYTE *pInBuf = NULL;
BYTE *pOutBuf = NULL;
HANDLE hInFile, hOutFile, hInSection, hOutSection;
MAPFILE_HDR *pHeader = NULL;
CString str, cachepath;
int result = Z_MEM_ERROR;
unsigned long out_len;
int actual_file_size = 0;
int desired_file_size = 0;
int pad_bytes = 0;
//Close open file so we can open it in memory-mapping mode
out_len = m_InputFile.GetLength() - 2048;
m_InputFile.Close();
str.Format("Saving to compressed file %s\n", output_file);
g_pOutput->PostText(str, LOG_BLUE);
str.Format("Compressing %s\n", m_InputFilename);
g_pOutput->PostText(str, LOG_BLUE);
g_pOutput->PostText("Please wait...\n", LOG_BLUE);
g_pOutput->RedrawWindow();
int k = sizeof(MAPFILE_HDR);
// Use Filemapping to make the input file "look" like a normal buffer
hInFile = CreateFile(m_InputFilename,
GENERIC_READ,
0, // do not share
0,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
0);
hInSection = CreateFileMapping(hInFile,
0,
PAGE_READONLY,
0, //this is not a large file
0, //map the entire file
0); //it does not need a name - no interprocess comm here :)
pInBuf = (BYTE*)MapViewOfFile(hInSection,
FILE_MAP_READ,
0,
0,
0);
if(pInBuf)
{
cachepath = m_WorkingDir + "\\cache.tmp";
// Do the same for the output "buffer" (make an output file)
hOutFile = CreateFile(output_file,
GENERIC_READ|GENERIC_WRITE,
0, // do not share
0,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
0);
pHeader = (MAPFILE_HDR*)pInBuf;
hOutSection = CreateFileMapping(hOutFile,
0,
PAGE_READWRITE,
0, //this is not a large file
pHeader->decomp_len+2048, //the decompressed length of the output file
0); //it does not need a name - no interprocess comm here :)
pOutBuf = (BYTE*)MapViewOfFile(hOutSection,
FILE_MAP_WRITE,
0,
0,
0);
if(!pOutBuf)
{
g_pOutput->PostText("Could not create output file.\r\nThere may not be enough hard drive space.\n", LOG_BLUE);
AfxMessageBox("Could not create output file. There may not be enough hard drive space.\n");
UnmapViewOfFile(pOutBuf);
CloseHandle(hOutSection);
}
else
{
CWaitCursor wait;
//write header
memcpy(pOutBuf, &m_MapfileHdr, sizeof(m_MapfileHdr));
//compress file data
int ret;
ret = compress(pOutBuf+2048,
&out_len,
pInBuf+2048,
pHeader->decomp_len-2048);
TRACE("outlen = %08X\n", out_len);
int actual_file_size = out_len + 2048;
int desired_file_size;
int pad_bytes;
pad_bytes = (0x800 - (actual_file_size % 0x800));
desired_file_size = actual_file_size + pad_bytes;
//truncate file to desired_file_size
UnmapViewOfFile(pOutBuf);
CloseHandle(hOutSection);
SetFilePointer(hOutFile, desired_file_size, 0, FILE_BEGIN);
SetEndOfFile(hOutFile);
if(ret != Z_OK)
{
str.Format("Compress returned %i!\n", ret);
g_pOutput->PostText(str, LOG_RED);
AfxMessageBox("Compress Map Failed.");
}
}
CloseHandle(hOutFile);
}
UnmapViewOfFile(pInBuf);
CloseHandle(hInSection);
CloseHandle(hInFile);
return(FALSE);
}