about summary refs log tree commit diff
path: root/src/engine/shared/compression.cpp
blob: 63e44699f4936c4cbec74680a0c445d63437c421 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
// copyright (c) 2007 magnus auvinen, see licence.txt for more info
#include <base/system.h>

#include "compression.h"

// Format: ESDDDDDD EDDDDDDD EDD...  Extended, Data, Sign
unsigned char *CVariableInt::Pack(unsigned char *pDst, int i) 
{ 
	*pDst = (i>>25)&0x40; // set sign bit if i<0
	i = i^(i>>31); // if(i<0) i = ~i

	*pDst |= i&0x3F; // pack 6bit into dst
	i >>= 6; // discard 6 bits
	if(i)
	{
		*pDst |= 0x80; // set extend bit
		while(1)
		{
			pDst++;
			*pDst = i&(0x7F); // pack 7bit
			i >>= 7; // discard 7 bits
			*pDst |= (i!=0)<<7; // set extend bit (may branch)
			if(!i)
				break;
		}
	}

	pDst++;
	return pDst; 
} 
 
const unsigned char *CVariableInt::Unpack(const unsigned char *pSrc, int *pInOut)
{ 
	int Sign = (*pSrc>>6)&1; 
	*pInOut = *pSrc&0x3F; 

	do
	{ 
		if(!(*pSrc&0x80)) break;
		pSrc++;
		*pInOut |= (*pSrc&(0x7F))<<(6);

		if(!(*pSrc&0x80)) break;
		pSrc++;
		*pInOut |= (*pSrc&(0x7F))<<(6+7);

		if(!(*pSrc&0x80)) break;
		pSrc++;
		*pInOut |= (*pSrc&(0x7F))<<(6+7+7);

		if(!(*pSrc&0x80)) break;
		pSrc++;
		*pInOut |= (*pSrc&(0x7F))<<(6+7+7+7);
	} while(0);

	pSrc++;
	*pInOut ^= -Sign; // if(sign) *i = ~(*i)
	return pSrc; 
} 


long CVariableInt::Decompress(const void *pSrc_, int Size, void *pDst_)
{
	const unsigned char *pSrc = (unsigned char *)pSrc_;
	const unsigned char *pEnd = pSrc + Size;
	int *pDst = (int *)pDst_;
	while(pSrc < pEnd)
	{
		pSrc = CVariableInt::Unpack(pSrc, pDst);
		pDst++;
	}
	return (long)((unsigned char *)pDst-(unsigned char *)pDst_);
}

long CVariableInt::Compress(const void *pSrc_, int Size, void *pDst_)
{
	int *pSrc = (int *)pSrc_;
	unsigned char *pDst = (unsigned char *)pDst_;
	Size /= 4;
	while(Size)
	{
		pDst = CVariableInt::Pack(pDst, *pSrc);
		Size--;
		pSrc++;
	}
	return (long)(pDst-(unsigned char *)pDst_);
}