summaryrefslogtreecommitdiffstatshomepage
path: root/3rdparty/lzma/CPP/7zip/Common/InOutTempBuffer.cpp
diff options
context:
space:
mode:
Diffstat (limited to '3rdparty/lzma/CPP/7zip/Common/InOutTempBuffer.cpp')
-rw-r--r--3rdparty/lzma/CPP/7zip/Common/InOutTempBuffer.cpp276
1 files changed, 193 insertions, 83 deletions
diff --git a/3rdparty/lzma/CPP/7zip/Common/InOutTempBuffer.cpp b/3rdparty/lzma/CPP/7zip/Common/InOutTempBuffer.cpp
index 85d6a1aa921..3f7272ef820 100644
--- a/3rdparty/lzma/CPP/7zip/Common/InOutTempBuffer.cpp
+++ b/3rdparty/lzma/CPP/7zip/Common/InOutTempBuffer.cpp
@@ -2,126 +2,236 @@
#include "StdAfx.h"
-#include "../../../C/7zCrc.h"
-
-#include "../../Common/Defs.h"
+#include "../../../C/Alloc.h"
#include "InOutTempBuffer.h"
+
#include "StreamUtils.h"
-using namespace NWindows;
-using namespace NFile;
-using namespace NDir;
+#ifdef USE_InOutTempBuffer_FILE
+
+#include "../../../C/7zCrc.h"
+
+#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);
-static const size_t kTempBufSize = (1 << 20);
+#endif
-static CFSTR kTempFilePrefixString = FTEXT("7zt");
+static const size_t kBufSize = (size_t)1 << 20;
-CInOutTempBuffer::CInOutTempBuffer(): _buf(NULL) { }
-void CInOutTempBuffer::Create()
+CInOutTempBuffer::CInOutTempBuffer():
+ _size(0),
+ _bufs(NULL),
+ _numBufs(0),
+ _numFilled(0)
{
- if (!_buf)
- _buf = new Byte[kTempBufSize];
+ #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);
}
-void CInOutTempBuffer::InitWriting()
-{
- _bufPos = 0;
- _tempFileCreated = false;
- _size = 0;
- _crc = CRC_INIT_VAL;
-}
-bool CInOutTempBuffer::WriteToFile(const void *data, UInt32 size)
+void *CInOutTempBuffer::GetBuf(size_t index)
{
- if (size == 0)
- return true;
- if (!_tempFileCreated)
+ 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)
{
- if (!_tempFile.CreateRandomInTempFolder(kTempFilePrefixString, &_outFile))
- return false;
- _tempFileCreated = true;
+ buf = MyAlloc(kBufSize);
+ if (buf)
+ _bufs[index] = buf;
}
- UInt32 processed;
- if (!_outFile.Write(data, size, processed))
- return false;
- _crc = CrcUpdate(_crc, data, processed);
- _size += processed;
- return (processed == size);
+ return buf;
}
-bool CInOutTempBuffer::Write(const void *data, UInt32 size)
+
+HRESULT CInOutTempBuffer::Write_HRESULT(const void *data, UInt32 size)
{
if (size == 0)
- return true;
- size_t cur = kTempBufSize - _bufPos;
- if (cur != 0)
+ return S_OK;
+
+ #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
}
- return WriteToFile(data, size);
+
+ #ifdef USE_InOutTempBuffer_FILE
+ if (!_outFile.WriteFull(data, size))
+ return GetLastError_noZero_HRESULT();
+ _crc = CrcUpdate(_crc, data, size);
+ _size += size;
+ return S_OK;
+ #endif
}
+
HRESULT CInOutTempBuffer::WriteToStream(ISequentialOutStream *stream)
{
- if (!_outFile.Close())
- return E_FAIL;
+ UInt64 rem = _size;
+ // if (rem == 0) return S_OK;
- UInt64 size = 0;
- UInt32 crc = CRC_INIT_VAL;
+ const size_t numFilled = _numFilled;
+ _numFilled = 0;
- 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;
-}
-/*
-STDMETHODIMP CSequentialOutTempBufferImp::Write(const void *data, UInt32 size, UInt32 *processed)
-{
- if (!_buf->Write(data, size))
- {
- if (processed)
- *processed = 0;
+
+ #ifdef USE_InOutTempBuffer_FILE
+
+ if (rem == 0)
+ return _tempFile_Created ? E_FAIL : S_OK;
+
+ 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;
}
-*/