<NME> utils.cpp
<BEF> #include <fstream>

#include "main.h"
#include "utils.h"
#include "textures.h"

long getFileSize(FILE *file)
{
    long lCurPos, lEndPos;
    lCurPos = ftell(file);
    fseek(file, 0, 2);
    lEndPos = ftell(file);
    fseek(file, lCurPos, 0);
    return lEndPos;
}

long ConvertInt16(unsigned char Byte1, unsigned char Byte2)
{
//return Byte1 << 8 | Byte2 ;
return Byte2 << 8 | Byte1 ;
}

long ConvertInt24(unsigned char Byte1, unsigned char Byte2,  unsigned char Byte3)
{
return Byte3 << 16 | Byte2 << 8 | Byte1 ;
}

long ConvertInt32(unsigned char Byte1, unsigned char Byte2,  unsigned char Byte3,  unsigned char Byte4)
{
return Byte4 << 24 | Byte3 << 16 | Byte2 << 8 | Byte1 ;		//24 was 32
}

long getValAtAddress(unsigned char *buffer, long Address, int size)
	{//Gets contents of bytes the the specific integer address. int(8), int(16), int(32) per uw-formats.txt
	if (Address < 0)
		{
		printf("Invalid Address Error\n");
		}
		switch (size)
		{
		case 8:
			{return buffer[Address];}
		case 16:
			{return ConvertInt16(buffer[Address],buffer[Address+1]);}
		case 24:
			{return ConvertInt24(buffer[Address],buffer[Address+1],buffer[Address+2]);}
		case 32:	//may be buggy!
			{return ConvertInt32(buffer[Address], buffer[Address + 1], buffer[Address + 2], buffer[Address + 3]); }
		default:
			{
			printf("Invalid size entered!");
			return -1;
			}
		}
	}



int getValAtCoordinate(int x, int y, int BlockStart,unsigned char *buffer,int size)
{
	int val = getValAtAddress(buffer, BlockStart + (x*4) + (y * (4 * 64)),size);
	return val;
}


// ua_uw2_import methods

/*! the function reads in compressed blocks from uw2 .ark files and creates
a SDL_RWops struct to transparently access it.

The code was adapted from the LoW project: http://low.sourceforge.net/

\param fd        an open .ark file
\param blocknum  block number to read in
\param destsize  number of bytes which should be read from the block
*/
unsigned char *get_rwops_uw2dec(unsigned char *buffer, unsigned int blocknum, int *datalen)
	{
	// read in number of blocks
	*datalen = 0;
	long addressPointer = 0; 
	int nblocks = getValAtAddress(buffer, 0, 16); //fread16(fd);

	// read in offset
	addressPointer += blocknum * 4 + 6;
	int offset = getValAtAddress(buffer, addressPointer, 32);

	if (offset == 0)
		return NULL; // no block

	// read in flags
	addressPointer = (blocknum + nblocks) * 4 + 6;
	int flags = getValAtAddress(buffer, addressPointer, 32);  

	// read in real block size
	addressPointer = (blocknum + nblocks * 2) * 4 + 6;
	int blocksize = getValAtAddress(buffer, addressPointer, 32);  
	
	// read in available block size
	addressPointer = (blocknum + nblocks * 3) * 4 + 6;
	int avail = getValAtAddress(buffer, addressPointer, 32);  //fread32(fd);


	// read in source data
	unsigned char *src = &buffer[offset]; //= new unsigned char[blocksize];
	//addressPointer = offset;
	//for (int i = 0; i < blocksize; i++)
	//	{
	//	src[i] = buffer[addressPointer + i];
	//	}
	long destsize = getValAtAddress(src, 0, 32) + 100;
	
		printf("uw2dec: reading in block %u:\n offset=%06x, flags=%u, blocksize=%04x, avail=%04x, destsize=%04x\n",
			blocknum, offset, flags, blocksize, avail, destsize);

	// allocate destination array
	unsigned char *dest = new unsigned char[destsize];
	//for (int i = 0; i < destsize; i++)
	//	{
	//	dest[i] = 0;
	//	}

	// decode uw2 compression scheme
	if ((flags & 2) != 0)
		{
		// compressed data
		unsigned char * ubuf = dest;
		unsigned char * cp = &src[4];
		unsigned char * ce = &src[blocksize];
		unsigned char * up = ubuf;
		unsigned char * ue = ubuf + destsize;

		while (up<ue && cp<ce)
			{
			unsigned char bits = *cp++;

			for (int i = 0; i<8; i++, bits >>= 1)
				{
				if (bits & 1)
					{
					*up++ = *cp++;
					*datalen = *datalen + 1;
					}
				else
					{
					signed int m1 = *cp++; // m1: pos
					signed int m2 = *cp++; // m2: run

					m1 |= (m2 & 0xF0) << 4;

					// correct for sign bit
					if (m1 & 0x800)
						m1 |= 0xFFFFF000;

					// add offsets
					m2 = (m2 & 0x0F) + 3;
					m1 += 18;

					if (m1 > up - ubuf)
						printf("uw2dec: pos exceeds buffer!");

					// adjust pos to current 4k segment
					while (m1 < (up - ubuf - 0x1000))
						m1 += 0x1000;

					while (m2-- && up < ue)
						{
						*up++ = ubuf[m1++];
						*datalen = *datalen + 1;
						}
						
					}
				if (up >= ue || cp >= ce)
					break;
				}
			}

		printf(" decoded %04x compressed bytes to %04x uncompressed data.\n",
			cp - &src[4], up - ubuf);
		}
	else
		{
		// uncompressed
		memcpy(dest, &src[0], blocksize);
		*datalen = blocksize;

		printf(" block was uncompressed.\n");
		}

	return dest;
	}



unsigned char* unpackUW2(unsigned char *tmp, int address_pointer, int *datalen)
  {
  
 //Robbed and changed slightly from the Labyrinth of Worlds implementation project.
 //This decompresses UW2 blocks.
  fprintf(LOGFILE, "Unpacking block");
    int	len = getValAtAddress(tmp,address_pointer,32);	//lword(base);
    unsigned char*	buf = new unsigned char[len+100];
    unsigned char*	up = buf;
	*datalen = 0;
    address_pointer += 4;
	int upPtr = 0;
	int bitBlock = 0;
    while(up < buf+len)
      {
		int	bits = tmp[address_pointer++];
		//fprintf(LOGFILE, "\n\tBit Block %d at %d is %d", bitBlock++, address_pointer, bits);
		for(int r=0; r<8; r++)
		  {
			if(bits&1)
			{
			//printf("transfer %d\ at %d\n", byte(base),base);
			//fprintf(LOGFILE, "\n\t\tTransferring from %d to %d Value %d", address_pointer, upPtr++, tmp[address_pointer]);
			*up++ = tmp[address_pointer++];
			*datalen = *datalen+1;
			}
			else
			  {
				int	o = tmp[address_pointer++];
				int	c = tmp[address_pointer++];

				o |= (c&0xF0)<<4;
				c = (c&15) + 3;
				o = o+18;
				int OrigOffset = o;
				int uplessbuf = up - buf;
				if(o > (up-buf))
					o -= 0x1000;
				while(o < (up-buf-0x1000))
					o += 0x1000;
		 
				//fprintf(LOGFILE, "\n\t\tCopy Record C= %d  O=%d  (orig offset=%d)", c, o, OrigOffset);
				while(c--)
					{
					//if (o < 0)
					//	{
					//	printf("Offset is less than 0!");
					//	}
					//fprintf(LOGFILE, "\n\t\t\tCopying Value %d from %d to %d ", buf[o], o, upPtr++);
				//	fprintf(LOGFILE, "%d ", buf[o]);
					*up++ = buf[o++];
					*datalen = *datalen+1;
					}
				  }
			bits >>= 1;
		  }
      }

    return buf;
}


//****************************************************************************

