/*
 *  Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

/*
 * arith_routins.c
 *
 * This C file contains a function for finalizing the bitstream
 * after arithmetic coding.
 *
 */

#include "arith_routins.h"


/****************************************************************************
 * WebRtcIsacfix_EncTerminate(...)
 *
 * Final call to the arithmetic coder for an encoder call. This function
 * terminates and return byte stream.
 *
 * Input:
 *      - streamData        : in-/output struct containing bitstream
 *
 * Return value             : number of bytes in the stream
 */
int16_t WebRtcIsacfix_EncTerminate(Bitstr_enc *streamData)
{
  uint16_t *streamPtr;
  uint16_t negCarry;

  /* point to the right place in the stream buffer */
  streamPtr = streamData->stream + streamData->stream_index;

  /* find minimum length (determined by current interval width) */
  if ( streamData->W_upper > 0x01FFFFFF )
  {
    streamData->streamval += 0x01000000;

    /* if result is less than the added value we must take care of the carry */
    if (streamData->streamval < 0x01000000)
    {
      /* propagate carry */
      if (streamData->full == 0) {
        /* Add value to current value */
        negCarry = *streamPtr;
        negCarry += 0x0100;
        *streamPtr = negCarry;

        /* if value is too big, propagate carry to next byte, and so on */
        while (!(negCarry))
        {
          negCarry = *--streamPtr;
          negCarry++;
          *streamPtr = negCarry;
        }
      } else {
        /* propagate carry by adding one to the previous byte in the
         * stream if that byte is 0xFFFF we need to propagate the carry
         * furhter back in the stream */
        while ( !(++(*--streamPtr)) );
      }

      /* put pointer back to the old value */
      streamPtr = streamData->stream + streamData->stream_index;
    }
    /* write remaining data to bitstream, if "full == 0" first byte has data */
    if (streamData->full == 0) {
      *streamPtr++ += (uint16_t) WEBRTC_SPL_RSHIFT_W32(streamData->streamval, 24);
      streamData->full = 1;
    } else {
      *streamPtr = (uint16_t) WEBRTC_SPL_LSHIFT_W32(
          WEBRTC_SPL_RSHIFT_W32(streamData->streamval, 24), 8);
      streamData->full = 0;
    }
  }
  else
  {
    streamData->streamval += 0x00010000;

    /* if result is less than the added value we must take care of the carry */
    if (streamData->streamval < 0x00010000)
    {
      /* propagate carry */
      if (streamData->full == 0) {
        /* Add value to current value */
        negCarry = *streamPtr;
        negCarry += 0x0100;
        *streamPtr = negCarry;

        /* if value to big, propagate carry to next byte, and so on */
        while (!(negCarry))
        {
          negCarry = *--streamPtr;
          negCarry++;
          *streamPtr = negCarry;
        }
      } else {
        /* Add carry to previous byte */
        while ( !(++(*--streamPtr)) );
      }

      /* put pointer back to the old value */
      streamPtr = streamData->stream + streamData->stream_index;
    }
    /* write remaining data (2 bytes) to bitstream */
    if (streamData->full) {
      *streamPtr++ = (uint16_t) WEBRTC_SPL_RSHIFT_W32(streamData->streamval, 16);
    } else {
      *streamPtr++ |= (uint16_t) WEBRTC_SPL_RSHIFT_W32(streamData->streamval, 24);
      *streamPtr = (uint16_t) WEBRTC_SPL_RSHIFT_W32(streamData->streamval, 8)
          & 0xFF00;
    }
  }

  /* calculate stream length in bytes */
  return (((streamPtr - streamData->stream)<<1) + !(streamData->full));
}
