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