/* (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. */ #include #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_, int DstSize) { const unsigned char *pSrc = (unsigned char *)pSrc_; const unsigned char *pEnd = pSrc + Size; int *pDst = (int *)pDst_; int *pDstEnd = pDst + DstSize / 4; while(pSrc < pEnd) { if(pDst >= pDstEnd) return -1; pSrc = CVariableInt::Unpack(pSrc, pDst); pDst++; } return (unsigned char *)pDst-(unsigned char *)pDst_; } long CVariableInt::Compress(const void *pSrc_, int Size, void *pDst_, int DstSize) { int *pSrc = (int *)pSrc_; unsigned char *pDst = (unsigned char *)pDst_; unsigned char *pDstEnd = pDst + DstSize; Size /= 4; while(Size) { if(pDstEnd - pDst < 6) return -1; pDst = CVariableInt::Pack(pDst, *pSrc); Size--; pSrc++; } return pDst-(unsigned char *)pDst_; }