// InBuffer.cpp | |
#include "StdAfx.h" | |
#include "../../../C/Alloc.h" | |
#include "InBuffer.h" | |
CInBufferBase::CInBufferBase() throw(): | |
_buf(0), | |
_bufLim(0), | |
_bufBase(0), | |
_stream(0), | |
_processedSize(0), | |
_bufSize(0), | |
_wasFinished(false), | |
NumExtraBytes(0) | |
{} | |
bool CInBuffer::Create(size_t bufSize) throw() | |
{ | |
const unsigned kMinBlockSize = 1; | |
if (bufSize < kMinBlockSize) | |
bufSize = kMinBlockSize; | |
if (_bufBase != 0 && _bufSize == bufSize) | |
return true; | |
Free(); | |
_bufSize = bufSize; | |
_bufBase = (Byte *)::MidAlloc(bufSize); | |
return (_bufBase != 0); | |
} | |
void CInBuffer::Free() throw() | |
{ | |
::MidFree(_bufBase); | |
_bufBase = 0; | |
} | |
void CInBufferBase::Init() throw() | |
{ | |
_processedSize = 0; | |
_buf = _bufBase; | |
_bufLim = _buf; | |
_wasFinished = false; | |
#ifdef _NO_EXCEPTIONS | |
ErrorCode = S_OK; | |
#endif | |
NumExtraBytes = 0; | |
} | |
bool CInBufferBase::ReadBlock() | |
{ | |
#ifdef _NO_EXCEPTIONS | |
if (ErrorCode != S_OK) | |
return false; | |
#endif | |
if (_wasFinished) | |
return false; | |
_processedSize += (_buf - _bufBase); | |
_buf = _bufBase; | |
_bufLim = _bufBase; | |
UInt32 processed; | |
// FIX_ME: we can improve it to support (_bufSize >= (1 << 32)) | |
HRESULT result = _stream->Read(_bufBase, (UInt32)_bufSize, &processed); | |
#ifdef _NO_EXCEPTIONS | |
ErrorCode = result; | |
#else | |
if (result != S_OK) | |
throw CInBufferException(result); | |
#endif | |
_bufLim = _buf + processed; | |
_wasFinished = (processed == 0); | |
return !_wasFinished; | |
} | |
bool CInBufferBase::ReadByte_FromNewBlock(Byte &b) | |
{ | |
if (!ReadBlock()) | |
{ | |
NumExtraBytes++; | |
b = 0xFF; | |
return false; | |
} | |
b = *_buf++; | |
return true; | |
} | |
Byte CInBufferBase::ReadByte_FromNewBlock() | |
{ | |
if (!ReadBlock()) | |
{ | |
NumExtraBytes++; | |
return 0xFF; | |
} | |
return *_buf++; | |
} | |
size_t CInBufferBase::ReadBytes(Byte *buf, size_t size) | |
{ | |
if ((size_t)(_bufLim - _buf) >= size) | |
{ | |
const Byte *src = _buf; | |
for (size_t i = 0; i < size; i++) | |
buf[i] = src[i]; | |
_buf += size; | |
return size; | |
} | |
for (size_t i = 0; i < size; i++) | |
{ | |
if (_buf >= _bufLim) | |
if (!ReadBlock()) | |
return i; | |
buf[i] = *_buf++; | |
} | |
return size; | |
} | |
size_t CInBufferBase::Skip(size_t size) | |
{ | |
size_t processed = 0; | |
for (;;) | |
{ | |
size_t rem = (_bufLim - _buf); | |
if (rem >= size) | |
{ | |
_buf += size; | |
return processed + size; | |
} | |
_buf += rem; | |
processed += rem; | |
size -= rem; | |
if (!ReadBlock()) | |
return processed; | |
} | |
} |