1370b324cSopenharmony_ci// InOutTempBuffer.cpp
2370b324cSopenharmony_ci
3370b324cSopenharmony_ci#include "StdAfx.h"
4370b324cSopenharmony_ci
5370b324cSopenharmony_ci#include "../../../C/Alloc.h"
6370b324cSopenharmony_ci
7370b324cSopenharmony_ci#include "InOutTempBuffer.h"
8370b324cSopenharmony_ci
9370b324cSopenharmony_ci#include "StreamUtils.h"
10370b324cSopenharmony_ci
11370b324cSopenharmony_ci#ifdef USE_InOutTempBuffer_FILE
12370b324cSopenharmony_ci
13370b324cSopenharmony_ci#include "../../../C/7zCrc.h"
14370b324cSopenharmony_ci
15370b324cSopenharmony_ci#define kTempFilePrefixString FTEXT("7zt")
16370b324cSopenharmony_ci/*
17370b324cSopenharmony_ci  Total buffer size limit, if we use temp file scheme:
18370b324cSopenharmony_ci    32-bit:  16 MiB = 1 MiB *   16 buffers
19370b324cSopenharmony_ci    64-bit:   4 GiB = 1 MiB * 4096 buffers
20370b324cSopenharmony_ci*/
21370b324cSopenharmony_cistatic const size_t kNumBufsMax = (size_t)1 << (sizeof(size_t) * 2 - 4);
22370b324cSopenharmony_ci
23370b324cSopenharmony_ci#endif
24370b324cSopenharmony_ci
25370b324cSopenharmony_cistatic const size_t kBufSize = (size_t)1 << 20;
26370b324cSopenharmony_ci
27370b324cSopenharmony_ci
28370b324cSopenharmony_ciCInOutTempBuffer::CInOutTempBuffer():
29370b324cSopenharmony_ci    _size(0),
30370b324cSopenharmony_ci    _bufs(NULL),
31370b324cSopenharmony_ci    _numBufs(0),
32370b324cSopenharmony_ci    _numFilled(0)
33370b324cSopenharmony_ci{
34370b324cSopenharmony_ci #ifdef USE_InOutTempBuffer_FILE
35370b324cSopenharmony_ci  _tempFile_Created = false;
36370b324cSopenharmony_ci  _useMemOnly = false;
37370b324cSopenharmony_ci  _crc = CRC_INIT_VAL;
38370b324cSopenharmony_ci #endif
39370b324cSopenharmony_ci}
40370b324cSopenharmony_ci
41370b324cSopenharmony_ciCInOutTempBuffer::~CInOutTempBuffer()
42370b324cSopenharmony_ci{
43370b324cSopenharmony_ci  for (size_t i = 0; i < _numBufs; i++)
44370b324cSopenharmony_ci    MyFree(_bufs[i]);
45370b324cSopenharmony_ci  MyFree(_bufs);
46370b324cSopenharmony_ci}
47370b324cSopenharmony_ci
48370b324cSopenharmony_ci
49370b324cSopenharmony_civoid *CInOutTempBuffer::GetBuf(size_t index)
50370b324cSopenharmony_ci{
51370b324cSopenharmony_ci  if (index >= _numBufs)
52370b324cSopenharmony_ci  {
53370b324cSopenharmony_ci    const size_t num = (_numBufs == 0 ? 16 : _numBufs * 2);
54370b324cSopenharmony_ci    void **p = (void **)MyRealloc(_bufs, num * sizeof(void *));
55370b324cSopenharmony_ci    if (!p)
56370b324cSopenharmony_ci      return NULL;
57370b324cSopenharmony_ci    _bufs = p;
58370b324cSopenharmony_ci    memset(p + _numBufs, 0, (num - _numBufs) * sizeof(void *));
59370b324cSopenharmony_ci    _numBufs = num;
60370b324cSopenharmony_ci  }
61370b324cSopenharmony_ci
62370b324cSopenharmony_ci  void *buf = _bufs[index];
63370b324cSopenharmony_ci  if (!buf)
64370b324cSopenharmony_ci  {
65370b324cSopenharmony_ci    buf = MyAlloc(kBufSize);
66370b324cSopenharmony_ci    if (buf)
67370b324cSopenharmony_ci      _bufs[index] = buf;
68370b324cSopenharmony_ci  }
69370b324cSopenharmony_ci  return buf;
70370b324cSopenharmony_ci}
71370b324cSopenharmony_ci
72370b324cSopenharmony_ci
73370b324cSopenharmony_ciHRESULT CInOutTempBuffer::Write_HRESULT(const void *data, UInt32 size)
74370b324cSopenharmony_ci{
75370b324cSopenharmony_ci  if (size == 0)
76370b324cSopenharmony_ci    return S_OK;
77370b324cSopenharmony_ci
78370b324cSopenharmony_ci #ifdef USE_InOutTempBuffer_FILE
79370b324cSopenharmony_ci  if (!_tempFile_Created)
80370b324cSopenharmony_ci #endif
81370b324cSopenharmony_ci  for (;;)  // loop for additional attemp to allocate memory after file creation error
82370b324cSopenharmony_ci  {
83370b324cSopenharmony_ci   #ifdef USE_InOutTempBuffer_FILE
84370b324cSopenharmony_ci    bool allocError = false;
85370b324cSopenharmony_ci   #endif
86370b324cSopenharmony_ci
87370b324cSopenharmony_ci    for (;;)  // loop for writing to buffers
88370b324cSopenharmony_ci    {
89370b324cSopenharmony_ci      const size_t index = (size_t)(_size / kBufSize);
90370b324cSopenharmony_ci
91370b324cSopenharmony_ci     #ifdef USE_InOutTempBuffer_FILE
92370b324cSopenharmony_ci      if (index >= kNumBufsMax && !_useMemOnly)
93370b324cSopenharmony_ci        break;
94370b324cSopenharmony_ci     #endif
95370b324cSopenharmony_ci
96370b324cSopenharmony_ci      void *buf = GetBuf(index);
97370b324cSopenharmony_ci      if (!buf)
98370b324cSopenharmony_ci      {
99370b324cSopenharmony_ci       #ifdef USE_InOutTempBuffer_FILE
100370b324cSopenharmony_ci        if (!_useMemOnly)
101370b324cSopenharmony_ci        {
102370b324cSopenharmony_ci          allocError = true;
103370b324cSopenharmony_ci          break;
104370b324cSopenharmony_ci        }
105370b324cSopenharmony_ci       #endif
106370b324cSopenharmony_ci        return E_OUTOFMEMORY;
107370b324cSopenharmony_ci      }
108370b324cSopenharmony_ci
109370b324cSopenharmony_ci      const size_t offset = (size_t)(_size) & (kBufSize - 1);
110370b324cSopenharmony_ci      size_t cur = kBufSize - offset;
111370b324cSopenharmony_ci      if (cur > size)
112370b324cSopenharmony_ci        cur = size;
113370b324cSopenharmony_ci      memcpy((Byte *)buf + offset, data, cur);
114370b324cSopenharmony_ci      _size += cur;
115370b324cSopenharmony_ci      if (index >= _numFilled)
116370b324cSopenharmony_ci        _numFilled = index + 1;
117370b324cSopenharmony_ci      data = (const void *)((const Byte *)data + cur);
118370b324cSopenharmony_ci      size -= (UInt32)cur;
119370b324cSopenharmony_ci      if (size == 0)
120370b324cSopenharmony_ci        return S_OK;
121370b324cSopenharmony_ci    }
122370b324cSopenharmony_ci
123370b324cSopenharmony_ci   #ifdef USE_InOutTempBuffer_FILE
124370b324cSopenharmony_ci   #ifndef _WIN32
125370b324cSopenharmony_ci    _outFile.mode_for_Create = 0600;  // only owner will have the rights to access this file
126370b324cSopenharmony_ci   #endif
127370b324cSopenharmony_ci    if (_tempFile.CreateRandomInTempFolder(kTempFilePrefixString, &_outFile))
128370b324cSopenharmony_ci    {
129370b324cSopenharmony_ci      _tempFile_Created = true;
130370b324cSopenharmony_ci      break;
131370b324cSopenharmony_ci    }
132370b324cSopenharmony_ci    _useMemOnly = true;
133370b324cSopenharmony_ci    if (allocError)
134370b324cSopenharmony_ci      return GetLastError_noZero_HRESULT();
135370b324cSopenharmony_ci   #endif
136370b324cSopenharmony_ci  }
137370b324cSopenharmony_ci
138370b324cSopenharmony_ci #ifdef USE_InOutTempBuffer_FILE
139370b324cSopenharmony_ci  if (!_outFile.WriteFull(data, size))
140370b324cSopenharmony_ci    return GetLastError_noZero_HRESULT();
141370b324cSopenharmony_ci  _crc = CrcUpdate(_crc, data, size);
142370b324cSopenharmony_ci  _size += size;
143370b324cSopenharmony_ci  return S_OK;
144370b324cSopenharmony_ci #endif
145370b324cSopenharmony_ci}
146370b324cSopenharmony_ci
147370b324cSopenharmony_ci
148370b324cSopenharmony_ciHRESULT CInOutTempBuffer::WriteToStream(ISequentialOutStream *stream)
149370b324cSopenharmony_ci{
150370b324cSopenharmony_ci  UInt64 rem = _size;
151370b324cSopenharmony_ci  // if (rem == 0) return S_OK;
152370b324cSopenharmony_ci
153370b324cSopenharmony_ci  const size_t numFilled = _numFilled;
154370b324cSopenharmony_ci  _numFilled = 0;
155370b324cSopenharmony_ci
156370b324cSopenharmony_ci  for (size_t i = 0; i < numFilled; i++)
157370b324cSopenharmony_ci  {
158370b324cSopenharmony_ci    if (rem == 0)
159370b324cSopenharmony_ci      return E_FAIL;
160370b324cSopenharmony_ci    size_t cur = kBufSize;
161370b324cSopenharmony_ci    if (cur > rem)
162370b324cSopenharmony_ci      cur = (size_t)rem;
163370b324cSopenharmony_ci    RINOK(WriteStream(stream, _bufs[i], cur))
164370b324cSopenharmony_ci    rem -= cur;
165370b324cSopenharmony_ci   #ifdef USE_InOutTempBuffer_FILE
166370b324cSopenharmony_ci    // we will use _bufs[0] later for writing from temp file
167370b324cSopenharmony_ci    if (i != 0 || !_tempFile_Created)
168370b324cSopenharmony_ci   #endif
169370b324cSopenharmony_ci    {
170370b324cSopenharmony_ci      MyFree(_bufs[i]);
171370b324cSopenharmony_ci      _bufs[i] = NULL;
172370b324cSopenharmony_ci    }
173370b324cSopenharmony_ci  }
174370b324cSopenharmony_ci
175370b324cSopenharmony_ci
176370b324cSopenharmony_ci #ifdef USE_InOutTempBuffer_FILE
177370b324cSopenharmony_ci
178370b324cSopenharmony_ci  if (rem == 0)
179370b324cSopenharmony_ci    return _tempFile_Created ? E_FAIL : S_OK;
180370b324cSopenharmony_ci
181370b324cSopenharmony_ci  if (!_tempFile_Created)
182370b324cSopenharmony_ci    return E_FAIL;
183370b324cSopenharmony_ci
184370b324cSopenharmony_ci  if (!_outFile.Close())
185370b324cSopenharmony_ci    return GetLastError_noZero_HRESULT();
186370b324cSopenharmony_ci
187370b324cSopenharmony_ci  HRESULT hres;
188370b324cSopenharmony_ci  void *buf = GetBuf(0); // index
189370b324cSopenharmony_ci  if (!buf)
190370b324cSopenharmony_ci    hres = E_OUTOFMEMORY;
191370b324cSopenharmony_ci  else
192370b324cSopenharmony_ci  {
193370b324cSopenharmony_ci    NWindows::NFile::NIO::CInFile inFile;
194370b324cSopenharmony_ci    if (!inFile.Open(_tempFile.GetPath()))
195370b324cSopenharmony_ci      hres = GetLastError_noZero_HRESULT();
196370b324cSopenharmony_ci    else
197370b324cSopenharmony_ci    {
198370b324cSopenharmony_ci      UInt32 crc = CRC_INIT_VAL;
199370b324cSopenharmony_ci      for (;;)
200370b324cSopenharmony_ci      {
201370b324cSopenharmony_ci        size_t processed;
202370b324cSopenharmony_ci        if (!inFile.ReadFull(buf, kBufSize, processed))
203370b324cSopenharmony_ci        {
204370b324cSopenharmony_ci          hres = GetLastError_noZero_HRESULT();
205370b324cSopenharmony_ci          break;
206370b324cSopenharmony_ci        }
207370b324cSopenharmony_ci        if (processed == 0)
208370b324cSopenharmony_ci        {
209370b324cSopenharmony_ci          // we compare crc without CRC_GET_DIGEST
210370b324cSopenharmony_ci          hres = (_crc == crc ? S_OK : E_FAIL);
211370b324cSopenharmony_ci          break;
212370b324cSopenharmony_ci        }
213370b324cSopenharmony_ci        size_t n = processed;
214370b324cSopenharmony_ci        if (n > rem)
215370b324cSopenharmony_ci          n = (size_t)rem;
216370b324cSopenharmony_ci        hres = WriteStream(stream, buf, n);
217370b324cSopenharmony_ci        if (hres != S_OK)
218370b324cSopenharmony_ci          break;
219370b324cSopenharmony_ci        crc = CrcUpdate(crc, buf, n);
220370b324cSopenharmony_ci        rem -= n;
221370b324cSopenharmony_ci        if (n != processed)
222370b324cSopenharmony_ci        {
223370b324cSopenharmony_ci          hres = E_FAIL;
224370b324cSopenharmony_ci          break;
225370b324cSopenharmony_ci        }
226370b324cSopenharmony_ci      }
227370b324cSopenharmony_ci    }
228370b324cSopenharmony_ci  }
229370b324cSopenharmony_ci
230370b324cSopenharmony_ci  // _tempFile.DisableDeleting(); // for debug
231370b324cSopenharmony_ci  _tempFile.Remove();
232370b324cSopenharmony_ci  RINOK(hres)
233370b324cSopenharmony_ci
234370b324cSopenharmony_ci #endif
235370b324cSopenharmony_ci
236370b324cSopenharmony_ci  return rem == 0 ? S_OK : E_FAIL;
237370b324cSopenharmony_ci}
238