#include "diablo.h"
#include "../3rdParty/Storm/Source/storm.h"

int sgdwMpqOffset; // idb
char mpq_buf[4096];
_HASHENTRY *sgpHashTbl;
_bool save_archive_modified; // weak
_BLOCKENTRY *sgpBlockTbl;
_bool save_archive_open; // weak

//note: 32872 = 32768 + 104 (sizeof(_FILEHEADER))

/* data */

HANDLE sghArchive = (HANDLE)0xFFFFFFFF; // idb

_bool mpqapi_set_hidden(char *pszArchive, _bool hidden)
{
	char *v2; // edi
	BOOL v3; // esi
	DWORD v4; // eax
	_bool result; // al
	DWORD v6; // esi

	v2 = pszArchive;
	v3 = hidden;
	v4 = GetFileAttributes(pszArchive);
	if ( v4 == -1 )
		return GetLastError() == ERROR_FILE_NOT_FOUND;
	v6 = v3 != 0 ? FILE_ATTRIBUTE_SYSTEM|FILE_ATTRIBUTE_HIDDEN : 0;
	if ( v4 == v6 )
		result = 1;
	else
		result = SetFileAttributes(v2, v6);
	return result;
}

void mpqapi_store_creation_time(char *pszArchive, int dwChar)
{
	int v2; // esi
	char *v3; // ebx
	HANDLE v4; // eax
	int v5; // esi
	struct _WIN32_FIND_DATAA FindFileData; // [esp+8h] [ebp-1E0h]
	char dst[160]; // [esp+148h] [ebp-A0h]

	v2 = dwChar;
	v3 = pszArchive;
	if ( gbMaxPlayers != 1 )
	{
		mpqapi_reg_load_modification_time(dst, 160);
		v4 = FindFirstFile(v3, &FindFileData);
		if ( v4 != (HANDLE)-1 )
		{
			FindClose(v4);
			v5 = 16 * v2;
			*(_DWORD *)&dst[v5] = FindFileData.ftCreationTime.dwLowDateTime;
			*(_DWORD *)&dst[v5 + 4] = FindFileData.ftCreationTime.dwHighDateTime;
			mpqapi_reg_store_modification_time(dst, 160);
		}
	}
}

_bool mpqapi_reg_load_modification_time(char *dst, int size)
{
	unsigned int v2; // esi
	char *v3; // edi
	unsigned int v6; // esi
	char *v7; // ecx
	int nbytes_read; // [esp+8h] [ebp-4h]

	v2 = size;
	v3 = dst;
	memset(dst, 0, size);
	if ( !SRegLoadData("Diablo", "Video Player ", 0, (unsigned char *)v3, v2, (unsigned long *)&nbytes_read) || nbytes_read != v2 )
		return 0;
	if ( v2 >= 8 )
	{
		v6 = v2 >> 3;
		do
		{
			v7 = v3;
			v3 += 8;
			mpqapi_xor_buf(v7);
			--v6;
		}
		while ( v6 );
	}
	return 1;
}

void mpqapi_xor_buf(char *pbData)
{
	signed int v1; // eax
	char *v2; // esi
	signed int v3; // edi

	v1 = 0xF0761AB;
	v2 = pbData;
	v3 = 8;
	do
	{
		*v2 ^= v1;
		++v2;
		v1 = _rotl(v1, 1);
		--v3;
	}
	while ( v3 );
}

void mpqapi_store_default_time(DWORD dwChar)
{
/*
	DWORD idx;
	char dst[160];

	if(gbMaxPlayers == 1) {
		return;
	}

	/// ASSERT: assert(dwChar < MAX_CHARACTERS);
	idx = 16 * dwChar;
	mpqapi_reg_load_modification_time(dst, sizeof(dst));
	*(_DWORD *)&dst[idx + 4] = 0x78341348; // dwHighDateTime
	mpqapi_reg_store_modification_time(dst, sizeof(dst));
*/
}

_bool mpqapi_reg_store_modification_time(char *pbData, int dwLen)
{
	int v2; // ebx
	char *v3; // ebp
	char *v4; // edi
	unsigned int v5; // esi
	char *v6; // ecx

	v2 = dwLen;
	v3 = pbData;
	v4 = pbData;
	if ( (unsigned int)dwLen >= 8 )
	{
		v5 = (unsigned int)dwLen >> 3;
		do
		{
			v6 = v4;
			v4 += 8;
			mpqapi_xor_buf(v6);
			--v5;
		}
		while ( v5 );
	}
	return SRegSaveData("Diablo", "Video Player ", 0, (unsigned char *)v3, v2);
}

