// OutByte.cpp



#include "StdAfx.h"



#include "OutBuffer.h"



extern "C"

{

  #include "../../../C/Alloc.h"

}



bool COutBuffer::Create(UInt32 bufferSize)

{

  const UInt32 kMinBlockSize = 1;

  if (bufferSize < kMinBlockSize)

    bufferSize = kMinBlockSize;

  if (_buffer != 0 && _bufferSize == bufferSize)

    return true;

  Free();

  _bufferSize = bufferSize;

  _buffer = (Byte *)::MidAlloc(bufferSize);

  return (_buffer != 0);

}



void COutBuffer::Free()

{

  ::MidFree(_buffer);

  _buffer = 0;

}



void COutBuffer::SetStream(ISequentialOutStream *stream)

{

  _stream = stream;

}



void COutBuffer::Init()

{

  _streamPos = 0;

  _limitPos = _bufferSize;

  _pos = 0;

  _processedSize = 0;

  _overDict = false;

  #ifdef _NO_EXCEPTIONS

  ErrorCode = S_OK;

  #endif

}



UInt64 COutBuffer::GetProcessedSize() const

{ 

  UInt64 res = _processedSize + _pos - _streamPos;

  if (_streamPos > _pos) 

    res += _bufferSize;

  return res;

}





HRESULT COutBuffer::FlushPart()

{

  // _streamPos < _bufferSize

  UInt32 size = (_streamPos >= _pos) ? (_bufferSize - _streamPos) : (_pos - _streamPos);

  HRESULT result = S_OK;

  #ifdef _NO_EXCEPTIONS

  result = ErrorCode;

  #endif

  if (_buffer2 != 0)

  {

    memmove(_buffer2, _buffer + _streamPos, size);

    _buffer2 += size;

  }



  if (_stream != 0

      #ifdef _NO_EXCEPTIONS

      && (ErrorCode == S_OK)

      #endif

     )

  {

    UInt32 processedSize = 0;

    result = _stream->Write(_buffer + _streamPos, size, &processedSize);

    size = processedSize;

  }

  _streamPos += size;

  if (_streamPos == _bufferSize)

    _streamPos = 0;

  if (_pos == _bufferSize)

  {

    _overDict = true;

    _pos = 0;

  }

  _limitPos = (_streamPos > _pos) ? _streamPos : _bufferSize;

  _processedSize += size;

  return result;

}



HRESULT COutBuffer::Flush()

{

  #ifdef _NO_EXCEPTIONS

  if (ErrorCode != S_OK)

    return ErrorCode;

  #endif



  while(_streamPos != _pos)

  {

    HRESULT result = FlushPart();

    if (result != S_OK)

      return result;

  }

  return S_OK;

}



void COutBuffer::FlushWithCheck()

{

  HRESULT result = Flush();

  #ifdef _NO_EXCEPTIONS

  ErrorCode = result;

  #else

  if (result != S_OK)

    throw COutBufferException(result);

  #endif

}

