1// InBuffer.cpp
2
3#include "StdAfx.h"
4
5#include "../../../C/Alloc.h"
6
7#include "InBuffer.h"
8
9CInBufferBase::CInBufferBase() throw():
10  _buf(0),
11  _bufLim(0),
12  _bufBase(0),
13  _stream(0),
14  _processedSize(0),
15  _bufSize(0),
16  _wasFinished(false),
17  NumExtraBytes(0)
18{}
19
20bool CInBuffer::Create(size_t bufSize) throw()
21{
22  const unsigned kMinBlockSize = 1;
23  if (bufSize < kMinBlockSize)
24    bufSize = kMinBlockSize;
25  if (_bufBase != 0 && _bufSize == bufSize)
26    return true;
27  Free();
28  _bufSize = bufSize;
29  _bufBase = (Byte *)::MidAlloc(bufSize);
30  return (_bufBase != 0);
31}
32
33void CInBuffer::Free() throw()
34{
35  ::MidFree(_bufBase);
36  _bufBase = 0;
37}
38
39void CInBufferBase::Init() throw()
40{
41  _processedSize = 0;
42  _buf = _bufBase;
43  _bufLim = _buf;
44  _wasFinished = false;
45  #ifdef _NO_EXCEPTIONS
46  ErrorCode = S_OK;
47  #endif
48  NumExtraBytes = 0;
49}
50
51bool CInBufferBase::ReadBlock()
52{
53  #ifdef _NO_EXCEPTIONS
54  if (ErrorCode != S_OK)
55    return false;
56  #endif
57  if (_wasFinished)
58    return false;
59  _processedSize += (_buf - _bufBase);
60  _buf = _bufBase;
61  _bufLim = _bufBase;
62  UInt32 processed;
63  // FIX_ME: we can improve it to support (_bufSize >= (1 << 32))
64  HRESULT result = _stream->Read(_bufBase, (UInt32)_bufSize, &processed);
65  #ifdef _NO_EXCEPTIONS
66  ErrorCode = result;
67  #else
68  if (result != S_OK)
69    throw CInBufferException(result);
70  #endif
71  _bufLim = _buf + processed;
72  _wasFinished = (processed == 0);
73  return !_wasFinished;
74}
75
76bool CInBufferBase::ReadByte_FromNewBlock(Byte &b)
77{
78  if (!ReadBlock())
79  {
80    NumExtraBytes++;
81    b = 0xFF;
82    return false;
83  }
84  b = *_buf++;
85  return true;
86}
87
88Byte CInBufferBase::ReadByte_FromNewBlock()
89{
90  if (!ReadBlock())
91  {
92    NumExtraBytes++;
93    return 0xFF;
94  }
95  return *_buf++;
96}
97
98size_t CInBufferBase::ReadBytes(Byte *buf, size_t size)
99{
100  if ((size_t)(_bufLim - _buf) >= size)
101  {
102    const Byte *src = _buf;
103    for (size_t i = 0; i < size; i++)
104      buf[i] = src[i];
105    _buf += size;
106    return size;
107  }
108  for (size_t i = 0; i < size; i++)
109  {
110    if (_buf >= _bufLim)
111      if (!ReadBlock())
112        return i;
113    buf[i] = *_buf++;
114  }
115  return size;
116}
117
118size_t CInBufferBase::Skip(size_t size)
119{
120  size_t processed = 0;
121  for (;;)
122  {
123    size_t rem = (_bufLim - _buf);
124    if (rem >= size)
125    {
126      _buf += size;
127      return processed + size;
128    }
129    _buf += rem;
130    processed += rem;
131    size -= rem;
132    if (!ReadBlock())
133      return processed;
134  }
135}
136