1 // StreamObjects.cpp
2
3 #include "StdAfx.h"
4
5 #include "../../../C/Alloc.h"
6
7 #include "StreamObjects.h"
8
Read(void * data,UInt32 size,UInt32 * processedSize)9 STDMETHODIMP CBufInStream::Read(void *data, UInt32 size, UInt32 *processedSize)
10 {
11 if (processedSize)
12 *processedSize = 0;
13 if (size == 0)
14 return S_OK;
15 if (_pos > _size)
16 return E_FAIL;
17 size_t rem = _size - (size_t)_pos;
18 if (rem > size)
19 rem = (size_t)size;
20 memcpy(data, _data + (size_t)_pos, rem);
21 _pos += rem;
22 if (processedSize)
23 *processedSize = (UInt32)rem;
24 return S_OK;
25 }
26
Seek(Int64 offset,UInt32 seekOrigin,UInt64 * newPosition)27 STDMETHODIMP CBufInStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)
28 {
29 switch(seekOrigin)
30 {
31 case STREAM_SEEK_SET: _pos = offset; break;
32 case STREAM_SEEK_CUR: _pos += offset; break;
33 case STREAM_SEEK_END: _pos = _size + offset; break;
34 default: return STG_E_INVALIDFUNCTION;
35 }
36 if (newPosition)
37 *newPosition = _pos;
38 return S_OK;
39 }
40
Free()41 void CByteDynBuffer::Free()
42 {
43 free(_buf);
44 _buf = 0;
45 _capacity = 0;
46 }
47
EnsureCapacity(size_t cap)48 bool CByteDynBuffer::EnsureCapacity(size_t cap)
49 {
50 if (cap <= _capacity)
51 return true;
52 size_t delta;
53 if (_capacity > 64)
54 delta = _capacity / 4;
55 else if (_capacity > 8)
56 delta = 16;
57 else
58 delta = 4;
59 cap = MyMax(_capacity + delta, cap);
60 Byte *buf = (Byte *)realloc(_buf, cap);
61 if (!buf)
62 return false;
63 _buf = buf;
64 _capacity = cap;
65 return true;
66 }
67
GetBufPtrForWriting(size_t addSize)68 Byte *CDynBufSeqOutStream::GetBufPtrForWriting(size_t addSize)
69 {
70 addSize += _size;
71 if (addSize < _size)
72 return NULL;
73 if (!_buffer.EnsureCapacity(addSize))
74 return NULL;
75 return (Byte *)_buffer + _size;
76 }
77
CopyToBuffer(CByteBuffer & dest) const78 void CDynBufSeqOutStream::CopyToBuffer(CByteBuffer &dest) const
79 {
80 dest.SetCapacity(_size);
81 memcpy(dest, _buffer, _size);
82 }
83
Write(const void * data,UInt32 size,UInt32 * processedSize)84 STDMETHODIMP CDynBufSeqOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
85 {
86 if (processedSize)
87 *processedSize = 0;
88 if (size == 0)
89 return S_OK;
90 Byte *buf = GetBufPtrForWriting(size);
91 if (!buf)
92 return E_OUTOFMEMORY;
93 memcpy(buf, data, size);
94 UpdateSize(size);
95 if (processedSize)
96 *processedSize = size;
97 return S_OK;
98 }
99
Write(const void * data,UInt32 size,UInt32 * processedSize)100 STDMETHODIMP CBufPtrSeqOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
101 {
102 size_t rem = _size - _pos;
103 if (rem > size)
104 rem = (size_t)size;
105 memcpy(_buffer + _pos, data, rem);
106 _pos += rem;
107 if (processedSize)
108 *processedSize = (UInt32)rem;
109 return (rem != 0 || size == 0) ? S_OK : E_FAIL;
110 }
111
Write(const void * data,UInt32 size,UInt32 * processedSize)112 STDMETHODIMP CSequentialOutStreamSizeCount::Write(const void *data, UInt32 size, UInt32 *processedSize)
113 {
114 UInt32 realProcessedSize;
115 HRESULT result = _stream->Write(data, size, &realProcessedSize);
116 _size += realProcessedSize;
117 if (processedSize)
118 *processedSize = realProcessedSize;
119 return result;
120 }
121
122 static const UInt64 kEmptyTag = (UInt64)(Int64)-1;
123
Free()124 void CCachedInStream::Free()
125 {
126 MyFree(_tags);
127 _tags = 0;
128 MidFree(_data);
129 _data = 0;
130 }
131
Alloc(unsigned blockSizeLog,unsigned numBlocksLog)132 bool CCachedInStream::Alloc(unsigned blockSizeLog, unsigned numBlocksLog)
133 {
134 unsigned sizeLog = blockSizeLog + numBlocksLog;
135 if (sizeLog >= sizeof(size_t) * 8)
136 return false;
137 size_t dataSize = (size_t)1 << sizeLog;
138 if (_data == 0 || dataSize != _dataSize)
139 {
140 MidFree(_data);
141 _data = (Byte *)MidAlloc(dataSize);
142 if (_data == 0)
143 return false;
144 _dataSize = dataSize;
145 }
146 if (_tags == 0 || numBlocksLog != _numBlocksLog)
147 {
148 MyFree(_tags);
149 _tags = (UInt64 *)MyAlloc(sizeof(UInt64) << numBlocksLog);
150 if (_tags == 0)
151 return false;
152 _numBlocksLog = numBlocksLog;
153 }
154 _blockSizeLog = blockSizeLog;
155 return true;
156 }
157
Init(UInt64 size)158 void CCachedInStream::Init(UInt64 size)
159 {
160 _size = size;
161 _pos = 0;
162 size_t numBlocks = (size_t)1 << _numBlocksLog;
163 for (size_t i = 0; i < numBlocks; i++)
164 _tags[i] = kEmptyTag;
165 }
166
Read(void * data,UInt32 size,UInt32 * processedSize)167 STDMETHODIMP CCachedInStream::Read(void *data, UInt32 size, UInt32 *processedSize)
168 {
169 if (processedSize)
170 *processedSize = 0;
171 if (size == 0)
172 return S_OK;
173 if (_pos > _size)
174 return E_FAIL;
175
176 {
177 UInt64 rem = _size - _pos;
178 if (size > rem)
179 size = (UInt32)rem;
180 }
181
182 while (size != 0)
183 {
184 UInt64 cacheTag = _pos >> _blockSizeLog;
185 size_t cacheIndex = (size_t)cacheTag & (((size_t)1 << _numBlocksLog) - 1);
186 Byte *p = _data + (cacheIndex << _blockSizeLog);
187 if (_tags[cacheIndex] != cacheTag)
188 {
189 UInt64 remInBlock = _size - (cacheTag << _blockSizeLog);
190 size_t blockSize = (size_t)1 << _blockSizeLog;
191 if (blockSize > remInBlock)
192 blockSize = (size_t)remInBlock;
193 RINOK(ReadBlock(cacheTag, p, blockSize));
194 _tags[cacheIndex] = cacheTag;
195 }
196 size_t offset = (size_t)_pos & (((size_t)1 << _blockSizeLog) - 1);
197 UInt32 cur = (UInt32)MyMin(((size_t)1 << _blockSizeLog) - offset, (size_t)size);
198 memcpy(data, p + offset, cur);
199 if (processedSize)
200 *processedSize += cur;
201 data = (void *)((const Byte *)data + cur);
202 _pos += cur;
203 size -= cur;
204 }
205
206 return S_OK;
207 }
208
Seek(Int64 offset,UInt32 seekOrigin,UInt64 * newPosition)209 STDMETHODIMP CCachedInStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)
210 {
211 switch(seekOrigin)
212 {
213 case STREAM_SEEK_SET: _pos = offset; break;
214 case STREAM_SEEK_CUR: _pos = _pos + offset; break;
215 case STREAM_SEEK_END: _pos = _size + offset; break;
216 default: return STG_E_INVALIDFUNCTION;
217 }
218 if (newPosition != 0)
219 *newPosition = _pos;
220 return S_OK;
221 }
222