void mpqapi_remove_hash_entry(char *pszName)
{
	int v1; // eax
	_HASHENTRY *v2; // ecx
	_BLOCKENTRY *v3; // eax
	int v4; // esi
	int v5; // edi

	v1 = mpqapi_get_hash_index_of_path(pszName);
	if ( v1 != -1 )
	{
		v2 = &sgpHashTbl[v1];
		v3 = &sgpBlockTbl[v2->block];
		v2->block = -2;
		v4 = v3->offset;
		v5 = v3->sizealloc;
		memset(v3, 0, 0x10u);
		mpqapi_free_block(v4, v5);
		save_archive_modified = 1;
	}
}

void mpqapi_free_block(int block_offset, int block_size)
{
	int v2; // esi
	int v3; // edi
	_BLOCKENTRY *v4; // eax
	signed int v5; // edx
	signed int v6; // ecx
	int v7; // ecx
	_bool v8; // zf
	_BLOCKENTRY *v9; // eax

	v2 = block_size;
	v3 = block_offset;
LABEL_2:
	v4 = sgpBlockTbl;
	v5 = 2048;
	while ( 1 )
	{
		v6 = v5--;
		if ( !v6 )
			break;
		v7 = v4->offset;
		if ( v4->offset && !v4->flags && !v4->sizefile )
		{
			if ( v7 + v4->sizealloc == v3 )
			{
				v3 = v4->offset;
LABEL_11:
				v2 += v4->sizealloc;
				memset(v4, 0, 0x10u);
				goto LABEL_2;
			}
			if ( v3 + v2 == v7 )
				goto LABEL_11;
		}
		++v4;
	}
	v8 = v3 + v2 == sgdwMpqOffset;
	if ( v3 + v2 > sgdwMpqOffset )
	{
		app_fatal("MPQ free list error");
		v8 = v3 + v2 == sgdwMpqOffset;
	}
	if ( v8 )
	{
		sgdwMpqOffset = v3;
	}
	else
	{
		v9 = mpqapi_new_block(0);
		v9->offset = v3;
		v9->sizealloc = v2;
		v9->sizefile = 0;
		v9->flags = 0;
	}
}

_BLOCKENTRY *mpqapi_new_block(int *block_index)
{
	_BLOCKENTRY *result; // eax
	unsigned int v2; // edx

	result = sgpBlockTbl;
	v2 = 0;
	while ( result->offset || result->sizealloc || result->flags || result->sizefile )
	{
		++v2;
		++result;
		if ( v2 >= 0x800 )
		{
			app_fatal("Out of free block entries");
			return 0;
		}
	}
	if ( block_index )
		*block_index = v2;
	return result;
}

int mpqapi_get_hash_index_of_path(char *pszName) // FetchHandle
{
	char *v1; // esi
	int v2; // ST00_4
	int v3; // edi
	short v4; // ax

	v1 = pszName;
	v2 = Hash(pszName, 2); // MPQ_HASH_NAME_B
	v3 = Hash(v1, 1); // MPQ_HASH_NAME_A
	v4 = Hash(v1, 0); // MPQ_HASH_TABLE_INDEX
	return mpqapi_get_hash_index(v4, v3, v2, 0);
}

int mpqapi_get_hash_index(short index, int hash_a, int hash_b, int locale)
{
	int v4; // ecx
	signed int v5; // eax
	signed int v6; // edx
	_HASHENTRY *v7; // ecx
	int v8; // edi
	int v10; // [esp+Ch] [ebp-8h]
	int i; // [esp+10h] [ebp-4h]

	v4 = index & 0x7FF;
	v10 = hash_a;
	v5 = 2048;
	for ( i = v4; ; i = (i + 1) & 0x7FF )
	{
		v7 = &sgpHashTbl[v4];
		v8 = v7->block;
		if ( v8 == -1 )
			return -1;
		v6 = v5--;
		if ( !v6 )
			return -1;
		if ( v7->hashcheck[0] == v10 && v7->hashcheck[1] == hash_b && v7->lcid == locale && v8 != -2 )
			break;
		v4 = (i + 1) & 0x7FF;
	}
	return i;
}

