Blame libfreerdp/codec/rfx_rlgr.c

Packit 1fb8d4
/**
Packit 1fb8d4
 * FreeRDP: A Remote Desktop Protocol Implementation
Packit 1fb8d4
 * RemoteFX Codec Library - RLGR
Packit 1fb8d4
 *
Packit 1fb8d4
 * Copyright 2011 Vic Lee
Packit 1fb8d4
 *
Packit 1fb8d4
 * Licensed under the Apache License, Version 2.0 (the "License");
Packit 1fb8d4
 * you may not use this file except in compliance with the License.
Packit 1fb8d4
 * You may obtain a copy of the License at
Packit 1fb8d4
 *
Packit 1fb8d4
 *     http://www.apache.org/licenses/LICENSE-2.0
Packit 1fb8d4
 *
Packit 1fb8d4
 * Unless required by applicable law or agreed to in writing, software
Packit 1fb8d4
 * distributed under the License is distributed on an "AS IS" BASIS,
Packit 1fb8d4
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Packit 1fb8d4
 * See the License for the specific language governing permissions and
Packit 1fb8d4
 * limitations under the License.
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * This implementation of RLGR refers to
Packit 1fb8d4
 * [MS-RDPRFX] 3.1.8.1.7.3 RLGR1/RLGR3 Pseudocode
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
#ifdef HAVE_CONFIG_H
Packit 1fb8d4
#include "config.h"
Packit 1fb8d4
#endif
Packit 1fb8d4
Packit 1fb8d4
#include <stdio.h>
Packit 1fb8d4
#include <stdlib.h>
Packit 1fb8d4
#include <string.h>
Packit 1fb8d4
Packit 1fb8d4
#include <winpr/crt.h>
Packit 1fb8d4
#include <winpr/print.h>
Packit 1fb8d4
#include <winpr/sysinfo.h>
Packit 1fb8d4
#include <winpr/bitstream.h>
Packit 1fb8d4
#include <winpr/intrin.h>
Packit 1fb8d4
Packit 1fb8d4
#include "rfx_bitstream.h"
Packit 1fb8d4
Packit 1fb8d4
#include "rfx_rlgr.h"
Packit 1fb8d4
Packit 1fb8d4
/* Constants used in RLGR1/RLGR3 algorithm */
Packit Service 5a9772
#define KPMAX (80) /* max value for kp or krp */
Packit Service 5a9772
#define LSGR (3)   /* shift count to convert kp to k */
Packit Service 5a9772
#define UP_GR (4)  /* increase in kp after a zero run in RL mode */
Packit Service 5a9772
#define DN_GR (6)  /* decrease in kp after a nonzero symbol in RL mode */
Packit Service 5a9772
#define UQ_GR (3)  /* increase in kp after nonzero symbol in GR mode */
Packit Service 5a9772
#define DQ_GR (3)  /* decrease in kp after zero symbol in GR mode */
Packit 1fb8d4
Packit 1fb8d4
/* Returns the least number of bits required to represent a given value */
Packit 1fb8d4
#define GetMinBits(_val, _nbits) \
Packit Service 5a9772
	{                            \
Packit Service 5a9772
		UINT32 _v = _val;        \
Packit Service 5a9772
		_nbits = 0;              \
Packit Service 5a9772
		while (_v)               \
Packit Service 5a9772
		{                        \
Packit Service 5a9772
			_v >>= 1;            \
Packit Service 5a9772
			_nbits++;            \
Packit Service 5a9772
		}                        \
Packit Service 5a9772
	}
Packit 1fb8d4
Packit 1fb8d4
/*
Packit 1fb8d4
 * Update the passed parameter and clamp it to the range [0, KPMAX]
Packit 1fb8d4
 * Return the value of parameter right-shifted by LSGR
Packit 1fb8d4
 */
Packit 1fb8d4
#define UpdateParam(_param, _deltaP, _k) \
Packit Service 5a9772
	{                                    \
Packit Service 5a9772
		_param += _deltaP;               \
Packit Service 5a9772
		if (_param > KPMAX)              \
Packit Service 5a9772
			_param = KPMAX;              \
Packit Service 5a9772
		if (_param < 0)                  \
Packit Service 5a9772
			_param = 0;                  \
Packit Service 5a9772
		_k = (_param >> LSGR);           \
Packit Service 5a9772
	}
