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