void mpqapi_remove_hash_entries(_bool (__stdcall *fnGetName)(int, char *))
{
	_bool (__stdcall *v1)(int, char *); // edi
	signed int v2; // esi
	int i; // eax
	int v4; // eax
	char v5[260]; // [esp+8h] [ebp-104h]

	v1 = fnGetName;
	v2 = 1;
	for ( i = fnGetName(0, v5); i; i = v1(v4, v5) )
	{
		mpqapi_remove_hash_entry(v5);
		v4 = v2++;
	}
}

_bool mpqapi_write_file(char *pszName, char *pbData, int dwLen)
{
	char *v3; // edi
	char *v4; // esi
	_BLOCKENTRY *v5; // eax

	v3 = pbData;
	v4 = pszName;
	save_archive_modified = 1;
	mpqapi_remove_hash_entry(pszName);
	v5 = mpqapi_add_file(v4, 0, 0);
	if ( mpqapi_write_file_contents(v4, v3, dwLen, v5) )
		return 1;
	mpqapi_remove_hash_entry(v4);
	return 0;
}

_BLOCKENTRY *mpqapi_add_file(char *pszName, _BLOCKENTRY *pBlk, int block_index)
{
	char *v3; // edi
	short v4; // si
	int v5; // ebx
	signed int v6; // edx
	int v7; // esi
	int v8; // ecx
	int v9; // esi
	int v11; // [esp+Ch] [ebp-8h]
	_BLOCKENTRY *v12; // [esp+10h] [ebp-4h]

	v12 = pBlk;
	v3 = pszName;
	v4 = Hash(pszName, 0);
	v5 = Hash(v3, 1);
	v11 = Hash(v3, 2);
	if ( mpqapi_get_hash_index(v4, v5, v11, 0) != -1 )
		app_fatal("Hash collision between \"%s\" and existing file\n", v3);
	v6 = 2048;
	v7 = v4 & 0x7FF;
	while ( 1 )
	{
		--v6;
		v8 = sgpHashTbl[v7].block;
		if ( v8 == -1 || v8 == -2 )
			break;
		v7 = (v7 + 1) & 0x7FF;
		if ( !v6 )
		{
			v6 = -1;
			break;
		}
	}
	if ( v6 < 0 )
		app_fatal("Out of hash space");
	if ( !v12 )
		v12 = mpqapi_new_block(&block_index);
	v9 = v7;
	sgpHashTbl[v9].hashcheck[0] = v5;
	sgpHashTbl[v9].hashcheck[1] = v11;
	sgpHashTbl[v9].lcid = 0;
	sgpHashTbl[v9].block = block_index;
	return v12;
}