Packit 1fb8d4
Packit 1fb8d4
static BOOL g_LZCNT = FALSE;
Packit 1fb8d4
Packit 1fb8d4
static INIT_ONCE rfx_rlgr_init_once = INIT_ONCE_STATIC_INIT;
Packit 1fb8d4
Packit Service 5a9772
static BOOL CALLBACK rfx_rlgr_init(PINIT_ONCE once, PVOID param, PVOID* context)
Packit 1fb8d4
{
Packit 1fb8d4
	g_LZCNT = IsProcessorFeaturePresentEx(PF_EX_LZCNT);
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static INLINE UINT32 lzcnt_s(UINT32 x)
Packit 1fb8d4
{
Packit 1fb8d4
	if (!x)
Packit 1fb8d4
		return 32;
Packit Service 5a9772
Packit 1fb8d4
	if (!g_LZCNT)
Packit 1fb8d4
	{
Packit 1fb8d4
		UINT32 y;
Packit 1fb8d4
		int n = 32;
Packit Service 5a9772
		y = x >> 16;
Packit Service 5a9772
		if (y != 0)
Packit Service 5a9772
		{
Packit Service 5a9772
			n = n - 16;
Packit Service 5a9772
			x = y;
Packit Service 5a9772
		}
Packit Service 5a9772
		y = x >> 8;
Packit Service 5a9772
		if (y != 0)
Packit Service 5a9772
		{
Packit Service 5a9772
			n = n - 8;
Packit Service 5a9772
			x = y;
Packit Service 5a9772
		}
Packit Service 5a9772
		y = x >> 4;
Packit Service 5a9772
		if (y != 0)
Packit Service 5a9772
		{
Packit Service 5a9772
			n = n - 4;
Packit Service 5a9772
			x = y;
Packit Service 5a9772
		}
Packit Service 5a9772
		y = x >> 2;
Packit Service 5a9772
		if (y != 0)
Packit Service 5a9772
		{
Packit Service 5a9772
			n = n - 2;
Packit Service 5a9772
			x = y;
Packit Service 5a9772
		}
Packit Service 5a9772
		y = x >> 1;
Packit Service 5a9772
		if (y != 0)
Packit Service 5a9772
			return n - 2;
Packit 1fb8d4
		return n - x;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return __lzcnt(x);
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
int rfx_rlgr_decode(RLGR_MODE mode, const BYTE* pSrcData, UINT32 SrcSize, INT16* pDstData,
Packit Service 5a9772
                    UINT32 DstSize)
Packit 1fb8d4
{
Packit 1fb8d4
	int vk;
Packit 1fb8d4
	int run;
Packit 1fb8d4
	int cnt;
Packit 1fb8d4
	int size;
Packit 1fb8d4
	int nbits;
Packit Service 5a9772
	size_t offset;
Packit 1fb8d4
	INT16 mag;
Packit Service 5a9772
	UINT32 k;
Packit Service 5a9772
	INT32 kp;
Packit Service 5a9772
	UINT32 kr;
Packit Service 5a9772
	INT32 krp;
Packit 1fb8d4
	UINT16 code;
Packit 1fb8d4
	UINT32 sign;
Packit 1fb8d4
	UINT32 nIdx;
Packit 1fb8d4
	UINT32 val1;
Packit 1fb8d4
	UINT32 val2;
Packit 1fb8d4
	INT16* pOutput;
Packit 1fb8d4
	wBitStream* bs;
Packit 1fb8d4
	wBitStream s_bs;
Packit 1fb8d4
Packit 1fb8d4
	InitOnceExecuteOnce(&rfx_rlgr_init_once, rfx_rlgr_init, NULL, NULL);
Packit 1fb8d4
Packit 1fb8d4
	k = 1;
Packit 1fb8d4
	kp = k << LSGR;
Packit 1fb8d4
Packit 1fb8d4
	kr = 1;
Packit 1fb8d4
	krp = kr << LSGR;
Packit 1fb8d4
Packit 1fb8d4
	if ((mode != RLGR1) && (mode != RLGR3))
Packit 1fb8d4
		mode = RLGR1;
Packit 1fb8d4
Packit 1fb8d4
	if (!pSrcData || !SrcSize)
Packit 1fb8d4
		return -1;
Packit 1fb8d4
Packit 1fb8d4
	if (!pDstData || !DstSize)
Packit 1fb8d4
		return -1;
Packit 1fb8d4
Packit 1fb8d4
	pOutput = pDstData;
Packit 1fb8d4
Packit 1fb8d4
	bs = &s_bs;
Packit 1fb8d4
Packit 1fb8d4
	BitStream_Attach(bs, pSrcData, SrcSize);
Packit 1fb8d4
	BitStream_Fetch(bs);
Packit 1fb8d4
Packit 1fb8d4
	while ((BitStream_GetRemainingLength(bs) > 0) && ((pOutput - pDstData) < DstSize))
Packit 1fb8d4
	{
Packit 1fb8d4
		if (k)
Packit 1fb8d4
		{
Packit 1fb8d4
			/* Run-Length (RL) Mode */
Packit 1fb8d4
Packit 1fb8d4
			run = 0;
Packit 1fb8d4
Packit 1fb8d4
			/* count number of leading 0s */
Packit 1fb8d4
Packit 1fb8d4
			cnt = lzcnt_s(bs->accumulator);
Packit 1fb8d4
Packit 1fb8d4
			nbits = BitStream_GetRemainingLength(bs);
Packit 1fb8d4
Packit 1fb8d4
			if (cnt > nbits)
Packit 1fb8d4
				cnt = nbits;
Packit 1fb8d4
Packit 1fb8d4
			vk = cnt;
Packit 1fb8d4
Packit 1fb8d4
			while ((cnt == 32) && (BitStream_GetRemainingLength(bs) > 0))
Packit 1fb8d4
			{
Packit 1fb8d4
				BitStream_Shift32(bs);
Packit 1fb8d4
Packit 1fb8d4
				cnt = lzcnt_s(bs->accumulator);
Packit 1fb8d4
Packit 1fb8d4
				nbits = BitStream_GetRemainingLength(bs);
Packit 1fb8d4
Packit 1fb8d4
				if (cnt > nbits)
Packit 1fb8d4
					cnt = nbits;
Packit 1fb8d4
Packit 1fb8d4
				vk += cnt;
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
			BitStream_Shift(bs, (vk % 32));
Packit 1fb8d4
Packit 1fb8d4
			if (BitStream_GetRemainingLength(bs) < 1)
Packit 1fb8d4
				break;
Packit 1fb8d4
Packit 1fb8d4
			BitStream_Shift(bs, 1);
Packit 1fb8d4
Packit 1fb8d4
			while (vk--)
Packit 1fb8d4
			{
Packit 1fb8d4
				run += (1 << k); /* add (1 << k) to run length */
Packit 1fb8d4
Packit 1fb8d4
				/* update k, kp params */
Packit 1fb8d4
Packit 1fb8d4
				kp += UP_GR;
Packit 1fb8d4
Packit 1fb8d4
				if (kp > KPMAX)
Packit 1fb8d4
					kp = KPMAX;
Packit 1fb8d4
Packit 1fb8d4
				k = kp >> LSGR;
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
			/* next k bits contain run length remainder */
Packit 1fb8d4
Packit 1fb8d4
			if (BitStream_GetRemainingLength(bs) < k)
Packit 1fb8d4
				break;
Packit 1fb8d4
Packit 1fb8d4
			bs->mask = ((1 << k) - 1);
Packit 1fb8d4
			run += ((bs->accumulator >> (32 - k)) & bs->mask);
Packit 1fb8d4
			BitStream_Shift(bs, k);
Packit 1fb8d4
Packit 1fb8d4
			/* read sign bit */
Packit 1fb8d4
Packit 1fb8d4
			if (BitStream_GetRemainingLength(bs) < 1)
Packit 1fb8d4
				break;
Packit 1fb8d4
Packit 1fb8d4
			sign = (bs->accumulator & 0x80000000) ? 1 : 0;
Packit 1fb8d4
			BitStream_Shift(bs, 1);
Packit 1fb8d4
Packit 1fb8d4
			/* count number of leading 1s */
Packit 1fb8d4
Packit 1fb8d4
			cnt = lzcnt_s(~(bs->accumulator));
Packit 1fb8d4
Packit 1fb8d4
			nbits = BitStream_GetRemainingLength(bs);
Packit 1fb8d4
Packit 1fb8d4
			if (cnt > nbits)
Packit 1fb8d4
				cnt = nbits;
Packit 1fb8d4
Packit 1fb8d4
			vk = cnt;
Packit 1fb8d4
Packit 1fb8d4
			while ((cnt == 32) && (BitStream_GetRemainingLength(bs) > 0))
Packit 1fb8d4
			{
Packit 1fb8d4
				BitStream_Shift32(bs);
Packit 1fb8d4
Packit 1fb8d4
				cnt = lzcnt_s(~(bs->accumulator));
Packit 1fb8d4
Packit 1fb8d4
				nbits = BitStream_GetRemainingLength(bs);
Packit 1fb8d4
Packit 1fb8d4
				if (cnt > nbits)
Packit 1fb8d4
					cnt = nbits;
Packit 1fb8d4
Packit 1fb8d4
				vk += cnt;
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
			BitStream_Shift(bs, (vk % 32));
Packit 1fb8d4
Packit 1fb8d4
			if (BitStream_GetRemainingLength(bs) < 1)
Packit 1fb8d4
				break;
Packit 1fb8d4
Packit 1fb8d4
			BitStream_Shift(bs, 1);
Packit 1fb8d4
Packit 1fb8d4
			/* next kr bits contain code remainder */
Packit 1fb8d4
Packit 1fb8d4
			if (BitStream_GetRemainingLength(bs) < kr)
Packit 1fb8d4
				break;
Packit 1fb8d4
Packit 1fb8d4
			bs->mask = ((1 << kr) - 1);
Packit Service 5a9772
			if (kr > 0)
Packit Service 5a9772
				code = (UINT16)((bs->accumulator >> (32 - kr)) & bs->mask);
Packit Service 5a9772
			else
Packit Service 5a9772
				code = 0;
Packit 1fb8d4
			BitStream_Shift(bs, kr);
Packit 1fb8d4
Packit 1fb8d4
			/* add (vk << kr) to code */
Packit 1fb8d4
Packit 1fb8d4
			code |= (vk << kr);
Packit 1fb8d4
Packit 1fb8d4
			if (!vk)
Packit 1fb8d4
			{
Packit 1fb8d4
				/* update kr, krp params */
Packit 1fb8d4
Packit 1fb8d4
				krp -= 2;
Packit 1fb8d4
Packit 1fb8d4
				if (krp < 0)
Packit 1fb8d4
					krp = 0;
Packit 1fb8d4
Packit 1fb8d4
				kr = krp >> LSGR;
Packit 1fb8d4
			}
Packit 1fb8d4
			else if (vk != 1)
Packit 1fb8d4
			{
Packit 1fb8d4
				/* update kr, krp params */
Packit 1fb8d4
Packit 1fb8d4
				krp += vk;
Packit 1fb8d4
Packit 1fb8d4
				if (krp > KPMAX)
Packit 1fb8d4
					krp = KPMAX;
Packit 1fb8d4
Packit 1fb8d4
				kr = krp >> LSGR;
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
			/* update k, kp params */
Packit 1fb8d4
Packit 1fb8d4
			kp -= DN_GR;
Packit 1fb8d4
Packit 1fb8d4
			if (kp < 0)
Packit 1fb8d4
				kp = 0;
Packit 1fb8d4
Packit 1fb8d4
			k = kp >> LSGR;
Packit 1fb8d4
Packit 1fb8d4
			/* compute magnitude from code */
Packit 1fb8d4
Packit 1fb8d4
			if (sign)
Packit Service 5a9772
				mag = ((INT16)(code + 1)) * -1;
Packit 1fb8d4
			else
Packit Service 5a9772
				mag = (INT16)(code + 1);
Packit 1fb8d4
Packit 1fb8d4
			/* write to output stream */
Packit 1fb8d4
Packit Service 5a9772
			offset = (pOutput - pDstData);
Packit 1fb8d4
			size = run;
Packit 1fb8d4
Packit 1fb8d4
			if ((offset + size) > DstSize)
Packit 1fb8d4
				size = DstSize - offset;
Packit 1fb8d4
Packit 1fb8d4
			if (size)
Packit 1fb8d4
			{
Packit 1fb8d4
				ZeroMemory(pOutput, size * sizeof(INT16));
Packit 1fb8d4
				pOutput += size;
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
			if ((pOutput - pDstData) < DstSize)
Packit 1fb8d4
			{
Packit 1fb8d4
				*pOutput = mag;
Packit 1fb8d4
				pOutput++;
Packit 1fb8d4
			}
Packit 1fb8d4
		}
Packit 1fb8d4
		else
Packit 1fb8d4
		{
Packit 1fb8d4
			/* Golomb-Rice (GR) Mode */
Packit 1fb8d4
Packit 1fb8d4
			/* count number of leading 1s */
Packit 1fb8d4
Packit 1fb8d4
			cnt = lzcnt_s(~(bs->accumulator));
Packit 1fb8d4
Packit 1fb8d4
			nbits = BitStream_GetRemainingLength(bs);
Packit 1fb8d4
Packit 1fb8d4
			if (cnt > nbits)
Packit 1fb8d4
				cnt = nbits;
Packit 1fb8d4
Packit 1fb8d4
			vk = cnt;
Packit 1fb8d4
Packit 1fb8d4
			while ((cnt == 32) && (BitStream_GetRemainingLength(bs) > 0))
Packit 1fb8d4
			{
Packit 1fb8d4
				BitStream_Shift32(bs);
Packit 1fb8d4
Packit 1fb8d4
				cnt = lzcnt_s(~(bs->accumulator));
Packit 1fb8d4
Packit 1fb8d4
				nbits = BitStream_GetRemainingLength(bs);
Packit 1fb8d4
Packit 1fb8d4
				if (cnt > nbits)
Packit 1fb8d4
					cnt = nbits;
Packit 1fb8d4
Packit 1fb8d4
				vk += cnt;
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
			BitStream_Shift(bs, (vk % 32));
Packit 1fb8d4
Packit 1fb8d4
			if (BitStream_GetRemainingLength(bs) < 1)
Packit 1fb8d4
				break;
Packit 1fb8d4
Packit 1fb8d4
			BitStream_Shift(bs, 1);
Packit 1fb8d4
Packit 1fb8d4
			/* next kr bits contain code remainder */
Packit 1fb8d4
Packit 1fb8d4
			if (BitStream_GetRemainingLength(bs) < kr)
Packit 1fb8d4
				break;
Packit 1fb8d4
Packit 1fb8d4
			bs->mask = ((1 << kr) - 1);
Packit Service 5a9772
			if (kr > 0)
Packit Service 5a9772
				code = (UINT16)((bs->accumulator >> (32 - kr)) & bs->mask);
Packit Service 5a9772
			else
Packit Service 5a9772
				code = 0;
Packit 1fb8d4
			BitStream_Shift(bs, kr);
Packit 1fb8d4
Packit 1fb8d4
			/* add (vk << kr) to code */
Packit 1fb8d4
Packit 1fb8d4
			code |= (vk << kr);
Packit 1fb8d4
Packit 1fb8d4
			if (!vk)
Packit 1fb8d4
			{
Packit 1fb8d4
				/* update kr, krp params */
Packit 1fb8d4
Packit 1fb8d4
				krp -= 2;
Packit 1fb8d4
Packit 1fb8d4
				if (krp < 0)
Packit 1fb8d4
					krp = 0;
Packit 1fb8d4
Packit 1fb8d4
				kr = krp >> LSGR;
Packit 1fb8d4
			}
Packit 1fb8d4
			else if (vk != 1)
Packit 1fb8d4
			{
Packit 1fb8d4
				/* update kr, krp params */
Packit 1fb8d4
Packit 1fb8d4
				krp += vk;
Packit 1fb8d4
Packit 1fb8d4
				if (krp > KPMAX)
Packit 1fb8d4
					krp = KPMAX;
Packit 1fb8d4
Packit 1fb8d4
				kr = krp >> LSGR;
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
			if (mode == RLGR1) /* RLGR1 */
Packit 1fb8d4
			{
Packit 1fb8d4
				if (!code)
Packit 1fb8d4
				{
Packit 1fb8d4
					/* update k, kp params */
Packit 1fb8d4
Packit 1fb8d4
					kp += UQ_GR;
Packit 1fb8d4
Packit 1fb8d4
					if (kp > KPMAX)
Packit 1fb8d4
						kp = KPMAX;
Packit 1fb8d4
Packit 1fb8d4
					k = kp >> LSGR;
Packit 1fb8d4
Packit 1fb8d4
					mag = 0;
Packit 1fb8d4
				}
Packit 1fb8d4
				else
Packit 1fb8d4
				{
Packit 1fb8d4
					/* update k, kp params */
Packit 1fb8d4
Packit 1fb8d4
					kp -= DQ_GR;
Packit 1fb8d4
Packit 1fb8d4
					if (kp < 0)
Packit 1fb8d4
						kp = 0;
Packit 1fb8d4
Packit 1fb8d4
					k = kp >> LSGR;
Packit 1fb8d4
Packit 1fb8d4
					/*
Packit 1fb8d4
					 * code = 2 * mag - sign
Packit 1fb8d4
					 * sign + code = 2 * mag
Packit 1fb8d4
					 */
Packit 1fb8d4
Packit 1fb8d4
					if (code & 1)
Packit Service 5a9772
						mag = ((INT16)((code + 1) >> 1)) * -1;
Packit 1fb8d4
					else
Packit Service 5a9772
						mag = (INT16)(code >> 1);
Packit 1fb8d4
				}
Packit 1fb8d4
Packit 1fb8d4
				if ((pOutput - pDstData) < DstSize)
Packit 1fb8d4
				{
Packit 1fb8d4
					*pOutput = mag;
Packit 1fb8d4
					pOutput++;
Packit 1fb8d4
				}
Packit 1fb8d4
			}
Packit 1fb8d4
			else if (mode == RLGR3) /* RLGR3 */
Packit 1fb8d4
			{
Packit 1fb8d4
				nIdx = 0;
Packit 1fb8d4
Packit 1fb8d4
				if (code)
Packit 1fb8d4
				{
Packit Service 5a9772
					mag = (UINT32)code;
Packit 1fb8d4
					nIdx = 32 - lzcnt_s(mag);
Packit 1fb8d4
				}
Packit 1fb8d4
Packit 1fb8d4
				if (BitStream_GetRemainingLength(bs) < nIdx)
Packit 1fb8d4
					break;
Packit 1fb8d4
Packit 1fb8d4
				bs->mask = ((1 << nIdx) - 1);
Packit Service 5a9772
				if (nIdx > 0)
Packit Service 5a9772
					val1 = ((bs->accumulator >> (32 - nIdx)) & bs->mask);
Packit Service 5a9772
				else
Packit Service 5a9772
					val1 = 0;
Packit 1fb8d4
				BitStream_Shift(bs, nIdx);
Packit 1fb8d4
Packit 1fb8d4
				val2 = code - val1;
Packit 1fb8d4
Packit 1fb8d4
				if (val1 && val2)
Packit 1fb8d4
				{
Packit 1fb8d4
					/* update k, kp params */
Packit 1fb8d4
Packit 1fb8d4
					kp -= (2 * DQ_GR);
Packit 1fb8d4
Packit 1fb8d4
					if (kp < 0)
Packit 1fb8d4
						kp = 0;
Packit 1fb8d4
Packit 1fb8d4
					k = kp >> LSGR;
Packit 1fb8d4
				}
Packit 1fb8d4
				else if (!val1 && !val2)
Packit 1fb8d4
				{
Packit 1fb8d4
					/* update k, kp params */
Packit 1fb8d4
Packit 1fb8d4
					kp += (2 * UQ_GR);
Packit 1fb8d4
Packit 1fb8d4
					if (kp > KPMAX)
Packit 1fb8d4
						kp = KPMAX;
Packit 1fb8d4
Packit 1fb8d4
					k = kp >> LSGR;
Packit 1fb8d4
				}
Packit 1fb8d4
Packit 1fb8d4
				if (val1 & 1)
Packit Service 5a9772
					mag = ((INT16)((val1 + 1) >> 1)) * -1;
Packit 1fb8d4
				else
Packit Service 5a9772
					mag = (INT16)(val1 >> 1);
Packit 1fb8d4
Packit 1fb8d4
				if ((pOutput - pDstData) < DstSize)
Packit 1fb8d4
				{
Packit 1fb8d4
					*pOutput = mag;
Packit 1fb8d4
					pOutput++;
Packit 1fb8d4
				}
Packit 1fb8d4
Packit 1fb8d4
				if (val2 & 1)
Packit Service 5a9772
					mag = ((INT16)((val2 + 1) >> 1)) * -1;
Packit 1fb8d4
				else
Packit Service 5a9772
					mag = (INT16)(val2 >> 1);
Packit 1fb8d4
Packit 1fb8d4
				if ((pOutput - pDstData) < DstSize)
Packit 1fb8d4
				{
Packit 1fb8d4
					*pOutput = mag;
Packit 1fb8d4
					pOutput++;
Packit 1fb8d4
				}
Packit 1fb8d4
			}
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit Service 5a9772
	offset = (pOutput - pDstData);
Packit 1fb8d4
Packit 1fb8d4
	if (offset < DstSize)
Packit 1fb8d4
	{
Packit 1fb8d4
		size = DstSize - offset;
Packit 1fb8d4
		ZeroMemory(pOutput, size * 2);
Packit 1fb8d4
		pOutput += size;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit Service 5a9772
	offset = (pOutput - pDstData);
Packit 1fb8d4
Packit 1fb8d4
	if (offset != DstSize)
Packit 1fb8d4
		return -1;
Packit 1fb8d4
Packit 1fb8d4
	return 1;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/* Returns the next coefficient (a signed int) to encode, from the input stream */
Packit Service 5a9772
#define GetNextInput(_n)   \
Packit Service 5a9772
	{                      \
Packit Service 5a9772
		if (data_size > 0) \
Packit Service 5a9772
		{                  \
Packit Service 5a9772
			_n = *data++;  \
Packit Service 5a9772
			data_size--;   \
Packit Service 5a9772
		}                  \
Packit Service 5a9772
		else               \
Packit Service 5a9772
		{                  \
Packit Service 5a9772
			_n = 0;        \
Packit Service 5a9772
		}                  \
Packit Service 5a9772
	}
Packit 1fb8d4
Packit 1fb8d4
/* Emit bitPattern to the output bitstream */
Packit 1fb8d4
#define OutputBits(numBits, bitPattern) rfx_bitstream_put_bits(bs, bitPattern, numBits)
Packit 1fb8d4
Packit 1fb8d4
/* Emit a bit (0 or 1), count number of times, to the output bitstream */
Packit Service 5a9772
#define OutputBit(count, bit)                                    \
Packit Service 5a9772
	{                                                            \
Packit Service 5a9772
		UINT16 _b = (bit ? 0xFFFF : 0);                          \
Packit Service 5a9772
		int _c = (count);                                        \
Packit Service 5a9772
		for (; _c > 0; _c -= 16)                                 \
Packit Service 5a9772
			rfx_bitstream_put_bits(bs, _b, (_c > 16 ? 16 : _c)); \
Packit Service 5a9772
	}
Packit 1fb8d4
Packit Service 5a9772
/* Converts the input value to (2 * abs(input) - sign(input)), where sign(input) = (input < 0 ? 1 :
Packit Service 5a9772
 * 0) and returns it */
Packit Service 5a9772
#define Get2MagSign(input) ((input) >= 0 ? 2 * (input) : -2 * (input)-1)
Packit 1fb8d4
Packit 1fb8d4
/* Outputs the Golomb/Rice encoding of a non-negative integer */
Packit 1fb8d4
#define CodeGR(krp, val) rfx_rlgr_code_gr(bs, krp, val)
Packit 1fb8d4
Packit 1fb8d4
static void rfx_rlgr_code_gr(RFX_BITSTREAM* bs, int* krp, UINT32 val)
Packit 1fb8d4
{
Packit 1fb8d4
	int kr = *krp >> LSGR;
Packit 1fb8d4
Packit 1fb8d4
	/* unary part of GR code */
Packit 1fb8d4
Packit 1fb8d4
	UINT32 vk = (val) >> kr;
Packit 1fb8d4
	OutputBit(vk, 1);
Packit 1fb8d4
	OutputBit(1, 0);
Packit 1fb8d4
Packit 1fb8d4
	/* remainder part of GR code, if needed */
Packit 1fb8d4
	if (kr)
Packit 1fb8d4
	{
Packit 1fb8d4
		OutputBits(kr, val & ((1 << kr) - 1));
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	/* update krp, only if it is not equal to 1 */
Packit 1fb8d4
	if (vk == 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		UpdateParam(*krp, -2, kr);
Packit 1fb8d4
	}
Packit Service 5a9772
	else if (vk > 1)
Packit 1fb8d4
	{
Packit 1fb8d4
		UpdateParam(*krp, vk, kr);
Packit 1fb8d4
	}
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
int rfx_rlgr_encode(RLGR_MODE mode, const INT16* data, UINT32 data_size, BYTE* buffer,
Packit Service 5a9772
                    UINT32 buffer_size)
Packit 1fb8d4
{
Packit 1fb8d4
	int k;
Packit 1fb8d4
	int kp;
Packit 1fb8d4
	int krp;
Packit 1fb8d4
	RFX_BITSTREAM* bs;
Packit 1fb8d4
	int processed_size;
Packit 1fb8d4
Packit Service 5a9772
	if (!(bs = (RFX_BITSTREAM*)calloc(1, sizeof(RFX_BITSTREAM))))
Packit 1fb8d4
		return 0;
Packit 1fb8d4
Packit 1fb8d4
	rfx_bitstream_attach(bs, buffer, buffer_size);
Packit 1fb8d4
Packit 1fb8d4
	/* initialize the parameters */
Packit 1fb8d4
	k = 1;
Packit 1fb8d4
	kp = 1 << LSGR;
Packit 1fb8d4
	krp = 1 << LSGR;
Packit 1fb8d4
Packit 1fb8d4
	/* process all the input coefficients */
Packit 1fb8d4
	while (data_size > 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		int input;
Packit 1fb8d4
Packit 1fb8d4
		if (k)
Packit 1fb8d4
		{
Packit 1fb8d4
			int numZeros;
Packit 1fb8d4
			int runmax;
Packit 1fb8d4
			int mag;
Packit 1fb8d4
			int sign;
Packit 1fb8d4
Packit 1fb8d4
			/* RUN-LENGTH MODE */
Packit 1fb8d4
Packit 1fb8d4
			/* collect the run of zeros in the input stream */
Packit 1fb8d4
			numZeros = 0;
Packit 1fb8d4
			GetNextInput(input);
Packit 1fb8d4
			while (input == 0 && data_size > 0)
Packit 1fb8d4
			{
Packit 1fb8d4
				numZeros++;
Packit 1fb8d4
				GetNextInput(input);
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
			// emit output zeros
Packit 1fb8d4
			runmax = 1 << k;
Packit 1fb8d4
			while (numZeros >= runmax)
Packit 1fb8d4
			{
Packit 1fb8d4
				OutputBit(1, 0); /* output a zero bit */
Packit 1fb8d4
				numZeros -= runmax;
Packit 1fb8d4
				UpdateParam(kp, UP_GR, k); /* update kp, k */
Packit 1fb8d4
				runmax = 1 << k;
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
			/* output a 1 to terminate runs */
Packit 1fb8d4
			OutputBit(1, 1);
Packit 1fb8d4
Packit 1fb8d4
			/* output the remaining run length using k bits */
Packit 1fb8d4
			OutputBits(k, numZeros);
Packit 1fb8d4
Packit 1fb8d4
			/* note: when we reach here and the last byte being encoded is 0, we still
Packit 1fb8d4
			   need to output the last two bits, otherwise mstsc will crash */
Packit 1fb8d4
Packit 1fb8d4
			/* encode the nonzero value using GR coding */
Packit 1fb8d4
			mag = (input < 0 ? -input : input); /* absolute value of input coefficient */
Packit Service 5a9772
			sign = (input < 0 ? 1 : 0);         /* sign of input coefficient */
Packit 1fb8d4
Packit Service 5a9772
			OutputBit(1, sign);              /* output the sign bit */
Packit 1fb8d4
			CodeGR(&krp, mag ? mag - 1 : 0); /* output GR code for (mag - 1) */
Packit 1fb8d4
Packit 1fb8d4
			UpdateParam(kp, -DN_GR, k);
Packit 1fb8d4
		}
Packit 1fb8d4
		else
Packit 1fb8d4
		{
Packit 1fb8d4
			/* GOLOMB-RICE MODE */
Packit 1fb8d4
Packit 1fb8d4
			if (mode == RLGR1)
Packit 1fb8d4
			{
Packit 1fb8d4
				UINT32 twoMs;
Packit 1fb8d4
Packit 1fb8d4
				/* RLGR1 variant */
Packit 1fb8d4
Packit 1fb8d4
				/* convert input to (2*magnitude - sign), encode using GR code */
Packit 1fb8d4
				GetNextInput(input);
Packit 1fb8d4
				twoMs = Get2MagSign(input);
Packit 1fb8d4
				CodeGR(&krp, twoMs);
Packit 1fb8d4
Packit 1fb8d4
				/* update k, kp */
Packit 1fb8d4
				/* NOTE: as of Aug 2011, the algorithm is still wrongly documented
Packit 1fb8d4
				   and the update direction is reversed */
Packit 1fb8d4
				if (twoMs)
Packit 1fb8d4
				{
Packit 1fb8d4
					UpdateParam(kp, -DQ_GR, k);
Packit 1fb8d4
				}
Packit 1fb8d4
				else
Packit 1fb8d4
				{
Packit 1fb8d4
					UpdateParam(kp, UQ_GR, k);
Packit 1fb8d4
				}
Packit 1fb8d4
			}
Packit 1fb8d4
			else /* mode == RLGR3 */
Packit 1fb8d4
			{
Packit 1fb8d4
				UINT32 twoMs1;
Packit 1fb8d4
				UINT32 twoMs2;
Packit 1fb8d4
				UINT32 sum2Ms;
Packit 1fb8d4
				UINT32 nIdx;
Packit 1fb8d4
Packit 1fb8d4
				/* RLGR3 variant */
Packit 1fb8d4
Packit 1fb8d4
				/* convert the next two input values to (2*magnitude - sign) and */
Packit 1fb8d4
				/* encode their sum using GR code */
Packit 1fb8d4
Packit 1fb8d4
				GetNextInput(input);
Packit 1fb8d4
				twoMs1 = Get2MagSign(input);
Packit 1fb8d4
				GetNextInput(input);
Packit 1fb8d4
				twoMs2 = Get2MagSign(input);
Packit 1fb8d4
				sum2Ms = twoMs1 + twoMs2;
Packit 1fb8d4
Packit 1fb8d4
				CodeGR(&krp, sum2Ms);
Packit 1fb8d4
Packit 1fb8d4
				/* encode binary representation of the first input (twoMs1). */
Packit 1fb8d4
				GetMinBits(sum2Ms, nIdx);
Packit 1fb8d4
				OutputBits(nIdx, twoMs1);
Packit 1fb8d4
Packit 1fb8d4
				/* update k,kp for the two input values */
Packit 1fb8d4
Packit 1fb8d4
				if (twoMs1 && twoMs2)
Packit 1fb8d4
				{
Packit 1fb8d4
					UpdateParam(kp, -2 * DQ_GR, k);
Packit 1fb8d4
				}
Packit 1fb8d4
				else if (!twoMs1 && !twoMs2)
Packit 1fb8d4
				{
Packit 1fb8d4
					UpdateParam(kp, 2 * UQ_GR, k);
Packit 1fb8d4
				}
Packit 1fb8d4
			}
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	rfx_bitstream_flush(bs);
Packit 1fb8d4
	processed_size = rfx_bitstream_get_processed_bytes(bs);
Packit 1fb8d4
	free(bs);
Packit 1fb8d4
Packit 1fb8d4
	return processed_size;
Packit 1fb8d4
}