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