_bool mpqapi_write_file_contents(char *pszName, char *pbData, int dwLen, _BLOCKENTRY *pBlk)
{
	char *v4; // esi
	char *v5; // eax
	unsigned int destsize; // ebx
	char *v7; // eax
	unsigned int v8; // esi
	_BLOCKENTRY *v9; // edi
	int v10; // eax
	signed int v11; // eax
	unsigned int v13; // eax
	unsigned int v14; // eax
	int v15; // ecx
	int size; // [esp+Ch] [ebp-10h]
	char *v17; // [esp+10h] [ebp-Ch]
	int v18; // [esp+14h] [ebp-8h]
	DWORD nNumberOfBytesToWrite; // [esp+18h] [ebp-4h]

	v4 = pszName;
	v17 = pbData;
	v5 = strchr(pszName, ':');
	destsize = 0;
	while ( v5 )
	{
		v4 = v5 + 1;
		v5 = strchr(v5 + 1, ':');
	}
	while ( 1 )
	{
		v7 = strchr(v4, '\\');
		if ( !v7 )
			break;
		v4 = v7 + 1;
	}
	Hash(v4, 3);
	v8 = dwLen;
	v9 = pBlk;
	size = 4 * ((unsigned int)(dwLen + 4095) >> 12) + 4;
	nNumberOfBytesToWrite = 4 * ((unsigned int)(dwLen + 4095) >> 12) + 4;
	v10 = mpqapi_find_free_block(size + dwLen, &pBlk->sizealloc);
	v9->offset = v10;
	v9->sizefile = v8;
	v9->flags = 0x80000100;
	if ( SetFilePointer(sghArchive, v10, NULL, FILE_BEGIN) == -1 )
		return 0;
	pBlk = 0;
	v18 = 0;
	while ( v8 )
	{
		v11 = 0;
		do
			mpq_buf[v11++] -= 86;
		while ( v11 < 4096 );
		dwLen = v8;
		if ( v8 >= 0x1000 )
			dwLen = 4096;
		memcpy(mpq_buf, v17, dwLen);
		v17 += dwLen;
		dwLen = PkwareCompress(mpq_buf, dwLen);
		if ( !v18 )
		{
			nNumberOfBytesToWrite = size;
			pBlk = (_BLOCKENTRY *)DiabloAllocPtr(size);
			memset(pBlk, 0, nNumberOfBytesToWrite);
			if ( !WriteFile(sghArchive, pBlk, nNumberOfBytesToWrite, &nNumberOfBytesToWrite, 0) )
				goto LABEL_25;
			destsize += nNumberOfBytesToWrite;
		}
		*(&pBlk->offset + v18) = destsize;
		if ( !WriteFile(sghArchive, mpq_buf, dwLen, (LPDWORD)&dwLen, 0) )
			goto LABEL_25;
		++v18;
		if ( v8 <= 0x1000 )
			v8 = 0;
		else
			v8 -= 4096;
		destsize += dwLen;
	}
	*(&pBlk->offset + v18) = destsize;
	if ( SetFilePointer(sghArchive, -destsize, NULL, FILE_CURRENT) == -1
	  || !WriteFile(sghArchive, pBlk, nNumberOfBytesToWrite, &nNumberOfBytesToWrite, 0)
	  || SetFilePointer(sghArchive, destsize - nNumberOfBytesToWrite, NULL, FILE_CURRENT) == -1 )
	{
LABEL_25:
		if ( pBlk )
			mem_free_dbg(pBlk);
		return 0;
	}
	mem_free_dbg(pBlk);
	v13 = v9->sizealloc;
	if ( destsize < v13 )
	{
		v14 = v13 - destsize;
		if ( v14 >= 0x400 )
		{
			v15 = destsize + v9->offset;
			v9->sizealloc = destsize;
			mpqapi_free_block(v15, v14);
		}
	}
	return 1;
}

int mpqapi_find_free_block(int size, int *block_size)
{
	_BLOCKENTRY *v2; // eax
	signed int v3; // esi
	int result; // eax
	int v5; // esi
	_bool v6; // zf

	v2 = sgpBlockTbl;
	v3 = 2048;
	while ( 1 )
	{
		--v3;
		if ( v2->offset )
		{
			if ( !v2->flags && !v2->sizefile && v2->sizealloc >= (unsigned int)size )
				break;
		}
		++v2;
		if ( !v3 )
		{
			*block_size = size;
			result = sgdwMpqOffset;
			sgdwMpqOffset += size;
			return result;
		}
	}
	v5 = v2->offset;
	*block_size = size;
	v2->offset += size;
	v6 = v2->sizealloc == size;
	v2->sizealloc -= size;
	if ( v6 )
		memset(v2, 0, 0x10u);
	return v5;
}

void mpqapi_rename(char *pszOld, char *pszNew)
{
	char *v2; // esi
	int v3; // eax
	_HASHENTRY *v4; // eax
	int v5; // ST00_4
	_BLOCKENTRY *v6; // edx

	v2 = pszNew;
	v3 = mpqapi_get_hash_index_of_path(pszOld);
	if ( v3 != -1 )
	{
		v4 = &sgpHashTbl[v3];
		v5 = v4->block;
		v6 = &sgpBlockTbl[v5];
		v4->block = -2;
		mpqapi_add_file(v2, v6, v5);
		save_archive_modified = 1;
	}
}

_bool mpqapi_has_file(char *pszName)
{
	return mpqapi_get_hash_index_of_path(pszName) != -1;
}

