This commit is contained in:
Igor Pavlov
2023-12-22 17:17:05 +00:00
committed by Kornel
parent ec44a8a070
commit a36c48cece
954 changed files with 42199 additions and 25482 deletions

View File

@@ -2,170 +2,236 @@
#include "StdAfx.h"
#include "../../../C/Alloc.h"
#include "InOutTempBuffer.h"
#include "StreamUtils.h"
#ifdef USE_InOutTempBuffer_FILE
#include "../../../C/7zCrc.h"
using namespace NWindows;
using namespace NFile;
using namespace NDir;
static const size_t kTempBufSize = (1 << 20);
#define kTempFilePrefixString FTEXT("7zt")
/*
Total buffer size limit, if we use temp file scheme:
32-bit: 16 MiB = 1 MiB * 16 buffers
64-bit: 4 GiB = 1 MiB * 4096 buffers
*/
static const size_t kNumBufsMax = (size_t)1 << (sizeof(size_t) * 2 - 4);
#endif
static const size_t kBufSize = (size_t)1 << 20;
CInOutTempBuffer::CInOutTempBuffer():
_size(0),
_bufs(NULL),
_numBufs(0),
_numFilled(0)
{
#ifdef USE_InOutTempBuffer_FILE
_tempFile_Created = false;
_useMemOnly = false;
_crc = CRC_INIT_VAL;
#endif
}
CInOutTempBuffer::~CInOutTempBuffer()
{
delete []_buf;
for (size_t i = 0; i < _numBufs; i++)
MyFree(_bufs[i]);
MyFree(_bufs);
}
#endif
CInOutTempBuffer::CInOutTempBuffer()
#ifdef USE_InOutTempBuffer_FILE
: _buf(NULL)
#endif
{ }
void CInOutTempBuffer::Create()
void *CInOutTempBuffer::GetBuf(size_t index)
{
#ifdef USE_InOutTempBuffer_FILE
if (!_buf)
_buf = new Byte[kTempBufSize];
#endif
if (index >= _numBufs)
{
const size_t num = (_numBufs == 0 ? 16 : _numBufs * 2);
void **p = (void **)MyRealloc(_bufs, num * sizeof(void *));
if (!p)
return NULL;
_bufs = p;
memset(p + _numBufs, 0, (num - _numBufs) * sizeof(void *));
_numBufs = num;
}
void *buf = _bufs[index];
if (!buf)
{
buf = MyAlloc(kBufSize);
if (buf)
_bufs[index] = buf;
}
return buf;
}
void CInOutTempBuffer::InitWriting()
{
#ifdef USE_InOutTempBuffer_FILE
_bufPos = 0;
_crc = CRC_INIT_VAL;
_tempFileCreated = false;
#endif
_size = 0;
}
#ifdef USE_InOutTempBuffer_FILE
static inline HRESULT Get_HRESULT_LastError()
{
#ifdef _WIN32
DWORD lastError = ::GetLastError();
if (lastError != 0)
return HRESULT_FROM_WIN32(lastError);
#endif
return E_FAIL;
}
#endif
HRESULT CInOutTempBuffer::Write_HRESULT(const void *data, UInt32 size)
{
#ifdef USE_InOutTempBuffer_FILE
if (size == 0)
return S_OK;
size_t cur = kTempBufSize - _bufPos;
if (cur != 0)
#ifdef USE_InOutTempBuffer_FILE
if (!_tempFile_Created)
#endif
for (;;) // loop for additional attemp to allocate memory after file creation error
{
if (cur > size)
cur = size;
memcpy(_buf + _bufPos, data, cur);
_crc = CrcUpdate(_crc, data, cur);
_bufPos += cur;
_size += cur;
size -= (UInt32)cur;
data = ((const Byte *)data) + cur;
#ifdef USE_InOutTempBuffer_FILE
bool allocError = false;
#endif
for (;;) // loop for writing to buffers
{
const size_t index = (size_t)(_size / kBufSize);
#ifdef USE_InOutTempBuffer_FILE
if (index >= kNumBufsMax && !_useMemOnly)
break;
#endif
void *buf = GetBuf(index);
if (!buf)
{
#ifdef USE_InOutTempBuffer_FILE
if (!_useMemOnly)
{
allocError = true;
break;
}
#endif
return E_OUTOFMEMORY;
}
const size_t offset = (size_t)(_size) & (kBufSize - 1);
size_t cur = kBufSize - offset;
if (cur > size)
cur = size;
memcpy((Byte *)buf + offset, data, cur);
_size += cur;
if (index >= _numFilled)
_numFilled = index + 1;
data = (const void *)((const Byte *)data + cur);
size -= (UInt32)cur;
if (size == 0)
return S_OK;
}
#ifdef USE_InOutTempBuffer_FILE
#ifndef _WIN32
_outFile.mode_for_Create = 0600; // only owner will have the rights to access this file
#endif
if (_tempFile.CreateRandomInTempFolder(kTempFilePrefixString, &_outFile))
{
_tempFile_Created = true;
break;
}
_useMemOnly = true;
if (allocError)
return GetLastError_noZero_HRESULT();
#endif
}
if (size == 0)
return S_OK;
if (!_tempFileCreated)
{
if (!_tempFile.CreateRandomInTempFolder(kTempFilePrefixString, &_outFile))
return Get_HRESULT_LastError();
_tempFileCreated = true;
}
UInt32 processed;
if (!_outFile.Write(data, size, processed))
return Get_HRESULT_LastError();
_crc = CrcUpdate(_crc, data, processed);
_size += processed;
return (processed == size) ? S_OK : E_FAIL;
#else
const size_t newSize = _size + size;
if (newSize < _size)
return E_OUTOFMEMORY;
if (!_dynBuffer.EnsureCapacity(newSize))
return E_OUTOFMEMORY;
memcpy(((Byte *)_dynBuffer) + _size, data, size);
_size = newSize;
#ifdef USE_InOutTempBuffer_FILE
if (!_outFile.WriteFull(data, size))
return GetLastError_noZero_HRESULT();
_crc = CrcUpdate(_crc, data, size);
_size += size;
return S_OK;
#endif
#endif
}
HRESULT CInOutTempBuffer::WriteToStream(ISequentialOutStream *stream)
{
#ifdef USE_InOutTempBuffer_FILE
UInt64 rem = _size;
// if (rem == 0) return S_OK;
if (!_outFile.Close())
return E_FAIL;
const size_t numFilled = _numFilled;
_numFilled = 0;
UInt64 size = 0;
UInt32 crc = CRC_INIT_VAL;
if (_bufPos != 0)
for (size_t i = 0; i < numFilled; i++)
{
RINOK(WriteStream(stream, _buf, _bufPos));
crc = CrcUpdate(crc, _buf, _bufPos);
size += _bufPos;
}
if (_tempFileCreated)
{
NIO::CInFile inFile;
if (!inFile.Open(_tempFile.GetPath()))
if (rem == 0)
return E_FAIL;
while (size < _size)
size_t cur = kBufSize;
if (cur > rem)
cur = (size_t)rem;
RINOK(WriteStream(stream, _bufs[i], cur))
rem -= cur;
#ifdef USE_InOutTempBuffer_FILE
// we will use _bufs[0] later for writing from temp file
if (i != 0 || !_tempFile_Created)
#endif
{
UInt32 processed;
if (!inFile.ReadPart(_buf, kTempBufSize, processed))
return E_FAIL;
if (processed == 0)
break;
RINOK(WriteStream(stream, _buf, processed));
crc = CrcUpdate(crc, _buf, processed);
size += processed;
MyFree(_bufs[i]);
_bufs[i] = NULL;
}
}
return (_crc == crc && size == _size) ? S_OK : E_FAIL;
#else
return WriteStream(stream, (const Byte *)_dynBuffer, _size);
#ifdef USE_InOutTempBuffer_FILE
#endif
}
if (rem == 0)
return _tempFile_Created ? E_FAIL : S_OK;
/*
STDMETHODIMP CSequentialOutTempBufferImp::Write(const void *data, UInt32 size, UInt32 *processed)
{
if (!_buf->Write(data, size))
{
if (processed)
*processed = 0;
if (!_tempFile_Created)
return E_FAIL;
if (!_outFile.Close())
return GetLastError_noZero_HRESULT();
HRESULT hres;
void *buf = GetBuf(0); // index
if (!buf)
hres = E_OUTOFMEMORY;
else
{
NWindows::NFile::NIO::CInFile inFile;
if (!inFile.Open(_tempFile.GetPath()))
hres = GetLastError_noZero_HRESULT();
else
{
UInt32 crc = CRC_INIT_VAL;
for (;;)
{
size_t processed;
if (!inFile.ReadFull(buf, kBufSize, processed))
{
hres = GetLastError_noZero_HRESULT();
break;
}
if (processed == 0)
{
// we compare crc without CRC_GET_DIGEST
hres = (_crc == crc ? S_OK : E_FAIL);
break;
}
size_t n = processed;
if (n > rem)
n = (size_t)rem;
hres = WriteStream(stream, buf, n);
if (hres != S_OK)
break;
crc = CrcUpdate(crc, buf, n);
rem -= n;
if (n != processed)
{
hres = E_FAIL;
break;
}
}
}
}
if (processed)
*processed = size;
return S_OK;
// _tempFile.DisableDeleting(); // for debug
_tempFile.Remove();
RINOK(hres)
#endif
return rem == 0 ? S_OK : E_FAIL;
}
*/