xref: /aosp_15_r20/external/lzma/CPP/7zip/Common/InOutTempBuffer.cpp (revision f6dc9357d832569d4d1f5d24eacdb3935a1ae8e6)
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