1*f6dc9357SAndroid Build Coastguard Worker // InOutTempBuffer.cpp
2*f6dc9357SAndroid Build Coastguard Worker
3*f6dc9357SAndroid Build Coastguard Worker #include "StdAfx.h"
4*f6dc9357SAndroid Build Coastguard Worker
5*f6dc9357SAndroid Build Coastguard Worker #include "../../../C/Alloc.h"
6*f6dc9357SAndroid Build Coastguard Worker
7*f6dc9357SAndroid Build Coastguard Worker #include "InOutTempBuffer.h"
8*f6dc9357SAndroid Build Coastguard Worker
9*f6dc9357SAndroid Build Coastguard Worker #include "StreamUtils.h"
10*f6dc9357SAndroid Build Coastguard Worker
11*f6dc9357SAndroid Build Coastguard Worker #ifdef USE_InOutTempBuffer_FILE
12*f6dc9357SAndroid Build Coastguard Worker
13*f6dc9357SAndroid Build Coastguard Worker #include "../../../C/7zCrc.h"
14*f6dc9357SAndroid Build Coastguard Worker
15*f6dc9357SAndroid Build Coastguard Worker #define kTempFilePrefixString FTEXT("7zt")
16*f6dc9357SAndroid Build Coastguard Worker /*
17*f6dc9357SAndroid Build Coastguard Worker Total buffer size limit, if we use temp file scheme:
18*f6dc9357SAndroid Build Coastguard Worker 32-bit: 16 MiB = 1 MiB * 16 buffers
19*f6dc9357SAndroid Build Coastguard Worker 64-bit: 4 GiB = 1 MiB * 4096 buffers
20*f6dc9357SAndroid Build Coastguard Worker */
21*f6dc9357SAndroid Build Coastguard Worker static const size_t kNumBufsMax = (size_t)1 << (sizeof(size_t) * 2 - 4);
22*f6dc9357SAndroid Build Coastguard Worker
23*f6dc9357SAndroid Build Coastguard Worker #endif
24*f6dc9357SAndroid Build Coastguard Worker
25*f6dc9357SAndroid Build Coastguard Worker static const size_t kBufSize = (size_t)1 << 20;
26*f6dc9357SAndroid Build Coastguard Worker
27*f6dc9357SAndroid Build Coastguard Worker
CInOutTempBuffer()28*f6dc9357SAndroid Build Coastguard Worker CInOutTempBuffer::CInOutTempBuffer():
29*f6dc9357SAndroid Build Coastguard Worker _size(0),
30*f6dc9357SAndroid Build Coastguard Worker _bufs(NULL),
31*f6dc9357SAndroid Build Coastguard Worker _numBufs(0),
32*f6dc9357SAndroid Build Coastguard Worker _numFilled(0)
33*f6dc9357SAndroid Build Coastguard Worker {
34*f6dc9357SAndroid Build Coastguard Worker #ifdef USE_InOutTempBuffer_FILE
35*f6dc9357SAndroid Build Coastguard Worker _tempFile_Created = false;
36*f6dc9357SAndroid Build Coastguard Worker _useMemOnly = false;
37*f6dc9357SAndroid Build Coastguard Worker _crc = CRC_INIT_VAL;
38*f6dc9357SAndroid Build Coastguard Worker #endif
39*f6dc9357SAndroid Build Coastguard Worker }
40*f6dc9357SAndroid Build Coastguard Worker
~CInOutTempBuffer()41*f6dc9357SAndroid Build Coastguard Worker CInOutTempBuffer::~CInOutTempBuffer()
42*f6dc9357SAndroid Build Coastguard Worker {
43*f6dc9357SAndroid Build Coastguard Worker for (size_t i = 0; i < _numBufs; i++)
44*f6dc9357SAndroid Build Coastguard Worker MyFree(_bufs[i]);
45*f6dc9357SAndroid Build Coastguard Worker MyFree(_bufs);
46*f6dc9357SAndroid Build Coastguard Worker }
47*f6dc9357SAndroid Build Coastguard Worker
48*f6dc9357SAndroid Build Coastguard Worker
GetBuf(size_t index)49*f6dc9357SAndroid Build Coastguard Worker void *CInOutTempBuffer::GetBuf(size_t index)
50*f6dc9357SAndroid Build Coastguard Worker {
51*f6dc9357SAndroid Build Coastguard Worker if (index >= _numBufs)
52*f6dc9357SAndroid Build Coastguard Worker {
53*f6dc9357SAndroid Build Coastguard Worker const size_t num = (_numBufs == 0 ? 16 : _numBufs * 2);
54*f6dc9357SAndroid Build Coastguard Worker void **p = (void **)MyRealloc(_bufs, num * sizeof(void *));
55*f6dc9357SAndroid Build Coastguard Worker if (!p)
56*f6dc9357SAndroid Build Coastguard Worker return NULL;
57*f6dc9357SAndroid Build Coastguard Worker _bufs = p;
58*f6dc9357SAndroid Build Coastguard Worker memset(p + _numBufs, 0, (num - _numBufs) * sizeof(void *));
59*f6dc9357SAndroid Build Coastguard Worker _numBufs = num;
60*f6dc9357SAndroid Build Coastguard Worker }
61*f6dc9357SAndroid Build Coastguard Worker
62*f6dc9357SAndroid Build Coastguard Worker void *buf = _bufs[index];
63*f6dc9357SAndroid Build Coastguard Worker if (!buf)
64*f6dc9357SAndroid Build Coastguard Worker {
65*f6dc9357SAndroid Build Coastguard Worker buf = MyAlloc(kBufSize);
66*f6dc9357SAndroid Build Coastguard Worker if (buf)
67*f6dc9357SAndroid Build Coastguard Worker _bufs[index] = buf;
68*f6dc9357SAndroid Build Coastguard Worker }
69*f6dc9357SAndroid Build Coastguard Worker return buf;
70*f6dc9357SAndroid Build Coastguard Worker }
71*f6dc9357SAndroid Build Coastguard Worker
72*f6dc9357SAndroid Build Coastguard Worker
Write_HRESULT(const void * data,UInt32 size)73*f6dc9357SAndroid Build Coastguard Worker HRESULT CInOutTempBuffer::Write_HRESULT(const void *data, UInt32 size)
74*f6dc9357SAndroid Build Coastguard Worker {
75*f6dc9357SAndroid Build Coastguard Worker if (size == 0)
76*f6dc9357SAndroid Build Coastguard Worker return S_OK;
77*f6dc9357SAndroid Build Coastguard Worker
78*f6dc9357SAndroid Build Coastguard Worker #ifdef USE_InOutTempBuffer_FILE
79*f6dc9357SAndroid Build Coastguard Worker if (!_tempFile_Created)
80*f6dc9357SAndroid Build Coastguard Worker #endif
81*f6dc9357SAndroid Build Coastguard Worker for (;;) // loop for additional attemp to allocate memory after file creation error
82*f6dc9357SAndroid Build Coastguard Worker {
83*f6dc9357SAndroid Build Coastguard Worker #ifdef USE_InOutTempBuffer_FILE
84*f6dc9357SAndroid Build Coastguard Worker bool allocError = false;
85*f6dc9357SAndroid Build Coastguard Worker #endif
86*f6dc9357SAndroid Build Coastguard Worker
87*f6dc9357SAndroid Build Coastguard Worker for (;;) // loop for writing to buffers
88*f6dc9357SAndroid Build Coastguard Worker {
89*f6dc9357SAndroid Build Coastguard Worker const size_t index = (size_t)(_size / kBufSize);
90*f6dc9357SAndroid Build Coastguard Worker
91*f6dc9357SAndroid Build Coastguard Worker #ifdef USE_InOutTempBuffer_FILE
92*f6dc9357SAndroid Build Coastguard Worker if (index >= kNumBufsMax && !_useMemOnly)
93*f6dc9357SAndroid Build Coastguard Worker break;
94*f6dc9357SAndroid Build Coastguard Worker #endif
95*f6dc9357SAndroid Build Coastguard Worker
96*f6dc9357SAndroid Build Coastguard Worker void *buf = GetBuf(index);
97*f6dc9357SAndroid Build Coastguard Worker if (!buf)
98*f6dc9357SAndroid Build Coastguard Worker {
99*f6dc9357SAndroid Build Coastguard Worker #ifdef USE_InOutTempBuffer_FILE
100*f6dc9357SAndroid Build Coastguard Worker if (!_useMemOnly)
101*f6dc9357SAndroid Build Coastguard Worker {
102*f6dc9357SAndroid Build Coastguard Worker allocError = true;
103*f6dc9357SAndroid Build Coastguard Worker break;
104*f6dc9357SAndroid Build Coastguard Worker }
105*f6dc9357SAndroid Build Coastguard Worker #endif
106*f6dc9357SAndroid Build Coastguard Worker return E_OUTOFMEMORY;
107*f6dc9357SAndroid Build Coastguard Worker }
108*f6dc9357SAndroid Build Coastguard Worker
109*f6dc9357SAndroid Build Coastguard Worker const size_t offset = (size_t)(_size) & (kBufSize - 1);
110*f6dc9357SAndroid Build Coastguard Worker size_t cur = kBufSize - offset;
111*f6dc9357SAndroid Build Coastguard Worker if (cur > size)
112*f6dc9357SAndroid Build Coastguard Worker cur = size;
113*f6dc9357SAndroid Build Coastguard Worker memcpy((Byte *)buf + offset, data, cur);
114*f6dc9357SAndroid Build Coastguard Worker _size += cur;
115*f6dc9357SAndroid Build Coastguard Worker if (index >= _numFilled)
116*f6dc9357SAndroid Build Coastguard Worker _numFilled = index + 1;
117*f6dc9357SAndroid Build Coastguard Worker data = (const void *)((const Byte *)data + cur);
118*f6dc9357SAndroid Build Coastguard Worker size -= (UInt32)cur;
119*f6dc9357SAndroid Build Coastguard Worker if (size == 0)
120*f6dc9357SAndroid Build Coastguard Worker return S_OK;
121*f6dc9357SAndroid Build Coastguard Worker }
122*f6dc9357SAndroid Build Coastguard Worker
123*f6dc9357SAndroid Build Coastguard Worker #ifdef USE_InOutTempBuffer_FILE
124*f6dc9357SAndroid Build Coastguard Worker #ifndef _WIN32
125*f6dc9357SAndroid Build Coastguard Worker _outFile.mode_for_Create = 0600; // only owner will have the rights to access this file
126*f6dc9357SAndroid Build Coastguard Worker #endif
127*f6dc9357SAndroid Build Coastguard Worker if (_tempFile.CreateRandomInTempFolder(kTempFilePrefixString, &_outFile))
128*f6dc9357SAndroid Build Coastguard Worker {
129*f6dc9357SAndroid Build Coastguard Worker _tempFile_Created = true;
130*f6dc9357SAndroid Build Coastguard Worker break;
131*f6dc9357SAndroid Build Coastguard Worker }
132*f6dc9357SAndroid Build Coastguard Worker _useMemOnly = true;
133*f6dc9357SAndroid Build Coastguard Worker if (allocError)
134*f6dc9357SAndroid Build Coastguard Worker return GetLastError_noZero_HRESULT();
135*f6dc9357SAndroid Build Coastguard Worker #endif
136*f6dc9357SAndroid Build Coastguard Worker }
137*f6dc9357SAndroid Build Coastguard Worker
138*f6dc9357SAndroid Build Coastguard Worker #ifdef USE_InOutTempBuffer_FILE
139*f6dc9357SAndroid Build Coastguard Worker if (!_outFile.WriteFull(data, size))
140*f6dc9357SAndroid Build Coastguard Worker return GetLastError_noZero_HRESULT();
141*f6dc9357SAndroid Build Coastguard Worker _crc = CrcUpdate(_crc, data, size);
142*f6dc9357SAndroid Build Coastguard Worker _size += size;
143*f6dc9357SAndroid Build Coastguard Worker return S_OK;
144*f6dc9357SAndroid Build Coastguard Worker #endif
145*f6dc9357SAndroid Build Coastguard Worker }
146*f6dc9357SAndroid Build Coastguard Worker
147*f6dc9357SAndroid Build Coastguard Worker
WriteToStream(ISequentialOutStream * stream)148*f6dc9357SAndroid Build Coastguard Worker HRESULT CInOutTempBuffer::WriteToStream(ISequentialOutStream *stream)
149*f6dc9357SAndroid Build Coastguard Worker {
150*f6dc9357SAndroid Build Coastguard Worker UInt64 rem = _size;
151*f6dc9357SAndroid Build Coastguard Worker // if (rem == 0) return S_OK;
152*f6dc9357SAndroid Build Coastguard Worker
153*f6dc9357SAndroid Build Coastguard Worker const size_t numFilled = _numFilled;
154*f6dc9357SAndroid Build Coastguard Worker _numFilled = 0;
155*f6dc9357SAndroid Build Coastguard Worker
156*f6dc9357SAndroid Build Coastguard Worker for (size_t i = 0; i < numFilled; i++)
157*f6dc9357SAndroid Build Coastguard Worker {
158*f6dc9357SAndroid Build Coastguard Worker if (rem == 0)
159*f6dc9357SAndroid Build Coastguard Worker return E_FAIL;
160*f6dc9357SAndroid Build Coastguard Worker size_t cur = kBufSize;
161*f6dc9357SAndroid Build Coastguard Worker if (cur > rem)
162*f6dc9357SAndroid Build Coastguard Worker cur = (size_t)rem;
163*f6dc9357SAndroid Build Coastguard Worker RINOK(WriteStream(stream, _bufs[i], cur))
164*f6dc9357SAndroid Build Coastguard Worker rem -= cur;
165*f6dc9357SAndroid Build Coastguard Worker #ifdef USE_InOutTempBuffer_FILE
166*f6dc9357SAndroid Build Coastguard Worker // we will use _bufs[0] later for writing from temp file
167*f6dc9357SAndroid Build Coastguard Worker if (i != 0 || !_tempFile_Created)
168*f6dc9357SAndroid Build Coastguard Worker #endif
169*f6dc9357SAndroid Build Coastguard Worker {
170*f6dc9357SAndroid Build Coastguard Worker MyFree(_bufs[i]);
171*f6dc9357SAndroid Build Coastguard Worker _bufs[i] = NULL;
172*f6dc9357SAndroid Build Coastguard Worker }
173*f6dc9357SAndroid Build Coastguard Worker }
174*f6dc9357SAndroid Build Coastguard Worker
175*f6dc9357SAndroid Build Coastguard Worker
176*f6dc9357SAndroid Build Coastguard Worker #ifdef USE_InOutTempBuffer_FILE
177*f6dc9357SAndroid Build Coastguard Worker
178*f6dc9357SAndroid Build Coastguard Worker if (rem == 0)
179*f6dc9357SAndroid Build Coastguard Worker return _tempFile_Created ? E_FAIL : S_OK;
180*f6dc9357SAndroid Build Coastguard Worker
181*f6dc9357SAndroid Build Coastguard Worker if (!_tempFile_Created)
182*f6dc9357SAndroid Build Coastguard Worker return E_FAIL;
183*f6dc9357SAndroid Build Coastguard Worker
184*f6dc9357SAndroid Build Coastguard Worker if (!_outFile.Close())
185*f6dc9357SAndroid Build Coastguard Worker return GetLastError_noZero_HRESULT();
186*f6dc9357SAndroid Build Coastguard Worker
187*f6dc9357SAndroid Build Coastguard Worker HRESULT hres;
188*f6dc9357SAndroid Build Coastguard Worker void *buf = GetBuf(0); // index
189*f6dc9357SAndroid Build Coastguard Worker if (!buf)
190*f6dc9357SAndroid Build Coastguard Worker hres = E_OUTOFMEMORY;
191*f6dc9357SAndroid Build Coastguard Worker else
192*f6dc9357SAndroid Build Coastguard Worker {
193*f6dc9357SAndroid Build Coastguard Worker NWindows::NFile::NIO::CInFile inFile;
194*f6dc9357SAndroid Build Coastguard Worker if (!inFile.Open(_tempFile.GetPath()))
195*f6dc9357SAndroid Build Coastguard Worker hres = GetLastError_noZero_HRESULT();
196*f6dc9357SAndroid Build Coastguard Worker else
197*f6dc9357SAndroid Build Coastguard Worker {
198*f6dc9357SAndroid Build Coastguard Worker UInt32 crc = CRC_INIT_VAL;
199*f6dc9357SAndroid Build Coastguard Worker for (;;)
200*f6dc9357SAndroid Build Coastguard Worker {
201*f6dc9357SAndroid Build Coastguard Worker size_t processed;
202*f6dc9357SAndroid Build Coastguard Worker if (!inFile.ReadFull(buf, kBufSize, processed))
203*f6dc9357SAndroid Build Coastguard Worker {
204*f6dc9357SAndroid Build Coastguard Worker hres = GetLastError_noZero_HRESULT();
205*f6dc9357SAndroid Build Coastguard Worker break;
206*f6dc9357SAndroid Build Coastguard Worker }
207*f6dc9357SAndroid Build Coastguard Worker if (processed == 0)
208*f6dc9357SAndroid Build Coastguard Worker {
209*f6dc9357SAndroid Build Coastguard Worker // we compare crc without CRC_GET_DIGEST
210*f6dc9357SAndroid Build Coastguard Worker hres = (_crc == crc ? S_OK : E_FAIL);
211*f6dc9357SAndroid Build Coastguard Worker break;
212*f6dc9357SAndroid Build Coastguard Worker }
213*f6dc9357SAndroid Build Coastguard Worker size_t n = processed;
214*f6dc9357SAndroid Build Coastguard Worker if (n > rem)
215*f6dc9357SAndroid Build Coastguard Worker n = (size_t)rem;
216*f6dc9357SAndroid Build Coastguard Worker hres = WriteStream(stream, buf, n);
217*f6dc9357SAndroid Build Coastguard Worker if (hres != S_OK)
218*f6dc9357SAndroid Build Coastguard Worker break;
219*f6dc9357SAndroid Build Coastguard Worker crc = CrcUpdate(crc, buf, n);
220*f6dc9357SAndroid Build Coastguard Worker rem -= n;
221*f6dc9357SAndroid Build Coastguard Worker if (n != processed)
222*f6dc9357SAndroid Build Coastguard Worker {
223*f6dc9357SAndroid Build Coastguard Worker hres = E_FAIL;
224*f6dc9357SAndroid Build Coastguard Worker break;
225*f6dc9357SAndroid Build Coastguard Worker }
226*f6dc9357SAndroid Build Coastguard Worker }
227*f6dc9357SAndroid Build Coastguard Worker }
228*f6dc9357SAndroid Build Coastguard Worker }
229*f6dc9357SAndroid Build Coastguard Worker
230*f6dc9357SAndroid Build Coastguard Worker // _tempFile.DisableDeleting(); // for debug
231*f6dc9357SAndroid Build Coastguard Worker _tempFile.Remove();
232*f6dc9357SAndroid Build Coastguard Worker RINOK(hres)
233*f6dc9357SAndroid Build Coastguard Worker
234*f6dc9357SAndroid Build Coastguard Worker #endif
235*f6dc9357SAndroid Build Coastguard Worker
236*f6dc9357SAndroid Build Coastguard Worker return rem == 0 ? S_OK : E_FAIL;
237*f6dc9357SAndroid Build Coastguard Worker }
238