We just moved to a different server. Please be patient until all files and pages are restored and the MediaWiki software has been updated. Thank you

.CMP

From REWiki
Revision as of 07:02, 11 April 2009 by Wakko (Talk | contribs)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

Games

The .CMP file format is used by Wipeout. It contains a compressed archive of .TIM images.

Structure

The values are stored in Little-Endian order.

The file starts with an uint32 which is a number of images in the archive.

Then follows 'number of images' uint32 values which are the byte length of each image decompressed. They must be summed to give the total byte length of the decompressed archive.

Afterwards come the compressed byte stream, with LZ77 algorithm, i.e. repeatable strings are replaced by references to same strings in bitstream.

Extraction program

I've written this small program to decompress the LZ77 byte stream from a .CMP file. It uses a 8KB circular buffer.

#include <stdio.h>
#include <fcntl.h>

/* Load file in mem from filename, return buffer, update length */

char *loadFile(char *filename, int *length)
{
	int handle;
	char *buffer;

	/* Load file */
	handle = open(filename, O_RDONLY);
	if (handle<0) {
		fprintf(stderr, "Unable to open %s\n", filename);	
		return NULL;
	}

	*length = lseek(handle, 0, SEEK_END);
	lseek(handle, 0, SEEK_SET); 	

	buffer = (char *)malloc(*length);
	if (buffer==NULL) {
		fprintf(stderr, "Unable to allocate %d bytes\n", *length);
		return NULL;
	}

	read(handle, buffer, *length);
	close(handle);

	return buffer;
}

int srcPos, dstPos;
unsigned char tmp8K[0x2000];
int srcBitMask, srcCurByte;

int readSrcBitfield(unsigned char *src, int bitfieldSize)
{
	int curValue = 0;

	while (bitfieldSize > 0) {
		if (srcBitMask == 0x80) {
			srcCurByte = src[srcPos++];
		}

		if (srcCurByte & srcBitMask) {
			curValue |= bitfieldSize;
		}

		bitfieldSize >>= 1;

		srcBitMask >>= 1;
		if (srcBitMask == 0) {
			srcBitMask = 0x80;
		}
	}

	return curValue;
}

void depackFile(unsigned char *src, int srcLength, unsigned char *dst, int dstLength)
{
	srcPos = dstPos = 0;

	int srcCurBit;
	int curValue, curValue2;
	int tmp8Kpos;

	srcBitMask = 0x80;
	srcCurByte = 0;
	tmp8Kpos = 1;

	for (;;) {
		/* Just to be safe */
		if ((srcPos>srcLength) || (dstPos>dstLength)) {
			break;
		}

		if (srcBitMask == 0x80) {
			srcCurByte = src[srcPos++];
		}

		srcCurBit = (srcCurByte & srcBitMask);

		srcBitMask >>= 1;
		if (srcBitMask == 0) {
			srcBitMask = 0x80;
		}

		if (srcCurBit) {
			curValue = readSrcBitfield(src, 0x80);
			tmp8K[(tmp8Kpos++) & 0x1fff] = dst[dstPos++] = curValue;
		} else {
			int position, length, i;

			position = readSrcBitfield(src, 0x1000);
			if (position == 0) {
				break;
			}

			length = readSrcBitfield(src, 0x08)+2;			

			for (i=0; i<=length; i++) {
				curValue = tmp8K[(i + position) & 0x1fff];
				tmp8K[(tmp8Kpos++) & 0x1fff] = dst[dstPos++] = curValue;
			}
		}
	}
}

void *parseCmp(unsigned char *filePtr, int length, int *dstLength)
{
	int i, len;
	unsigned char *dstFile;
	unsigned long *file = (unsigned long *)filePtr;

	/* Sum all length */
	len = 0;
	for (i=0; i<file[0]; i++) {
		len += file[i+1];
	}

	length -= (file[0]+1)*4;
	dstFile = (unsigned char *)malloc(len);
	if (dstFile) {
		depackFile((unsigned char *) &file[file[0]+1], length, dstFile, len);

		*dstLength = len;
	}	

	return dstFile;
}

int main(int argc, char **argv)
{
	int length, dstLength;
	unsigned char *fileInMem;
	unsigned char *dstFile;

	if (argc<2) {
		fprintf(stderr, "give filename.cmp as parameter\n");
		return 1;
	}

	fileInMem = loadFile(argv[1], &length);
	if (fileInMem==NULL) {
		return 1;
	}

	dstFile = parseCmp(fileInMem, length, &dstLength);
	if (dstFile) {
		/* Now we can save the file from dstFile, dstLength bytes */
		printf("%d bytes depacked\n", dstLength);

		free(dstFile);
	}

	free(fileInMem);

	return 0;
}
Personal tools