mirror of
https://github.com/Xevion/easy7zip.git
synced 2025-12-08 18:07:15 -06:00
23.01
This commit is contained in:
@@ -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;
|
||||
}
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user