_bool mpqapi_open_archive(char *pszArchive, _bool hidden, int dwChar) // OpenMPQ
{
	char *v3; // ebp
	BOOL v4; // esi
	DWORD v6; // edi
	int v8; // eax
	int v10; // eax
	char *lpFileName; // [esp+10h] [ebp-70h]
	DWORD dwTemp; // [esp+14h] [ebp-6Ch]
	_FILEHEADER fhdr; // [esp+18h] [ebp-68h]

	v3 = pszArchive;
	v4 = hidden;
	lpFileName = pszArchive;
	InitHash();
	if ( !mpqapi_set_hidden(v3, v4) )
		return 0;
	v6 = (unsigned char)gbMaxPlayers > 1u ? FILE_FLAG_WRITE_THROUGH : 0;
	save_archive_open = 0;
	sghArchive = CreateFile(v3, GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, v6, NULL);
	if ( sghArchive == (HANDLE)-1 )
	{
		sghArchive = CreateFile(lpFileName, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, v6 | (v4 != 0 ? FILE_ATTRIBUTE_SYSTEM|FILE_ATTRIBUTE_HIDDEN : 0), NULL);
		if ( sghArchive == (HANDLE)-1 )
			return 0;
		save_archive_open = 1;
		save_archive_modified = 1;
	}
	if ( !sgpBlockTbl || !sgpHashTbl )
	{
		memset(&fhdr, 0, 0x68u);
		if ( !mpqapi_parse_archive_header(&fhdr, &sgdwMpqOffset) )
		{
LABEL_15:
			mpqapi_close_archive(lpFileName, 1, dwChar);
			return 0;
		}
		sgpBlockTbl = (_BLOCKENTRY *)DiabloAllocPtr(0x8000);
		memset(sgpBlockTbl, 0, 0x8000u);
		if ( fhdr.blockcount )
		{
			if ( SetFilePointer(sghArchive, 104, NULL, FILE_BEGIN) == -1
			  || !ReadFile(sghArchive, sgpBlockTbl, 0x8000u, &dwTemp, NULL) )
			{
				goto LABEL_15;
			}
			v8 = Hash("(block table)", 3);
			Decrypt(sgpBlockTbl, 0x8000, v8);
		}
		sgpHashTbl = (_HASHENTRY *)DiabloAllocPtr(0x8000);
		memset(sgpHashTbl, 255, 0x8000u);
		if ( fhdr.hashcount )
		{
			if ( SetFilePointer(sghArchive, 32872, NULL, FILE_BEGIN) == -1
			  || !ReadFile(sghArchive, sgpHashTbl, 0x8000u, &dwTemp, NULL) )
			{
				goto LABEL_15;
			}
			v10 = Hash("(hash table)", 3);
			Decrypt(sgpHashTbl, 0x8000, v10);
		}
	}
	return 1;
}

_bool mpqapi_parse_archive_header(_FILEHEADER *pHdr, int *pdwNextFileStart) // ParseMPQHeader
{
	int *v2; // ebp
	_FILEHEADER *v3; // esi
	DWORD v4; // eax
	DWORD v5; // edi
	DWORD NumberOfBytesRead; // [esp+10h] [ebp-4h]

	v2 = pdwNextFileStart;
	v3 = pHdr;
	v4 = GetFileSize(sghArchive, 0);
	v5 = v4;
	*v2 = v4;
	if ( v4 == -1
	  || v4 < 0x68
	  || !ReadFile(sghArchive, v3, 0x68u, &NumberOfBytesRead, NULL)
	  || NumberOfBytesRead != 104
	  || v3->signature != '\x1AQPM'
	  || v3->headersize != 32
	  || v3->version > 0u
	  || v3->sectorsizeid != 3
	  || v3->filesize != v5
	  || v3->hashoffset != 32872
	  || v3->blockoffset != 104
	  || v3->hashcount != 2048
	  || v3->blockcount != 2048 )
	{
		if ( SetFilePointer(sghArchive, 0, NULL, FILE_BEGIN) == -1 || !SetEndOfFile(sghArchive) )
			return 0;
		memset(v3, 0, 0x68u);
		v3->signature = '\x1AQPM';
		v3->headersize = 32;
		v3->sectorsizeid = 3;
		v3->version = 0;
		*v2 = 0x10068;
		save_archive_modified = 1;
		save_archive_open = 1;
	}
	return 1;
}

void mpqapi_close_archive(char *pszArchive, _bool bFree, int dwChar) // CloseMPQ
{
	char *v3; // esi
	_BLOCKENTRY *v4; // ecx
	_HASHENTRY *v5; // ecx

	v3 = pszArchive;
	if ( bFree )
	{
		v4 = sgpBlockTbl;
		sgpBlockTbl = 0;
		mem_free_dbg(v4);
		v5 = sgpHashTbl;
		sgpHashTbl = 0;
		mem_free_dbg(v5);
	}
	if ( sghArchive != (HANDLE)-1 )
	{
		CloseHandle(sghArchive);
		sghArchive = (HANDLE)-1;
	}
	if ( save_archive_modified )
	{
		save_archive_modified = 0;
		mpqapi_store_modified_time(v3, dwChar);
	}
	if ( save_archive_open )
	{
		save_archive_open = 0;
		mpqapi_store_creation_time(v3, dwChar);
	}
}