/* The following procedure comes straight from Jim Cameron
   http://madeira.physiol.ucl.ac.uk/people/jim
   Specifically, this procedure can be found on his "Unofficial System Shock
   Specifications" page at
   http://madeira.physiol.ucl.ac.uk/people/jim/games/ss-res.txt
*/
void unpack_data (unsigned char *pack,    unsigned char *unpack,
		  unsigned long unpacksize)
{

  unsigned char *byteptr;
  unsigned char *exptr;
  unsigned long word = 0;  /* initialise to stop "might be used before set" */
  int nbits;
/*    int type; */
  int val;

  int ntokens = 0;
  static int offs_token [16384];
  static int len_token  [16384];
  static int org_token  [16384];

  int i;

  for (i = 0; i < 16384; ++i)
  {
    len_token [i] = 1;
    org_token [i] = -1;
  }
  memset (unpack, 0, unpacksize);

  byteptr = pack;
  exptr   = unpack;
  nbits = 0;

  while (exptr - unpack < unpacksize)
  {

    while (nbits < 14)
    {
      word = (word << 8) + *byteptr++;
      nbits += 8;
    }

    nbits -= 14;
    val = (word >> nbits) & 0x3FFF;
    if (val == 0x3FFF)
    {
      break;
    }

    if (val == 0x3FFE)
    {
      for (i = 0; i < 16384; ++i)
      {
	len_token [i] = 1;
	org_token [i] = -1;
      }
      ntokens = 0;
      continue;
    }

    if (ntokens < 16384)
    {
      offs_token [ntokens] = exptr - unpack;
      if (val >= 0x100)
      {
	org_token [ntokens] = val - 0x100;
      }
		printf("");
	fileSize = getFileSize(file);
	lev_ark = new unsigned char[fileSize];
	//tex_ark = new unsigned char[fileSize];
	fread(lev_ark, fileSize, 1, file);
	//fread(tex_ark,fileSize,1,file);
	fclose(file);

	NoOfBlocks = getValAtAddress(lev_ark,0,16);
    else

	//tables that I have to write.
	long BlockAddress[320];	//No of blocks in UW2
	int CompressionFlags[320];
	int DataSize[320];
	int AvailableSpace[320];
	long currAddress;
	long address_pointer = 6;

	BlockAddress[0] = getValAtAddress(lev_ark, 6 , 32);//The first block
	long LastBlockAddress = BlockAddress[0];
	for (int x = 0; x < 320; x++)
		{
		if (x < 80)
			{
			currAddress = getValAtAddress(lev_ark, 6 + (x * 4), 32);
			if (currAddress != 0)
				{
				if (x >=1)
					{
					BlockAddress[x] = LastBlockAddress + 0x7c08;//Size of a map block
					LastBlockAddress = BlockAddress[x];
					}
				}
			else
		int chunkId = getValAtAddress(tmp_ark,address_pointer,16);
		*chunkUnpackedLength =getValAtAddress(tmp_ark,address_pointer+2,24);
		*chunkType = getValAtAddress(tmp_ark,address_pointer+5,8);	//Compression.
			}
		else
			{
			currAddress = getValAtAddress(lev_ark, 6 + (x * 4), 32);
			if (currAddress != 0)
				{
				BlockAddress[x] = LastBlockAddress + getValAtAddress(lev_ark, address_pointer + (3 * (NoOfBlocks * 4)) + (x * 4), 32);
				LastBlockAddress = BlockAddress[x];
				}
			else
				{
				BlockAddress[x] = 0;
				}
			}
		}
	
	//////if ((file = fopen(UW2_OUT_PATH, "w+b")) == NULL)
		

		address_pointer=address_pointer+10;			
		}
		
	if (blnLevelFound == 0)
		{
		//printf("Level not found"); 
		return -1;
		}
	else
		{
		return AddressOfBlockStart;
		}
}

int LoadShockChunk(long AddressOfBlockStart, int chunkType, unsigned char *archive_ark, unsigned char *OutputChunk,long chunkPackedLength,long chunkUnpackedLength)
{
//Util to return an uncompressed shock block. Will use this for all future lookups and replace old ones


	int chunkId;
//	long chunkUnpackedLength;
	//int chunkType=Compressed;//compression type
	//long chunkPackedLength;
	//long chunkContentType;
	long filepos;
//	long AddressOfBlockStart=0;
	long address_pointer=4;
	//int blnLevelFound=0;		
	


	//Find the address of the block. This will also return the file size.
	//AddressOfBlockStart = getShockBlockAddress(ChunkNo,archive_ark,&chunkPackedLength,&chunkUnpackedLength,&chunkType);  	
	if (AddressOfBlockStart == -1)	{return -1;}
	
	//if (chunkType ==1)
	switch (chunkType)
		{
		case 0:
			{//Flat uncompressed
			for (long k=0; k< chunkUnpackedLength; k++)
				{
					OutputChunk[k] = archive_ark[AddressOfBlockStart+k];
				}		
			return chunkUnpackedLength;
			break;
			}
		case 1:	
	{
		if (x<80)
			{
			WriteInt32(file, 0);
			}
		else
		{//copy the existing flags.
			int compressionFlag = getValAtAddress(lev_ark, address_pointer + (NoOfBlocks * 4) + (x * 4), 32);
			WriteInt32(file,compressionFlag);
		}
	}
	//write the space used
	for (int x = 0; x < 320; x++)
	{
		if (x <80)
		{
			WriteInt32(file, 0x7c08);
		}
		else
		{//copy the existing values
			int DataLen = getValAtAddress(lev_ark, address_pointer + (2 * (NoOfBlocks * 4)) + (x * 4), 32);
			WriteInt32(file, DataLen);
		}
	}
	//write my available space should not matter for compression so I'll just put the block size here.
	for (int x = 0; x < 320; x++)
	{
		if (x <80)
		{
			WriteInt32(file, 0x7c08);
		}
		else
		{//copy the existing values
			}
		}
}

	//write my uncompressed blocks.
	for (int x = 0; x < 320; x++)
		{
			long currAddress = getValAtAddress(lev_ark, 6 + (x * 4), 32);
			int compressionFlag = getValAtAddress(lev_ark, address_pointer + (NoOfBlocks * 4) + (x * 4), 32);
			int DataLen = getValAtAddress(lev_ark, address_pointer + (3 * (NoOfBlocks * 4)) + (x * 4), 32);
			int isCompressed = (compressionFlag >> 1) & 0x01;
			if (x < 80)
				{
					switch (isCompressed)
					{
					case 0:
						//DataSize[x] = DataLen;
						for (int y = currAddress; y < 0x7c08; y++)
						{//Copy the bytes
							fputc(lev_ark[y], file);
						}
						break;
					case 1://compressed block
					case 2:
						unsigned char *tmp_ark;
						tmp_ark = unpack(lev_ark, currAddress, &DataLen);
						//DataSize[x] = DataLen;
						for (int y = 0; y < 0x7c08; y++)
						{//Copy the bytes
							fputc(tmp_ark[y], file);
						}
						break;
					}
				}
			else
				{	//non map. just copy the bytes
				//DataSize[x] = DataLen;
				for (int y = currAddress; y < currAddress+DataLen; y++)
					{//Copy the bytes
						fputc(lev_ark[y], file);
					}
				}
		}
	{//Just dump out some original data for info.


	fclose(file);
	//////if ((file = fopen(UW2_OUT_PATH, "w+b")) == NULL)
	//////	printf("Could not open specified file\n");
	//////else
			{
			if (x == 80)
				{
				printf("");
				}
			if (currAddress != 0)
				{//Map blocks are always compressed in UW2.
				if (isCompressed == 1)
					{
					unpackUW2(lev_ark, currAddress, &DataLen);		//Unpack and see how much space I need to allow for.
					mapSize[x]=DataLen;
					
					if (FoundFirst == 0)
						{//The first block containing data stays the same.
						if (REPACK_INTO_UW1_HACK == 1)
							{
							BlockAddress[x] = 1286;//Conversation start //currAddress;
							}
						else
							{
							BlockAddress[x]=currAddress;
							}
						
						firstBlock=x;
						FoundFirst = 1;
						}
					else
						{
						BlockAddress[x] = LastBlockAddress + PreviousUsedLength;  //Size of a map block
						}					
					LastBlockAddress = BlockAddress[x];
					PreviousUsedLength = mapSize[x];
					}
				else
					{
					if (FoundFirst == 0)
						{
						BlockAddress[x] = currAddress;
						firstBlock = x;
						FoundFirst = 1;
						}
					else
						{
						BlockAddress[x] = LastBlockAddress + PreviousUsedLength;
						}					
				    LastBlockAddress = BlockAddress[x];
				    PreviousUsedLength = getValAtAddress(lev_ark, address_pointer + (UW2_SIZE_BLOCK * (NoOfBlocks * 4)) + (x * 4), 32);
				    //Set mapsize here???
					}
				}
			else
				{
					BlockAddress[x] = 0; 
					mapSize[x]=0;
				}
			}
		else
			{
			if (currAddress != 0)
				{//is this correct for all compression flags???
				BlockAddress[x] = LastBlockAddress + PreviousUsedLength;
				LastBlockAddress = BlockAddress[x];
				PreviousUsedLength = getValAtAddress(lev_ark, address_pointer + (UW2_SIZE_BLOCK * (NoOfBlocks * 4)) + (x * 4), 32);
				}
			else
				{
				BlockAddress[x] = 0;
				}
			}
		fprintf(LOGFILE, "\nBlock Address %d = %d", x, BlockAddress[x]);
		}
	
	if ((file = fopen(OutputFile, "w+b")) == NULL)
		{
		fprintf(LOGFILE, "Could not open specified file\n");
		return;
		}

	//Write the number of blocks
	WriteInt16(file,NoOfBlocks);

	//write 4x0
//was wrrite int 32. conversations have 2? maps have 4?
	WriteInt32(file, 0);


	//write my block addresses. increment by the size of the decompressed data.
	for (int x = 0; x < NoOfBlocks; x++)
	{
		//long currAddress = getValAtAddress(lev_ark, 6 + (x * 4), 32);

		fprintf(LOGFILE, "\nBlock %d at %d",x, BlockAddress[x]);

			WriteInt32(file, BlockAddress[x]);
	
	}

	if (REPACK_INTO_UW1_HACK==0)
		{
					//write my compression flags. each shoudld be 0 0 0
					for (int x = 0; x < NoOfBlocks; x++)
					{
					if (x == 80)
						{
						printf("");
						}
						compressionFlag = getValAtAddress(lev_ark, address_pointer + (NoOfBlocks * 4) + (x * 4), 32);
						DataLen = getValAtAddress(lev_ark, address_pointer + (UW2_SIZE_BLOCK * (NoOfBlocks * 4)) + (x * 4), 32);
						isCompressed = (compressionFlag >> 1) & 0x01;
						if (x<BlocksToUnpack)
							{
								WriteInt32(file, 0);
							}
						else
						{//copy the existing flags.
							compressionFlag = getValAtAddress(lev_ark, address_pointer + (NoOfBlocks * 4) + (x * 4), 32);
							WriteInt32(file,compressionFlag);
						}
					}
					//write the space used
					for (int x = 0; x < NoOfBlocks; x++)
					{
						currAddress = getValAtAddress(lev_ark, 6 + (x * 4), 32);
						if (x <BlocksToUnpack)
						{
							if (currAddress != 0)
								{
								WriteInt32(file, mapSize[x]);
								}
							else
								{
								DataLen = getValAtAddress(lev_ark, address_pointer + (UW2_SIZE_BLOCK * (NoOfBlocks * 4)) + (x * 4), 32);
								WriteInt32(file, DataLen);
								}
						}
						else
						{//copy the existing values
							DataLen = getValAtAddress(lev_ark, address_pointer + (UW2_SIZE_BLOCK * (NoOfBlocks * 4)) + (x * 4), 32);
							WriteInt32(file, DataLen);
						}
					}
					//write my available space should not matter for decompression so I'll just put the block size here (?)
					for (int x = 0; x < NoOfBlocks; x++)
					{
						currAddress = getValAtAddress(lev_ark, 6 + (x * 4), 32);
						if (x <BlocksToUnpack)
						{
							if (currAddress != 0)
							{
								WriteInt32(file, mapSize[x]);
							}
							else
							{
								int DataLen = getValAtAddress(lev_ark, address_pointer + (UW2_SIZE_BLOCK * (NoOfBlocks * 4)) + (x * 4), 32);
								WriteInt32(file, DataLen);
							}
						}
						else
						{//copy the existing values
							int DataLen = getValAtAddress(lev_ark, address_pointer + (UW2_SIZE_BLOCK * (NoOfBlocks * 4)) + (x * 4), 32);
							WriteInt32(file, DataLen);
						}
					}
		}

	//write my uncompressed blocks.
	for (int x = 0; x < NoOfBlocks; x++)
		{
		if (x == 80)
			{
			printf("");
			}
			currAddress = getValAtAddress(lev_ark, 6 + (x * 4), 32);
			compressionFlag = getValAtAddress(lev_ark, address_pointer + (NoOfBlocks * 4) + (x * 4), 32);
			DataLen = getValAtAddress(lev_ark, address_pointer + (UW2_SIZE_BLOCK * (NoOfBlocks * 4)) + (x * 4), 32);
			isCompressed = (compressionFlag >> 1) & 0x01;
			if (x < BlocksToUnpack)
				{
				if (currAddress!=0)
					{
					switch (isCompressed)
						{
						case 0:
							//DataSize[x] = DataLen;
							for (int y = currAddress; y < currAddress + DataLen; y++)
							{//Copy the bytes
								fputc(lev_ark[y], file);
							}
							break;
						case 1://compressed block
						case 2:
							unsigned char *tmp_ark;
							tmp_ark = unpackUW2(lev_ark, currAddress, &DataLen);
							//DataSize[x] = DataLen;
							for (int y = 0; y < mapSize[x]; y++)
							{//Copy the bytes
								fputc(tmp_ark[y], file);
							}
							break;
						}
					}
				}
			else
				{	//non map. just copy the bytes
				if (currAddress != 0)
					{
					for (int y = currAddress; y < currAddress+DataLen; y++)
						{//Copy the bytes
							fputc(lev_ark[y], file);
						}
					}
				}
		}



	fclose(file);


	if ((file = fopen(OutputFile, "rb")) == NULL)
		{
		fprintf(LOGFILE, "Could not open specified file\n");
			return;
		}
	fileSize = getFileSize(file);
	lev_ark = new unsigned char[fileSize];
	fread(lev_ark, fileSize, 1, file);
	fclose(file);
	fprintf(LOGFILE, "New Blocks\n");
	for (int x = 0; x < NoOfBlocks; x++)
	{
		currAddress = getValAtAddress(lev_ark, 6 + (x * 4), 32);
		compressionFlag = getValAtAddress(lev_ark, address_pointer + (NoOfBlocks * 4) + (x * 4), 32);
		long DataSizeVal = getValAtAddress(lev_ark, address_pointer + (UW2_SIZE_BLOCK * (NoOfBlocks * 4)) + (x * 4), 32);
		long DataAvail = getValAtAddress(lev_ark, address_pointer + (UW2_SPACE_BLOCK * (NoOfBlocks * 4)) + (x * 4), 32);

		fprintf(LOGFILE, "Block no %d\n", x);
		fprintf(LOGFILE, "\tAddress %d", currAddress);
		fprintf(LOGFILE, "\tFlags %d\n", compressionFlag);
		fprintf(LOGFILE, "\tData Size %d", DataSizeVal);
		fprintf(LOGFILE, "\tAvailable %d\n", DataAvail);
		fprintf(LOGFILE, "\tNext if using datasize %d\n", currAddress + DataSizeVal);
		fprintf(LOGFILE, "\tNext if using available %d\n", currAddress + DataAvail);


	}
}*/

/*
void RepackUW2(char InputFile[255], char OutputFile[255], int BlocksToUnpack)
	{
	//hopefully repacks a compressed level file into one containing uncompressed chuncks that I can edit to test object properties.

	FILE *file = NULL;
	char *filePath;
	//char *filePathO;
	long fileSize;
	unsigned char *lev_ark;
	int NoOfBlocks;
	if ((file = fopen(InputFile, "rb")) == NULL)
		{
		printf("Could not open specified file\n");
		return;
		}
	fileSize = getFileSize(file);
	lev_ark = new unsigned char[fileSize];
	fread(lev_ark, fileSize, 1, file);
	fclose(file);

	NoOfBlocks = getValAtAddress(lev_ark, 0, 16);


	//tables that I have to write.
	long *BlockAddress;
	BlockAddress = new long[NoOfBlocks];
	//	long BlockAddress[NoOfBlocks];	//No of blocks in UW2
	long PreviousUsedLength;
	//int CompressionFlags[NoOfBlocks];
	//int DataSize[NoOfBlocks];
	//int AvailableSpace[NoOfBlocks];
	long currAddress;
	long address_pointer = 6;

	int compressionFlag;
	int DataLen;
	int isCompressed;
	long *mapSize;
	mapSize = new long[NoOfBlocks];
	//long mapSize[BlocksToUnpack];// = 0x7c08;
	printf("Original Blocks\n");
	for (int x = 0; x < NoOfBlocks; x++)
		{//Just dump out some original data for info.
		currAddress = getValAtAddress(lev_ark, 6 + (x * 4), 32);
		compressionFlag = getValAtAddress(lev_ark, address_pointer + (UW2_COMPRESS_BLOCK *(NoOfBlocks * 4)) + (x * 4), 32);
		long DataSizeVal = getValAtAddress(lev_ark, address_pointer + (UW2_SIZE_BLOCK * (NoOfBlocks * 4)) + (x * 4), 32);
		long DataAvail = getValAtAddress(lev_ark, address_pointer + (UW2_SPACE_BLOCK * (NoOfBlocks * 4)) + (x * 4), 32);

		printf("Block no %d\n", x);
		printf("\tAddress %d", currAddress);
		printf("\tFlags %d\n", compressionFlag);
		printf("\tData Size %d", DataSizeVal);
		printf("\tAvailable %d\n", DataAvail);
		printf("\tNext if using datasize %d\n", currAddress + DataSizeVal);
		printf("\tNext if using available %d\n", currAddress + DataAvail);
		//if (x < BlocksToUnpack)
		//	{//This default size covers most of the map data except for the animation overlays + other stuff I know nothing about.
		//	mapSize[x]=0x7c08;//default size
		mapSize[x] = DataSizeVal;
		//	}
		}

	//Initial values for the loop for calculating block addresses.
	BlockAddress[0] = getValAtAddress(lev_ark, 6, 32);//The first block stays the same
	long LastBlockAddress = BlockAddress[0];
	PreviousUsedLength = 0;

	for (int x = 0; x < NoOfBlocks; x++)
		{
		currAddress = getValAtAddress(lev_ark, 6 + (x * 4), 32);
		compressionFlag = getValAtAddress(lev_ark, address_pointer + (NoOfBlocks * 4) + (x * 4), 32);
		DataLen = getValAtAddress(lev_ark, address_pointer + (UW2_SIZE_BLOCK * (NoOfBlocks * 4)) + (x * 4), 32);
		isCompressed = (compressionFlag >> 1) & 0x01;
		if (x < BlocksToUnpack)
			{
			if (currAddress != 0)
				{//Map blocks are always compressed in UW2.
				if (isCompressed == 1)
					{
					unpackUW2(lev_ark, currAddress, &DataLen);		//Unpack and see how much space I need to allow for.
					mapSize[x] = DataLen;
					BlockAddress[x] = LastBlockAddress + PreviousUsedLength;  //Size of a map block
					LastBlockAddress = BlockAddress[x];
					PreviousUsedLength = mapSize[x];
					}
				else
					{
					BlockAddress[x] = LastBlockAddress + PreviousUsedLength;
					LastBlockAddress = BlockAddress[x];
					PreviousUsedLength = getValAtAddress(lev_ark, address_pointer + (UW2_SIZE_BLOCK * (NoOfBlocks * 4)) + (x * 4), 32);
					//Set mapsize here???
					}
				}
			else
				{
				BlockAddress[x] = 0;
				mapSize[x] = 0;
				}
			}
		else
			{
			if (currAddress != 0)
				{//is this correct for all compression flags???
				BlockAddress[x] = LastBlockAddress + PreviousUsedLength;
				LastBlockAddress = BlockAddress[x];
				PreviousUsedLength = getValAtAddress(lev_ark, address_pointer + (UW2_SIZE_BLOCK * (NoOfBlocks * 4)) + (x * 4), 32);
				}
			else
				{
				BlockAddress[x] = 0;
				}
			}
		printf("\nBlock Address %d = %d", x, BlockAddress[x]);
		}

	if ((file = fopen(OutputFile, "w+b")) == NULL)
		{
		printf("Could not open specified file\n");
		return;
		}


	//Write the number of blocks
	WriteInt16(file, NoOfBlocks);
	//write 4x0
	WriteInt32(file, 0);

	//write my block addresses. increment by the size of the decompressed data.
	for (int x = 0; x < NoOfBlocks; x++)
		{
		//long currAddress = getValAtAddress(lev_ark, 6 + (x * 4), 32);
		WriteInt32(file, BlockAddress[x]);
		}

	//write my compression flags. each shoudld be 0 0 0
	for (int x = 0; x < NoOfBlocks; x++)
		{
		compressionFlag = getValAtAddress(lev_ark, address_pointer + (NoOfBlocks * 4) + (x * 4), 32);
		DataLen = getValAtAddress(lev_ark, address_pointer + (UW2_SIZE_BLOCK * (NoOfBlocks * 4)) + (x * 4), 32);
		isCompressed = (compressionFlag >> 1) & 0x01;
		if (x<BlocksToUnpack)
			{//TODO:Bit mask the flag out
			WriteInt32(file, 0);
			}
		else
			{//copy the existing flags.
			compressionFlag = getValAtAddress(lev_ark, address_pointer + (NoOfBlocks * 4) + (x * 4), 32);
			WriteInt32(file, compressionFlag);
			}
		}
	//write the space used
	for (int x = 0; x < NoOfBlocks; x++)
		{
		currAddress = getValAtAddress(lev_ark, 6 + (x * 4), 32);
		if (x <BlocksToUnpack)
			{
			if (currAddress != 0)
				{
				WriteInt32(file, mapSize[x]);
				}
			else
				{
				DataLen = getValAtAddress(lev_ark, address_pointer + (UW2_SIZE_BLOCK * (NoOfBlocks * 4)) + (x * 4), 32);
				WriteInt32(file, DataLen);
				}
			}
		else
			{//copy the existing values
			DataLen = getValAtAddress(lev_ark, address_pointer + (UW2_SIZE_BLOCK * (NoOfBlocks * 4)) + (x * 4), 32);
			WriteInt32(file, DataLen);
			}
		}
	//write my available space should not matter for decompression so I'll just put the block size here (?)
	for (int x = 0; x < NoOfBlocks; x++)
		{
		currAddress = getValAtAddress(lev_ark, 6 + (x * 4), 32);
		if (x <BlocksToUnpack)
			{
			if (currAddress != 0)
				{
				WriteInt32(file, mapSize[x]);
				}
			else
				{
				int DataLen = getValAtAddress(lev_ark, address_pointer + (UW2_SIZE_BLOCK * (NoOfBlocks * 4)) + (x * 4), 32);
				WriteInt32(file, DataLen);
				}
			}
		else
			{//copy the existing values
			int DataLen = getValAtAddress(lev_ark, address_pointer + (UW2_SIZE_BLOCK * (NoOfBlocks * 4)) + (x * 4), 32);
			WriteInt32(file, DataLen);
			}
		}
	//write my uncompressed blocks.
	for (int x = 0; x < NoOfBlocks; x++)
		{
		currAddress = getValAtAddress(lev_ark, 6 + (x * 4), 32);
		compressionFlag = getValAtAddress(lev_ark, address_pointer + (NoOfBlocks * 4) + (x * 4), 32);
		DataLen = getValAtAddress(lev_ark, address_pointer + (UW2_SIZE_BLOCK * (NoOfBlocks * 4)) + (x * 4), 32);
		isCompressed = (compressionFlag >> 1) & 0x01;
		if (x < BlocksToUnpack)
			{
			if (currAddress != 0)
				{
				switch (isCompressed)
					{
						case 0:
							//DataSize[x] = DataLen;
							for (int y = currAddress; y < currAddress + DataLen; y++)
								{//Copy the bytes
								fputc(lev_ark[y], file);
								}
							break;
						case 1://compressed block
						case 2:
							unsigned char *tmp_ark;
							tmp_ark = unpackUW2(lev_ark, currAddress, &DataLen);
							//DataSize[x] = DataLen;
							for (int y = 0; y < mapSize[x]; y++)
								{//Copy the bytes
								fputc(tmp_ark[y], file);
								}
							break;
					}
				}
			}
		else
			{	//non map. just copy the bytes
			if (currAddress != 0)
				{
				for (int y = currAddress; y < currAddress + DataLen; y++)
					{//Copy the bytes
					fputc(lev_ark[y], file);
					}
				}
			}
		}



	fclose(file);


	if ((file = fopen(OutputFile, "rb")) == NULL)
		{
		printf("Could not open specified file\n");
		return;
		}
	fileSize = getFileSize(file);
	lev_ark = new unsigned char[fileSize];
	fread(lev_ark, fileSize, 1, file);
	fclose(file);
	printf("New Blocks\n");
	for (int x = 0; x < NoOfBlocks; x++)
		{
		currAddress = getValAtAddress(lev_ark, 6 + (x * 4), 32);
		compressionFlag = getValAtAddress(lev_ark, address_pointer + (NoOfBlocks * 4) + (x * 4), 32);
		long DataSizeVal = getValAtAddress(lev_ark, address_pointer + (UW2_SIZE_BLOCK * (NoOfBlocks * 4)) + (x * 4), 32);
		long DataAvail = getValAtAddress(lev_ark, address_pointer + (UW2_SPACE_BLOCK * (NoOfBlocks * 4)) + (x * 4), 32);

		printf("Block no %d\n", x);
		printf("\tAddress %d", currAddress);
		printf("\tFlags %d\n", compressionFlag);
		printf("\tData Size %d", DataSizeVal);
		printf("\tAvailable %d\n", DataAvail);
		printf("\tNext if using datasize %d\n", currAddress + DataSizeVal);
		printf("\tNext if using available %d\n", currAddress + DataAvail);
		}
	}
*/



void RepackUW2(char InputFile[255], char OutputFile[255], int BlocksToUnpack)
	{
	//hopefully repacks a compressed level file into one containing uncompressed chuncks that I can edit to test object properties.

	long WritePointer = 0;
	FILE *file = NULL;
	char *filePath;
	//char *filePathO;
	long fileSize;
	unsigned char *lev_ark;
	int NoOfBlocks;
	if ((file = fopen(InputFile, "rb")) == NULL)
		{
		fprintf(LOGFILE, "Could not open specified file\n");
		return;
		}
	fileSize = getFileSize(file);
	lev_ark = new unsigned char[fileSize];
	fread(lev_ark, fileSize, 1, file);
	fclose(file);

	NoOfBlocks = getValAtAddress(lev_ark, 0, 16);


	//tables that I have to write.
	long *BlockAddress;
	BlockAddress = new long[NoOfBlocks];
	//	long BlockAddress[NoOfBlocks];	//No of blocks in UW2
	long PreviousUsedLength;
	//int CompressionFlags[NoOfBlocks];
	//int DataSize[NoOfBlocks];
	//int AvailableSpace[NoOfBlocks];
	long currAddress;
	long address_pointer = 6;

	int compressionFlag;
	int DataLen;
	int isCompressed;
	long *mapSize;
	mapSize = new long[NoOfBlocks];
	BlocksToUnpack = 80;//Any more than this crashes UW2 on a level transition.
	//long mapSize[BlocksToUnpack];// = 0x7c08;
	fprintf(LOGFILE, "Original Blocks\n");
	for (int x = 0; x < NoOfBlocks; x++)
		{//Just dump out some original data for info.
		currAddress = getValAtAddress(lev_ark, 6 + (x * 4), 32);
		compressionFlag = getValAtAddress(lev_ark, address_pointer + (UW2_COMPRESS_BLOCK *(NoOfBlocks * 4)) + (x * 4), 32);
		long DataSizeVal = getValAtAddress(lev_ark, address_pointer + (UW2_SIZE_BLOCK * (NoOfBlocks * 4)) + (x * 4), 32);
		long DataAvail = getValAtAddress(lev_ark, address_pointer + (UW2_SPACE_BLOCK * (NoOfBlocks * 4)) + (x * 4), 32);

		fprintf(LOGFILE, "\nBlock no %d\n", x);
		fprintf(LOGFILE, "\tAddress %d", currAddress);
		fprintf(LOGFILE, "\tFlags %d\n", compressionFlag);
		fprintf(LOGFILE, "\tData Size %d", DataSizeVal);
		fprintf(LOGFILE, "\tAvailable %d\n", DataAvail);
		fprintf(LOGFILE, "\tNext if using datasize %d\n", currAddress + DataSizeVal);
		fprintf(LOGFILE, "\tNext if using available %d\n", currAddress + DataAvail);
		//if (x < BlocksToUnpack)
		//	{//This default size covers most of the map data except for the animation overlays + other stuff I know nothing about.
		//	mapSize[x]=0x7c08;//default size
		mapSize[x] = DataSizeVal;
	
		fprintf(LOGFILE, "\tUsing Mapsize = %d", mapSize[x]);
		//	}
		}

	//Initial values for the loop for calculating block addresses.
	BlockAddress[0] = getValAtAddress(lev_ark, 6, 32);//The first block stays the same
	long LastBlockAddress = BlockAddress[0];
	PreviousUsedLength = 0;

	for (int x = 0; x < NoOfBlocks; x++)
		{
		currAddress = getValAtAddress(lev_ark, 6 + (x * 4), 32);
		compressionFlag = getValAtAddress(lev_ark, address_pointer + (NoOfBlocks * 4) + (x * 4), 32);
		DataLen = getValAtAddress(lev_ark, address_pointer + (UW2_SIZE_BLOCK * (NoOfBlocks * 4)) + (x * 4), 32);
		isCompressed = (compressionFlag >> 1) & 0x01;
		if (x < BlocksToUnpack)
		//if ((x >= 80) && (x<160))
			{
			if (currAddress != 0)
				{//Map blocks are always compressed in UW2.
				if (isCompressed == 1)
					{
					unpackUW2(lev_ark, currAddress, &DataLen);		//Unpack and see how much space I need to allow for.
					mapSize[x] = DataLen;
					BlockAddress[x] = LastBlockAddress + PreviousUsedLength;  //Size of a map block
					LastBlockAddress = BlockAddress[x];
					PreviousUsedLength = mapSize[x];
					}
				else
					{
					BlockAddress[x] = LastBlockAddress + PreviousUsedLength;
					LastBlockAddress = BlockAddress[x];
					PreviousUsedLength = getValAtAddress(lev_ark, address_pointer + (UW2_SIZE_BLOCK * (NoOfBlocks * 4)) + (x * 4), 32);
					//Set mapSize here???
					}
				}
			else
				{
				BlockAddress[x] = 0;
				mapSize[x] = 0;
				}
			}
		else
			{
			if (currAddress != 0)
				{//is this correct for all compression flags???
				BlockAddress[x] = LastBlockAddress + PreviousUsedLength;
				LastBlockAddress = BlockAddress[x];
				PreviousUsedLength = getValAtAddress(lev_ark, address_pointer + (UW2_SIZE_BLOCK * (NoOfBlocks * 4)) + (x * 4), 32);
				}
			else
				{
				BlockAddress[x] = 0;
				}
			}
		fprintf(LOGFILE, "\nBlock Address %d = %d", x, BlockAddress[x]);
		}

	if ((file = fopen(OutputFile, "w+b")) == NULL)
		{
		fprintf(LOGFILE, "Could not open specified file\n");
		return;
		}


	//Write the number of blocks
	WriteInt16(file, NoOfBlocks);
	WritePointer += 2;
	//write 4x0
	WriteInt32(file, 0);
	WritePointer += 4;

	//write my block addresses. increment by the size of the decompressed data.
	for (int x = 0; x < NoOfBlocks; x++)
		{
		//long currAddress = getValAtAddress(lev_ark, 6 + (x * 4), 32);
		fprintf(LOGFILE, "\nWriting block address %d for block %d at position %d in new file", BlockAddress[x], x, WritePointer);
		WriteInt32(file, BlockAddress[x]);
		WritePointer += 4;
		}

	//write my compression flags. each shoudld be 0 0 0
	for (int x = 0; x < NoOfBlocks; x++)
		{
		compressionFlag = getValAtAddress(lev_ark, address_pointer + (NoOfBlocks * 4) + (x * 4), 32);
		DataLen = getValAtAddress(lev_ark, address_pointer + (UW2_SIZE_BLOCK * (NoOfBlocks * 4)) + (x * 4), 32);
		isCompressed = (compressionFlag >> 1) & 0x01;
		if (x < BlocksToUnpack)
		//if ((x >= 80) && (x<160))
			{//TODO:Bit mask the flag out
			fprintf(LOGFILE, "\nWriting Compression Flag %d to blank for block %d at filepos %d", compressionFlag & 0x5, x, WritePointer);
			WriteInt32(file, 0);
			WritePointer += 4;
			}
		else
			{//copy the existing flags.
			fprintf(LOGFILE, "\nCopying Compression Flag %d for block %d at filepos %d", compressionFlag, x, WritePointer);
			compressionFlag = getValAtAddress(lev_ark, address_pointer + (NoOfBlocks * 4) + (x * 4), 32);
			WriteInt32(file, compressionFlag);
			WritePointer += 4;
			}
		}
	//write the space used
	for (int x = 0; x < NoOfBlocks; x++)
		{
		currAddress = getValAtAddress(lev_ark, 6 + (x * 4), 32);
		if (x < BlocksToUnpack)
		//if ((x >= 80) && (x<160))
			{
			if (currAddress != 0)
				{
				fprintf(LOGFILE, "\nWriting MapSize %d for block %d at filepos %d", mapSize[x], x, WritePointer);
				WriteInt32(file, mapSize[x]);
				WritePointer += 4;
				}
			else
				{
				DataLen = getValAtAddress(lev_ark, address_pointer + (UW2_SIZE_BLOCK * (NoOfBlocks * 4)) + (x * 4), 32);
				fprintf(LOGFILE, "\nCopying MapSize %d for empty block %d at filepos %d", DataLen, x, WritePointer);
				WriteInt32(file, DataLen);
				WritePointer += 4;
				}
			}
		else
			{//copy the existing values
			DataLen = getValAtAddress(lev_ark, address_pointer + (UW2_SIZE_BLOCK * (NoOfBlocks * 4)) + (x * 4), 32);
			fprintf(LOGFILE, "\nCopying MapSize %d for block %d at filepos %d", DataLen, x, WritePointer);
			WriteInt32(file, DataLen);
			WritePointer += 4;
			}
		}
	//write my available space should not matter for decompression so I'll just put the block size here (?)
	for (int x = 0; x < NoOfBlocks; x++)
		{
		currAddress = getValAtAddress(lev_ark, 6 + (x * 4), 32);
		if (x < BlocksToUnpack)
		//if ((x >= 80) && (x<160))
			{
			if (currAddress != 0)
				{
				fprintf(LOGFILE, "\nWriting available space %d for block %d at filepos %d", mapSize[x], x, WritePointer);
				WriteInt32(file, mapSize[x]);
				WritePointer += 4;
				}
			else
				{
				int DataLen = getValAtAddress(lev_ark, address_pointer + (UW2_SIZE_BLOCK * (NoOfBlocks * 4)) + (x * 4), 32);
				fprintf(LOGFILE, "\nWriting available space %d for blank block %d at filepos %d", DataLen, x, WritePointer);
				WriteInt32(file, DataLen);
				WritePointer += 4;
				}
			}
		else
			{//copy the existing values
			int DataLen = getValAtAddress(lev_ark, address_pointer + (UW2_SIZE_BLOCK * (NoOfBlocks * 4)) + (x * 4), 32);
			fprintf(LOGFILE, "\nCopying available space %d for block %d at filepos %d", DataLen, x, WritePointer);
			WriteInt32(file, DataLen);
			WritePointer += 4;
			}
		}
	//write my uncompressed blocks.
	for (int x = 0; x < NoOfBlocks; x++)
		{
		currAddress = getValAtAddress(lev_ark, 6 + (x * 4), 32);
		compressionFlag = getValAtAddress(lev_ark, address_pointer + (NoOfBlocks * 4) + (x * 4), 32);
		DataLen = getValAtAddress(lev_ark, address_pointer + (UW2_SIZE_BLOCK * (NoOfBlocks * 4)) + (x * 4), 32);
		isCompressed = (compressionFlag >> 1) & 0x01;
		if (x < BlocksToUnpack)
		//if ((x >= 80) && (x<160))
			{
			if (currAddress != 0)
				{
				switch (isCompressed)
					{
						case 0:
							//DataSize[x] = DataLen;
							fprintf(LOGFILE, "\nWriting UnCompressed Block %d ", x);
							fprintf(LOGFILE, " Writing output at %d of size %d ", WritePointer, mapSize[x]);
							//fprintf(LOGFILE, "\nWriting Uncompressed Block %d from %d length. Writing output at %d ", x, currAddress, DataLen, WritePointer);
							for (long y = currAddress; y < currAddress + DataLen; y++)
								{//Copy the bytes
								fputc(lev_ark[y], file);
								WritePointer++;
								}
							fprintf(LOGFILE, " to %d ", WritePointer);
							fprintf(LOGFILE, " Expected position was %d ", BlockAddress[x]);
							break;
						case 1://compressed block
						case 2:
							fprintf(LOGFILE, "\nWriting Compressed Block %d ", x);
							unsigned char *tmp_ark;
							tmp_ark = unpackUW2(lev_ark, currAddress, &DataLen);
							//DataSize[x] = DataLen;
							fprintf(LOGFILE, " Writing output at %d of size %d ", WritePointer, mapSize[x]);
							for (long y = 0; y < mapSize[x]; y++)
								{//Copy the bytes
								fputc(tmp_ark[y], file);
								WritePointer++;
								}
							fprintf(LOGFILE, " to %d ", WritePointer);
							fprintf(LOGFILE, " Expected position was %d ", BlockAddress[x]);
							break;

					}
				}
			}
		else
			{	//non map. just copy the bytes
			if (currAddress != 0)
				{
				fprintf(LOGFILE, "\nCopying non repacked data at %d of length %d ", WritePointer, DataLen);
				for (long y = currAddress; y < currAddress + DataLen; y++)
					{//Copy the bytes
					fputc(lev_ark[y], file);
					WritePointer++;
					}
				fprintf(LOGFILE, " to %d", WritePointer);
				fprintf(LOGFILE, " Expected position was %d ", mapSize[x]);
				}
			}
		}



	fclose(file);


	if ((file = fopen(OutputFile, "rb")) == NULL)
		{
		fprintf(LOGFILE, "Could not open specified file\n");
		return;
		}
	fileSize = getFileSize(file);
	lev_ark = new unsigned char[fileSize];
	fread(lev_ark, fileSize, 1, file);
	fclose(file);
	fprintf(LOGFILE, "New file Blocks\n");
	for (int x = 0; x < NoOfBlocks; x++)
		{
		currAddress = getValAtAddress(lev_ark, 6 + (x * 4), 32);
		compressionFlag = getValAtAddress(lev_ark, address_pointer + (NoOfBlocks * 4) + (x * 4), 32);
		long DataSizeVal = getValAtAddress(lev_ark, address_pointer + (UW2_SIZE_BLOCK * (NoOfBlocks * 4)) + (x * 4), 32);
		long DataAvail = getValAtAddress(lev_ark, address_pointer + (UW2_SPACE_BLOCK * (NoOfBlocks * 4)) + (x * 4), 32);

		fprintf(LOGFILE, "Block no %d\n", x);
		fprintf(LOGFILE, "\tAddress %d", currAddress);
		fprintf(LOGFILE, "\tFlags %d\n", compressionFlag);
		fprintf(LOGFILE, "\tData Size %d", DataSizeVal);
		fprintf(LOGFILE, "\tAvailable %d\n", DataAvail);
		fprintf(LOGFILE, "\tNext if using datasize %d\n", currAddress + DataSizeVal);
		fprintf(LOGFILE, "\tNext if using available %d\n", currAddress + DataAvail);
		}
	}

void WriteInt8(FILE *file, long val)
{
	unsigned char valOut;
	valOut = val & 0xff;
	fputc(valOut, file);
}

void WriteInt16(FILE *file, long val)
{
	unsigned char valOut;
	valOut = val & 0xff;
	fputc(valOut, file);

	valOut = val >> 8 & 0xff;
	fputc(valOut,file);


	//return Byte4 << 24 | Byte3 << 16 | Byte2 << 8 | Byte1;
}


void WriteInt32(FILE *file, long val)
{
unsigned char valOut;

	valOut = val & 0xff;
	fputc(valOut, file);

	valOut = val >> 8 & 0xff;
	fputc(valOut, file);

	valOut = val >> 16 & 0xff;
	fputc(valOut, file);

	valOut= val >> 24 & 0xff;
	fputc(valOut, file);

	//return Byte4 << 24 | Byte3 << 16 | Byte2 << 8 | Byte1;
}

void WriteInt24(FILE *file, long val)
{
	unsigned char valOut;

	valOut = val & 0xff;
	fputc(valOut, file);

	valOut = val >> 8 & 0xff;
	fputc(valOut, file);

	valOut = val >> 16 & 0xff;
	fputc(valOut, file);
}

void RepackShock(char InputFile[255], char OutputFile[255])
{
	unsigned char *archive_ark;
	unsigned char *tmp_ark;
	long DirectoryAddress;
	int NoOfChunks;
	long address_pointer;
	long AddressOfBlockStart;
	long NewBlockAddress;
	long BlockAddressesOld[1000];
	long BlockAddressesNew[1000];
	long NewBlockBoundary[1000];
	int chunkNos[1000];
	long UnpackedSize[1000];
	long PackedSize[1000];
	short contentType[1000];
	short compressionFlags[1000];
//load the shock resource file.
	//Read in the archive.
	FILE *file = NULL;      // File pointer
	if ((file = fopen(InputFile, "rb")) == NULL)
	{
		printf("\nRepackShock - Archive not found!\n");
		return;
	}
	long fileSize = getFileSize(file);
	int filepos = ftell(file);
	archive_ark = new unsigned char[fileSize];
	fread(archive_ark, fileSize, 1, file);
	fclose(file);


//Get the directory address
	DirectoryAddress = getValAtAddress(archive_ark,124,32);
	printf("\nThe Directory is at %d\n",DirectoryAddress);
//Read in the directory
	NoOfChunks = getValAtAddress(archive_ark, DirectoryAddress, 16);
	printf("No of chunks = %d\n",NoOfChunks);
	AddressOfBlockStart = getValAtAddress(archive_ark, DirectoryAddress + 2, 32);//The first chunk
	NewBlockAddress= AddressOfBlockStart;
	address_pointer = DirectoryAddress + 6;
	for (int x = 0; x < NoOfChunks; x++)
		{
		int chunkId = getValAtAddress(archive_ark, address_pointer, 16);
		chunkNos[x]=chunkId;

		int chunkUnpackedLength = getValAtAddress(archive_ark, address_pointer + 2, 24);
		UnpackedSize[x]=chunkUnpackedLength;

		int chunkCompression = getValAtAddress(archive_ark, address_pointer + 5, 8);	//Compression.
		compressionFlags[x]=chunkCompression;

		int chunkPackedLength = getValAtAddress(archive_ark, address_pointer + 6, 24);	//Does not matter
		PackedSize[x]=chunkPackedLength;

		short chunkContentType = getValAtAddress(archive_ark, address_pointer + 9, 8);
		contentType[x]=chunkContentType;

		printf("Index: %d, Chunk %d, Unpack size %d, compression %d, packed size %d, content type %d\t",
			x,chunkId, chunkUnpackedLength, chunkCompression,chunkPackedLength,chunkContentType);
		printf("Absolute address is %d",AddressOfBlockStart);
		
		BlockAddressesOld[x] = AddressOfBlockStart;
		BlockAddressesNew[x] = NewBlockAddress;
		printf("\tNew Block will be at %d\n", BlockAddressesNew[x]);
		
		AddressOfBlockStart = AddressOfBlockStart + chunkPackedLength;//The next block
		if ((AddressOfBlockStart % 4) != 0)
			AddressOfBlockStart = AddressOfBlockStart + 4 - (AddressOfBlockStart % 4); // chunk offsets always fall on 4-byte boundaries
		
		NewBlockAddress = NewBlockAddress + chunkUnpackedLength;	//The next block
		NewBlockBoundary[x]=0;
		//printf("\n%d\n",NewBlockAddress % 4);
		if ((NewBlockAddress % 4) != 0)
			{
			NewBlockBoundary[x] = 4 - (NewBlockAddress % 4);//Need to write these bytes to make it all match up.
			NewBlockAddress = NewBlockAddress + 4 - (NewBlockAddress % 4); // chunk offsets always fall on 4-byte boundaries
			}

		address_pointer = address_pointer + 10;
		}

//Write my data.
	if ((file = fopen(OutputFile, "w+b")) == NULL)
	{
		printf("Could not open specified file\n");
		return;
	}
//Copy the header
	for (int i = 0; i < 124; i++)
		{
		fputc(archive_ark[i],file);
		}

//My last chunk address is the directory.
	printf("\nThe New directory is at %d", NewBlockAddress);
	WriteInt32(file, NewBlockAddress);
	

	for (int x = 0; x < NoOfChunks; x++)
		{
		switch (compressionFlags[x])
			{
			case 0:	//Flat uncompressed. Just copy the bytes
				printf("\nCopying uncompressed chunk %d",x);
				for (int i = 0; i < UnpackedSize[x]; i++)
					{
					fputc(archive_ark[BlockAddressesOld[x] + i], file);
					//WriteInt8(file, x+1);
					}
				if (NewBlockBoundary[x]>0)
					{	
					printf("\nWriting a 4 byte boundary");
					for (int i = 0; i < NewBlockBoundary[x]; i++)
							{//Write to the 4 byte boundary.
							WriteInt8(file,0);
							}
					}
				break;
			case 1:	//Flat compressed. Unpacked and copy the output.
				tmp_ark = new unsigned char[UnpackedSize[x]];
				//unpack_data(archive_ark, tmp_ark, UnpackedSize[x]);
				printf("\nUnpacking compressed chunk %d", x);
				LoadShockChunk(BlockAddressesOld[x], compressionFlags[x], archive_ark, tmp_ark, PackedSize[x], UnpackedSize[x]);
				//if (chunkNos[x] == 4105)
				//	{
				//	int add_ptr=0;
				//	for (int i = 0; i<63; i++)
				//		{
				//		for (int j = 0; j<63; j++)
				//			{
				//			if ((i == 20) || (j == 27) || (i == 32) || (j == 20))
				//				{
				//				tmp_ark[add_ptr] = 0;
				//				//tmp_ark[add_ptr + 1] = tmp_ark[add_ptr + 1] & 0xE0;
				//				//tmp_ark[add_ptr+4] = 0;
				//				//tmp_ark[add_ptr+5] = 0;
				//				}
				//			else
				//				{
				//				if ((i != 0) || (j != 0)|| (i != 63) || (j != 63))
				//					{
				//					tmp_ark[add_ptr] = 1;
				//					tmp_ark[add_ptr + 1] = tmp_ark[add_ptr + 1] & 0xE0;
				//					//tmp_ark[add_ptr+4] = 0;
				//					//tmp_ark[add_ptr+5] = 0;
				//					}
				//				}
				//			add_ptr = add_ptr + 16;
				//			}
				//		}
				//	}
				for (int i = 0; i < UnpackedSize[x]; i++)
					{
					fputc(tmp_ark[i], file);
					//WriteInt8(file,x+1);
					}
				if (NewBlockBoundary[x]>0)
				{
					printf("\nWriting a 4 byte boundary");
					for (int i = 0; i < NewBlockBoundary[x]; i++)
					{//Write to the 4 byte boundary.
						WriteInt8(file, 0);
					}
				}
				break;
			case 2:
			case 3:
				printf("\nA subdir! What do I do here!!!\n");
				break;
			}
		}

		//Write the directory
		printf("\nWriting a new boundary");
		//No of chunks (int16)
		WriteInt16(file,NoOfChunks);
		//Offset to first chunk (int32)
		WriteInt32(file,BlockAddressesNew[0]);
		//Loop through
		for (int x = 0; x < NoOfChunks; x++)
		{
		//Chunk Id (int 16)
			WriteInt16(file, chunkNos[x]);
		//chunk unpacked length (int 24)
			WriteInt24(file, UnpackedSize[x]);
		//Chunk compression type (int 8)
			WriteInt8(file, 0);
		//chunk packed length (int 24)
			WriteInt24(file, UnpackedSize[x]);	//uncompressed.
		//Chunk content type.(int 8)
			WriteInt8(file,contentType[x]);
		}
	fclose(file);


//Reread my data
	//*file = NULL;      // File pointer
	if ((file = fopen(OutputFile, "rb")) == NULL)
	{
		printf("\nRepackShock - Archive not found!\n");
		return;
	}
	fileSize = getFileSize(file);

	archive_ark = new unsigned char[fileSize];
	fread(archive_ark, fileSize, 1, file);
	fclose(file);

	//Get the directory address
	DirectoryAddress = getValAtAddress(archive_ark, 124, 32);
	printf("\nThe Directory is at %d\n", DirectoryAddress);
	//Read in the directory
	NoOfChunks = getValAtAddress(archive_ark, DirectoryAddress, 16);
	printf("No of chunks = %d\n", NoOfChunks);
	AddressOfBlockStart = getValAtAddress(archive_ark, DirectoryAddress + 2, 32);//The first chunk
	address_pointer = DirectoryAddress + 6;
	for (int x = 0; x < NoOfChunks; x++)
	{
		int chunkId = getValAtAddress(archive_ark, address_pointer, 16);
		int chunkUnpackedLength = getValAtAddress(archive_ark, address_pointer + 2, 24);
		int chunkCompression = getValAtAddress(archive_ark, address_pointer + 5, 8);	//Compression.
		int chunkPackedLength = getValAtAddress(archive_ark, address_pointer + 6, 24);	//Does not matter
		short chunkContentType = getValAtAddress(archive_ark, address_pointer + 9, 8);
		printf("Index: %d, Chunk %d, Unpack size %d, compression %d, packed size %d, content type %d\t",
			x, chunkId, chunkUnpackedLength, chunkCompression, chunkPackedLength, chunkContentType);
		printf("Absolute address is %d\n", AddressOfBlockStart);

		AddressOfBlockStart = AddressOfBlockStart + chunkPackedLength;//The next block
		if ((AddressOfBlockStart % 4) != 0)
			AddressOfBlockStart = AddressOfBlockStart + 4 - (AddressOfBlockStart % 4); // chunk offsets always fall on 4-byte boundaries

		address_pointer = address_pointer + 10;
	}
}

void ParseTerrainProperties(int game)
{
long fileSize;
unsigned char *terraindat;

	FILE *file = NULL;      // File pointer
	switch (game)
		{
			case UWDEMO:
			case SHOCK:
				{
				return;
				break;
				}
		case UW1:
			{
			if ((file = fopen(UW1_TERRAIN_PROPS, "rb")) == NULL)
				{
				printf("\nParseTerrainProperties UW1 - Archive not found!\n");
				return;
				}
			break;
			}
		case UW2:
			{
			if ((file = fopen(UW2_TERRAIN_PROPS, "rb")) == NULL)
				{
					printf("\nParseTerrainProperties UW2 - Archive not found!\n");
					return;
				}
			break;
			}
		}
	fileSize = getFileSize(file);
	terraindat = new unsigned char[fileSize];
	fread(terraindat, fileSize, 1, file);
	fclose(file);
	printf("Print texture properties from terrain.dat");
	int j=0;
	for (int i = 0; i < 512; i++)
		{
		if (i < 256)
			{
			printf("\nWall:");
			}
		else
			{
			
			printf("\nFloor:");
			}
		if (j == 255)
			{
			j=0;
			}
		printf("%d %s", i, textureMasters[j].desc);
		int textureProp = getValAtAddress(terraindat, i * 2, 16);
		switch (textureProp)
				{
				case 0x0://Normal
					printf(" normal");
					break;
				case 0x2://Ankh Mural
					printf(" anhk mural");
					break;
				case 0x3://Stairs Up
					printf(" stairs up");
					break;
				case 0x4://Stairs down
					printf(" stairs down");
					break;
				case 0x5://Pipe
					printf(" pipe");
					break;
				case 0x6://Grating
					printf(" grating");
					break;
				case 0x7://Drain
					printf(" Drain");
					break;
				case 0x8://Chained up princess
					printf(" chained up princess");
					break;
				case 0x9://Window
					printf(" Window");
					break;
				case 0xa://Tapestry
					printf(" Tapestry");
					break;
				case 0xb://Textured Door
					printf(" Textured door");
					break;
				case 0x10://Water
					printf(" water");
					break;
				case 0x20://Lava
					printf(" Lava");
					break;
				case 0x40://Waterfall
					printf(" waterfall");
					break;
				case 0xC0://Ice wall
					printf(" waterfall");
					break;
				case 0xD8://Unknown
					printf(" unknown");
					break;
				case 0xE8://Ice wall (crumbling)
					printf(" ice wall (crumbling)");
					break;
				case 0x80://Lavafall
					printf(" lava fall");
					break;
				case 0xf8://Ice
					printf(" ice");
					break;
				default:
					printf(" unknown value %d", textureProp);
				}
		j++;
		}
}

void getNoOfFramesForShockDoors(int index, int *NoOfFrames, int *ChunkId)
	{//Frame zero to end
	switch (index)
		{
			case 299://blastdoor
			*ChunkId = 2400;
			*NoOfFrames=6;
			break;
		case 300://service access
			*ChunkId =2401;
			*NoOfFrames =7;
			break;
		case 301:
			*ChunkId =2402;
			*NoOfFrames =7;
			break;
		case 302:
			*ChunkId =2403;
			*NoOfFrames =7;
			break;
		case 303:
			*ChunkId = 2404;
			*NoOfFrames =5;
			break;
		case 304:
			*ChunkId =2405;
			*NoOfFrames =5;
			break;
		case 305:
			*ChunkId =2406;
			*NoOfFrames =7;
			break;
		case 306:
			*ChunkId =2407;
			*NoOfFrames =6;
			break;
		case 318:
		case 319:
		case 320:
		case 321:
			*ChunkId =2423;//????
			*NoOfFrames =7;
		case 322:
		case 323:
			*ChunkId =2424;
			*NoOfFrames =5;//??
			break;
		case 325:
			*ChunkId =2426;
			*NoOfFrames =6;
			break;
		case 326:
			*ChunkId =2427;
			*NoOfFrames =6;
			break;
		case 327:
			*ChunkId =2428;
			*NoOfFrames =7;
			break;
		case 328:
			*ChunkId =2429;
			*NoOfFrames =7;
			break;
		case 330:
			*ChunkId =2431;
			*NoOfFrames =7;
			break;
		case 331:
			*ChunkId =2432;
			*NoOfFrames =7;
			break;
		case 332:
			*ChunkId =2433;
			*NoOfFrames =6;
			break;
		case 336:
			*ChunkId =2437;
			*NoOfFrames =4;
			break;
		case 337:
			*ChunkId = 2438;
			*NoOfFrames =5;
			break;
		case 338:
			*ChunkId =2439;
			*NoOfFrames =5;
			break;
		default:
			*ChunkId=-1;
			*NoOfFrames=-1;
		}

	}
<MSG> UW2 Repacker now points correctly to texture maps. (Still not fully tested!!!)
<DFF> @@ -328,9 +328,7 @@ void Repack(int game)
 		printf("");
 	fileSize = getFileSize(file);
 	lev_ark = new unsigned char[fileSize];
-	//tex_ark = new unsigned char[fileSize];
 	fread(lev_ark, fileSize, 1, file);
-	//fread(tex_ark,fileSize,1,file);
 	fclose(file);
 
 	NoOfBlocks = getValAtAddress(lev_ark,0,16);
@@ -338,25 +336,55 @@ void Repack(int game)
 
 	//tables that I have to write.
 	long BlockAddress[320];	//No of blocks in UW2
-	int CompressionFlags[320];
-	int DataSize[320];
-	int AvailableSpace[320];
+	long PreviousUsedLength;
+	//int CompressionFlags[320];
+	//int DataSize[320];
+	//int AvailableSpace[320];
 	long currAddress;
 	long address_pointer = 6;
 
-	BlockAddress[0] = getValAtAddress(lev_ark, 6 , 32);//The first block
+	int compressionFlag ;
+	int DataLen;
+	int isCompressed;
+	printf("Original Blocks\n");
+	for (int x = 0; x < 320; x++)
+	{
+		currAddress = getValAtAddress(lev_ark, 6 + (x * 4), 32);
+		compressionFlag = getValAtAddress(lev_ark, address_pointer + (NoOfBlocks * 4) + (x * 4), 32);
+		long DataSizeVal = getValAtAddress(lev_ark, address_pointer + (2 * (NoOfBlocks * 4)) + (x * 4), 32);
+		long DataAvail = getValAtAddress(lev_ark, address_pointer + (3 * (NoOfBlocks * 4)) + (x * 4), 32);
+
+		printf("Block no %d\n",x);
+		printf("\tAddress %d", currAddress);
+		printf("\tFlags %d\n", compressionFlag);
+		printf("\tData Size %d", DataSizeVal);
+		printf("\tAvailable %d\n", DataAvail);
+		printf("\tNext if using datasize %d\n", currAddress+DataSizeVal);
+		printf("\tNext if using available %d\n", currAddress + DataAvail);
+	}
+
+	BlockAddress[0] = getValAtAddress(lev_ark, 6 , 32);//The first block stays the same
 	long LastBlockAddress = BlockAddress[0];
 	for (int x = 0; x < 320; x++)
 		{
+		currAddress = getValAtAddress(lev_ark, 6 + (x * 4), 32);
+		compressionFlag = getValAtAddress(lev_ark, address_pointer + (NoOfBlocks * 4) + (x * 4), 32);
+		DataLen = getValAtAddress(lev_ark, address_pointer + (3 * (NoOfBlocks * 4)) + (x * 4), 32);
+		isCompressed = (compressionFlag >> 1) & 0x01;
+		if (x == 72)
+			{
+			printf("");
+			}
 		if (x < 80)
 			{
-			currAddress = getValAtAddress(lev_ark, 6 + (x * 4), 32);
+			//currAddress = getValAtAddress(lev_ark, 6 + (x * 4), 32);
 			if (currAddress != 0)
 				{
 				if (x >=1)
 					{
 					BlockAddress[x] = LastBlockAddress + 0x7c08;//Size of a map block
 					LastBlockAddress = BlockAddress[x];
+					PreviousUsedLength=0x7c08;
 					}
 				}
 			else
@@ -366,17 +394,18 @@ void Repack(int game)
 			}
 		else
 			{
-			currAddress = getValAtAddress(lev_ark, 6 + (x * 4), 32);
 			if (currAddress != 0)
-				{
-				BlockAddress[x] = LastBlockAddress + getValAtAddress(lev_ark, address_pointer + (3 * (NoOfBlocks * 4)) + (x * 4), 32);
+				{//is this correct for all compression flags???
+				BlockAddress[x] = LastBlockAddress + PreviousUsedLength;
 				LastBlockAddress = BlockAddress[x];
+				PreviousUsedLength = getValAtAddress(lev_ark, address_pointer + (3 * (NoOfBlocks * 4)) + (x * 4), 32);
 				}
 			else
 				{
 				BlockAddress[x] = 0;
 				}
 			}
+		printf("\nBlock Address %d = %d", x, BlockAddress[x]);
 		}
 	
 	//////if ((file = fopen(UW2_OUT_PATH, "w+b")) == NULL)
@@ -433,33 +462,51 @@ void Repack(int game)
 	{
 		if (x<80)
 			{
-			WriteInt32(file, 0);
+				WriteInt32(file, 0);
 			}
 		else
 		{//copy the existing flags.
-			int compressionFlag = getValAtAddress(lev_ark, address_pointer + (NoOfBlocks * 4) + (x * 4), 32);
+			compressionFlag = getValAtAddress(lev_ark, address_pointer + (NoOfBlocks * 4) + (x * 4), 32);
 			WriteInt32(file,compressionFlag);
 		}
 	}
 	//write the space used
 	for (int x = 0; x < 320; x++)
 	{
+		currAddress = getValAtAddress(lev_ark, 6 + (x * 4), 32);
 		if (x <80)
 		{
-			WriteInt32(file, 0x7c08);
+			if (currAddress != 0)
+				{
+				WriteInt32(file, 0x7c08);
+				}
+			else
+				{
+				DataLen = getValAtAddress(lev_ark, address_pointer + (2 * (NoOfBlocks * 4)) + (x * 4), 32);
+				WriteInt32(file, DataLen);
+				}
 		}
 		else
 		{//copy the existing values
-			int DataLen = getValAtAddress(lev_ark, address_pointer + (2 * (NoOfBlocks * 4)) + (x * 4), 32);
+			DataLen = getValAtAddress(lev_ark, address_pointer + (2 * (NoOfBlocks * 4)) + (x * 4), 32);
 			WriteInt32(file, DataLen);
 		}
 	}
-	//write my available space should not matter for compression so I'll just put the block size here.
+	//write my available space should not matter for decompression so I'll just put the block size here (?)
 	for (int x = 0; x < 320; x++)
 	{
+		currAddress = getValAtAddress(lev_ark, 6 + (x * 4), 32);
 		if (x <80)
 		{
-			WriteInt32(file, 0x7c08);
+			if (currAddress != 0)
+			{
+				WriteInt32(file, 0x7c08);
+			}
+			else
+			{
+				int DataLen = getValAtAddress(lev_ark, address_pointer + (3 * (NoOfBlocks * 4)) + (x * 4), 32);
+				WriteInt32(file, DataLen);
+			}
 		}
 		else
 		{//copy the existing values
@@ -470,39 +517,44 @@ void Repack(int game)
 	//write my uncompressed blocks.
 	for (int x = 0; x < 320; x++)
 		{
-			long currAddress = getValAtAddress(lev_ark, 6 + (x * 4), 32);
-			int compressionFlag = getValAtAddress(lev_ark, address_pointer + (NoOfBlocks * 4) + (x * 4), 32);
-			int DataLen = getValAtAddress(lev_ark, address_pointer + (3 * (NoOfBlocks * 4)) + (x * 4), 32);
-			int isCompressed = (compressionFlag >> 1) & 0x01;
+			currAddress = getValAtAddress(lev_ark, 6 + (x * 4), 32);
+			compressionFlag = getValAtAddress(lev_ark, address_pointer + (NoOfBlocks * 4) + (x * 4), 32);
+			DataLen = getValAtAddress(lev_ark, address_pointer + (3 * (NoOfBlocks * 4)) + (x * 4), 32);
+			isCompressed = (compressionFlag >> 1) & 0x01;
 			if (x < 80)
 				{
-					switch (isCompressed)
+				if (currAddress!=0)
 					{
-					case 0:
-						//DataSize[x] = DataLen;
-						for (int y = currAddress; y < 0x7c08; y++)
-						{//Copy the bytes
-							fputc(lev_ark[y], file);
-						}
-						break;
-					case 1://compressed block
-					case 2:
-						unsigned char *tmp_ark;
-						tmp_ark = unpack(lev_ark, currAddress, &DataLen);
-						//DataSize[x] = DataLen;
-						for (int y = 0; y < 0x7c08; y++)
-						{//Copy the bytes
-							fputc(tmp_ark[y], file);
+					switch (isCompressed)
+						{
+						case 0:
+							//DataSize[x] = DataLen;
+							for (int y = currAddress; y < currAddress + 0x7c08; y++)
+							{//Copy the bytes
+								fputc(lev_ark[y], file);
+							}
+							break;
+						case 1://compressed block
+						case 2:
+							unsigned char *tmp_ark;
+							tmp_ark = unpack(lev_ark, currAddress, &DataLen);
+							//DataSize[x] = DataLen;
+							for (int y = 0; y < 0x7c08; y++)
+							{//Copy the bytes
+								fputc(tmp_ark[y], file);
+							}
+							break;
 						}
-						break;
 					}
 				}
 			else
 				{	//non map. just copy the bytes
-				//DataSize[x] = DataLen;
-				for (int y = currAddress; y < currAddress+DataLen; y++)
-					{//Copy the bytes
-						fputc(lev_ark[y], file);
+				if (currAddress != 0)
+					{
+					for (int y = currAddress; y < currAddress+DataLen; y++)
+						{//Copy the bytes
+							fputc(lev_ark[y], file);
+						}
 					}
 				}
 		}
@@ -510,6 +562,33 @@ void Repack(int game)
 
 
 	fclose(file);
+
+
+	if ((file = fopen(UW2_OUT_PATH, "rb")) == NULL)
+		printf("Could not open specified file\n");
+	else
+		printf("");
+	fileSize = getFileSize(file);
+	lev_ark = new unsigned char[fileSize];
+	fread(lev_ark, fileSize, 1, file);
+	fclose(file);
+	printf("New Blocks\n");
+	for (int x = 0; x < 320; x++)
+	{
+		currAddress = getValAtAddress(lev_ark, 6 + (x * 4), 32);
+		compressionFlag = getValAtAddress(lev_ark, address_pointer + (NoOfBlocks * 4) + (x * 4), 32);
+		long DataSizeVal = getValAtAddress(lev_ark, address_pointer + (2 * (NoOfBlocks * 4)) + (x * 4), 32);
+		long DataAvail = getValAtAddress(lev_ark, address_pointer + (3 * (NoOfBlocks * 4)) + (x * 4), 32);
+
+		printf("Block no %d\n", x);
+		printf("\tAddress %d", currAddress);
+		printf("\tFlags %d\n", compressionFlag);
+		printf("\tData Size %d", DataSizeVal);
+		printf("\tAvailable %d\n", DataAvail);
+		printf("\tNext if using datasize %d\n", currAddress + DataSizeVal);
+		printf("\tNext if using available %d\n", currAddress + DataAvail);
+	}
+
 	//////if ((file = fopen(UW2_OUT_PATH, "w+b")) == NULL)
 	//////	printf("Could not open specified file\n");
 	//////else

UW2 Repacker now points correctly to texture maps. (Still not fully tested!!!)