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"
|
|
|
|
|
2011-04-13 18:37:12 +00:00
|
|
|
// Format: ESDDDDDD EDDDDDDD EDD... Extended, Data, Sign
|
|
|
|
unsigned char *CVariableInt::Pack(unsigned char *pDst, int i)
|
|
|
|
{
|
2020-09-26 19:41:58 +00:00
|
|
|
*pDst = (i >> 25) & 0x40; // set sign bit if i<0
|
2021-12-27 13:08:29 +00:00
|
|
|
i ^= i >> 31; // if(i<0) i = ~i
|
2010-05-29 07:25:38 +00:00
|
|
|
|
2020-09-26 19:41:58 +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
|
2021-12-27 13:08:29 +00:00
|
|
|
while(true)
|
2010-05-29 07:25:38 +00:00
|
|
|
{
|
|
|
|
pDst++;
|
2021-12-27 13:08:29 +00:00
|
|
|
*pDst = i & 0x7F; // pack 7bit
|
2010-05-29 07:25:38 +00:00
|
|
|
i >>= 7; // discard 7 bits
|
2020-09-26 19:41:58 +00:00
|
|
|
*pDst |= (i != 0) << 7; // set extend bit (may branch)
|
2010-05-29 07:25:38 +00:00
|
|
|
if(!i)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pDst++;
|
2011-04-13 18:37:12 +00:00
|
|
|
return pDst;
|
|
|
|
}
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
const unsigned char *CVariableInt::Unpack(const unsigned char *pSrc, int *pInOut)
|
2011-04-13 18:37:12 +00:00
|
|
|
{
|
2021-12-27 13:08:29 +00:00
|
|
|
const int Sign = (*pSrc >> 6) & 1;
|
2020-09-26 19:41:58 +00:00
|
|
|
*pInOut = *pSrc & 0x3F;
|
2010-05-29 07:25:38 +00:00
|
|
|
|
|
|
|
do
|
2011-04-13 18:37:12 +00:00
|
|
|
{
|
2020-09-26 19:41:58 +00:00
|
|
|
if(!(*pSrc & 0x80))
|
|
|
|
break;
|
2010-05-29 07:25:38 +00:00
|
|
|
pSrc++;
|
2021-12-27 13:08:29 +00:00
|
|
|
*pInOut |= (*pSrc & 0x7F) << 6;
|
2010-05-29 07:25:38 +00:00
|
|
|
|
2020-09-26 19:41:58 +00:00
|
|
|
if(!(*pSrc & 0x80))
|
|
|
|
break;
|
2010-05-29 07:25:38 +00:00
|
|
|
pSrc++;
|
2021-12-27 13:08:29 +00:00
|
|
|
*pInOut |= (*pSrc & 0x7F) << (6 + 7);
|
2010-05-29 07:25:38 +00:00
|
|
|
|
2020-09-26 19:41:58 +00:00
|
|
|
if(!(*pSrc & 0x80))
|
|
|
|
break;
|
2010-05-29 07:25:38 +00:00
|
|
|
pSrc++;
|
2021-12-27 13:08:29 +00:00
|
|
|
*pInOut |= (*pSrc & 0x7F) << (6 + 7 + 7);
|
2010-05-29 07:25:38 +00:00
|
|
|
|
2020-09-26 19:41:58 +00:00
|
|
|
if(!(*pSrc & 0x80))
|
|
|
|
break;
|
2010-05-29 07:25:38 +00:00
|
|
|
pSrc++;
|
2021-12-27 13:08:29 +00:00
|
|
|
*pInOut |= (*pSrc & 0x0F) << (6 + 7 + 7 + 7);
|
|
|
|
} while(false);
|
2010-05-29 07:25:38 +00:00
|
|
|
|
|
|
|
pSrc++;
|
|
|
|
*pInOut ^= -Sign; // if(sign) *i = ~(*i)
|
2011-04-13 18:37:12 +00:00
|
|
|
return pSrc;
|
|
|
|
}
|
2010-05-29 07:25:38 +00:00
|
|
|
|
2021-12-27 13:08:29 +00:00
|
|
|
long CVariableInt::Decompress(const void *pSrc_, int SrcSize, void *pDst_, int DstSize)
|
2010-05-29 07:25:38 +00:00
|
|
|
{
|
2021-12-27 13:08:29 +00:00
|
|
|
dbg_assert(DstSize % sizeof(int) == 0, "invalid bounds");
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
const unsigned char *pSrc = (unsigned char *)pSrc_;
|
2021-12-27 13:08:29 +00:00
|
|
|
const unsigned char *pEnd = pSrc + SrcSize;
|
2010-05-29 07:25:38 +00:00
|
|
|
int *pDst = (int *)pDst_;
|
2021-12-27 13:08:29 +00:00
|
|
|
const int *pDstEnd = pDst + DstSize / sizeof(int);
|
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++;
|
|
|
|
}
|
2021-12-27 13:08:29 +00:00
|
|
|
return (long)((unsigned char *)pDst - (unsigned char *)pDst_);
|
2010-05-29 07:25:38 +00:00
|
|
|
}
|
|
|
|
|
2021-12-27 13:08:29 +00:00
|
|
|
long CVariableInt::Compress(const void *pSrc_, int SrcSize, void *pDst_, int DstSize)
|
2010-05-29 07:25:38 +00:00
|
|
|
{
|
2021-12-27 13:08:29 +00:00
|
|
|
dbg_assert(SrcSize % sizeof(int) == 0, "invalid bounds");
|
|
|
|
|
|
|
|
const int *pSrc = (int *)pSrc_;
|
2010-05-29 07:25:38 +00:00
|
|
|
unsigned char *pDst = (unsigned char *)pDst_;
|
2021-12-27 13:08:29 +00:00
|
|
|
const unsigned char *pDstEnd = pDst + DstSize;
|
|
|
|
SrcSize /= sizeof(int);
|
|
|
|
while(SrcSize)
|
2010-05-29 07:25:38 +00:00
|
|
|
{
|
2021-12-27 13:08:29 +00:00
|
|
|
if(pDstEnd - pDst <= MAX_BYTES_PACKED)
|
2017-09-16 17:30:08 +00:00
|
|
|
return -1;
|
2010-05-29 07:25:38 +00:00
|
|
|
pDst = CVariableInt::Pack(pDst, *pSrc);
|
2021-12-27 13:08:29 +00:00
|
|
|
SrcSize--;
|
2010-05-29 07:25:38 +00:00
|
|
|
pSrc++;
|
|
|
|
}
|
2021-12-27 13:08:29 +00:00
|
|
|
return (long)(pDst - (unsigned char *)pDst_);
|
2010-05-29 07:25:38 +00:00
|
|
|
}
|