void mpqapi_store_modified_time(char *pszArchive, int dwChar)
{
	int v2; // esi
	char *v3; // ebx
	HANDLE v4; // eax
	int v5; // esi
	struct _WIN32_FIND_DATAA FindFileData; // [esp+8h] [ebp-1E0h]
	char dst[160]; // [esp+148h] [ebp-A0h]

	v2 = dwChar;
	v3 = pszArchive;
	if ( gbMaxPlayers != 1 )
	{
		mpqapi_reg_load_modification_time(dst, 160);
		v4 = FindFirstFile(v3, &FindFileData);
		if ( v4 != (HANDLE)-1 )
		{
			FindClose(v4);
			v5 = 16 * v2;
			*(_DWORD *)&dst[v5 + 8] = FindFileData.ftLastWriteTime.dwLowDateTime;
			*(_DWORD *)&dst[v5 + 12] = FindFileData.ftLastWriteTime.dwHighDateTime;
			mpqapi_reg_store_modification_time(dst, 160);
		}
	}
}

void mpqapi_flush_and_close(char *pszArchive, _bool bFree, int dwChar)
{
	if ( sghArchive != (HANDLE)-1 )
	{
		if ( save_archive_modified )
		{
			if ( mpqapi_can_seek() )
			{
				if ( mpqapi_write_header() )
				{
					if ( mpqapi_write_block_table() )
						mpqapi_write_hash_table();
				}
			}
		}
	}
	mpqapi_close_archive(pszArchive, bFree, dwChar);
}

_bool mpqapi_write_header() // WriteMPQHeader
{
	_bool result; // al
	_FILEHEADER fhdr; // [esp+8h] [ebp-6Ch]
	DWORD NumberOfBytesWritten; // [esp+70h] [ebp-4h]

	memset(&fhdr, 0, 0x68u);
	fhdr.signature = '\x1AQPM';
	fhdr.headersize = 32;
	fhdr.filesize = GetFileSize(sghArchive, 0);
	fhdr.version = 0;
	fhdr.sectorsizeid = 3;
	fhdr.hashoffset = 32872;
	fhdr.blockoffset = 104;
	fhdr.hashcount = 2048;
	fhdr.blockcount = 2048;
	if ( SetFilePointer(sghArchive, 0, NULL, FILE_BEGIN) != -1 && WriteFile(sghArchive, &fhdr, 0x68u, &NumberOfBytesWritten, 0) )
		result = NumberOfBytesWritten == 104;
	else
		result = 0;
	return result;
}

_bool mpqapi_write_block_table()
{
	int v1; // eax
	BOOL v2; // ebx
	int v3; // eax
	DWORD NumberOfBytesWritten; // [esp+4h] [ebp-4h]

	if ( SetFilePointer(sghArchive, 104, NULL, FILE_BEGIN) == -1 )
		return 0;
	v1 = Hash("(block table)", 3);
	Encrypt(sgpBlockTbl, 0x8000, v1);
	v2 = WriteFile(sghArchive, sgpBlockTbl, 0x8000u, &NumberOfBytesWritten, 0);
	v3 = Hash("(block table)", 3);
	Decrypt(sgpBlockTbl, 0x8000, v3);
	return v2 && NumberOfBytesWritten == 0x8000;
}

_bool mpqapi_write_hash_table()
{
	int v1; // eax
	BOOL v2; // ebx
	int v3; // eax
	DWORD NumberOfBytesWritten; // [esp+4h] [ebp-4h]

	if ( SetFilePointer(sghArchive, 32872, NULL, FILE_BEGIN) == -1 )
		return 0;
	v1 = Hash("(hash table)", 3);
	Encrypt(sgpHashTbl, 0x8000, v1);
	v2 = WriteFile(sghArchive, sgpHashTbl, 0x8000u, &NumberOfBytesWritten, 0);
	v3 = Hash("(hash table)", 3);
	Decrypt(sgpHashTbl, 0x8000, v3);
	return v2 && NumberOfBytesWritten == 0x8000;
}

_bool mpqapi_can_seek()
{
	_bool result; // al

	if ( SetFilePointer(sghArchive, sgdwMpqOffset, NULL, FILE_BEGIN) == -1 )
		result = 0;
	else
		result = SetEndOfFile(sghArchive);
	return result;
}
