ddnet/src/engine/shared/compression.cpp

98 lines
2.1 KiB
C++
Raw Normal View History

2010-11-20 10:37:14 +00:00
/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */
/* If you are missing that file, acquire a complete release at teeworlds.com. */
2010-05-29 07:25:38 +00:00
#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
2010-05-29 07:25:38 +00:00
*pDst |= i & 0x3F; // pack 6bit into dst
2010-05-29 07:25:38 +00:00
i >>= 6; // discard 6 bits
if(i)
{
*pDst |= 0x80; // set extend bit
while(1)
{
pDst++;
*pDst = i & (0x7F); // pack 7bit
2010-05-29 07:25:38 +00:00
i >>= 7; // discard 7 bits
*pDst |= (i != 0) << 7; // set extend bit (may branch)
2010-05-29 07:25:38 +00:00
if(!i)
break;
}
}
pDst++;
return pDst;
}
2010-05-29 07:25:38 +00:00
const unsigned char *CVariableInt::Unpack(const unsigned char *pSrc, int *pInOut)
{
int Sign = (*pSrc >> 6) & 1;
*pInOut = *pSrc & 0x3F;
2010-05-29 07:25:38 +00:00
do
{
if(!(*pSrc & 0x80))
break;
2010-05-29 07:25:38 +00:00
pSrc++;
*pInOut |= (*pSrc & (0x7F)) << (6);
2010-05-29 07:25:38 +00:00
if(!(*pSrc & 0x80))
break;
2010-05-29 07:25:38 +00:00
pSrc++;
*pInOut |= (*pSrc & (0x7F)) << (6 + 7);
2010-05-29 07:25:38 +00:00
if(!(*pSrc & 0x80))
break;
2010-05-29 07:25:38 +00:00
pSrc++;
*pInOut |= (*pSrc & (0x7F)) << (6 + 7 + 7);
2010-05-29 07:25:38 +00:00
if(!(*pSrc & 0x80))
break;
2010-05-29 07:25:38 +00:00
pSrc++;
*pInOut |= (*pSrc & (0x7F)) << (6 + 7 + 7 + 7);
2010-05-29 07:25:38 +00:00
} while(0);
pSrc++;
*pInOut ^= -Sign; // if(sign) *i = ~(*i)
return pSrc;
}
2010-05-29 07:25:38 +00:00
2017-09-16 17:30:08 +00:00
long CVariableInt::Decompress(const void *pSrc_, int Size, void *pDst_, int DstSize)
2010-05-29 07:25:38 +00:00
{
const unsigned char *pSrc = (unsigned char *)pSrc_;
const unsigned char *pEnd = pSrc + Size;
int *pDst = (int *)pDst_;
2017-09-16 17:30:08 +00:00
int *pDstEnd = pDst + DstSize / 4;
2010-05-29 07:25:38 +00:00
while(pSrc < pEnd)
{
2017-09-16 17:30:08 +00:00
if(pDst >= pDstEnd)
return -1;
2010-05-29 07:25:38 +00:00
pSrc = CVariableInt::Unpack(pSrc, pDst);
pDst++;
}
return (unsigned char *)pDst - (unsigned char *)pDst_;
2010-05-29 07:25:38 +00:00
}
2017-09-16 17:30:08 +00:00
long CVariableInt::Compress(const void *pSrc_, int Size, void *pDst_, int DstSize)
2010-05-29 07:25:38 +00:00
{
int *pSrc = (int *)pSrc_;
unsigned char *pDst = (unsigned char *)pDst_;
2017-09-16 17:30:08 +00:00
unsigned char *pDstEnd = pDst + DstSize;
2010-05-29 07:25:38 +00:00
Size /= 4;
while(Size)
{
2017-09-16 17:30:08 +00:00
if(pDstEnd - pDst < 6)
return -1;
2010-05-29 07:25:38 +00:00
pDst = CVariableInt::Pack(pDst, *pSrc);
Size--;
pSrc++;
}
return pDst - (unsigned char *)pDst_;
2010-05-29 07:25:38 +00:00
}