diff options
Diffstat (limited to 'CPP/7zip/Common/FileStreams.cpp')
-rwxr-xr-x | CPP/7zip/Common/FileStreams.cpp | 189 |
1 files changed, 167 insertions, 22 deletions
diff --git a/CPP/7zip/Common/FileStreams.cpp b/CPP/7zip/Common/FileStreams.cpp index eb7ad3a2..f7c01d2c 100755 --- a/CPP/7zip/Common/FileStreams.cpp +++ b/CPP/7zip/Common/FileStreams.cpp @@ -8,6 +8,11 @@ #include <errno.h> #endif +#ifdef SUPPORT_DEVICE_FILE +#include "../../../C/Alloc.h" +#include "../../Common/Defs.h" +#endif + #include "FileStreams.h" static inline HRESULT ConvertBoolToHRESULT(bool result) @@ -52,24 +57,138 @@ bool CInFileStream::OpenShared(LPCWSTR fileName, bool shareForWrite) #endif #endif +#ifdef SUPPORT_DEVICE_FILE + +static const UInt32 kClusterSize = 1 << 18; +CInFileStream::CInFileStream(): + VirtPos(0), + PhyPos(0), + Buffer(0), + BufferSize(0) +{ +} + +#endif + +CInFileStream::~CInFileStream() +{ + #ifdef SUPPORT_DEVICE_FILE + MidFree(Buffer); + #endif +} + STDMETHODIMP CInFileStream::Read(void *data, UInt32 size, UInt32 *processedSize) { #ifdef USE_WIN_FILE + #ifdef SUPPORT_DEVICE_FILE + if (processedSize != NULL) + *processedSize = 0; + if (size == 0) + return S_OK; + if (File.IsDeviceFile) + { + if (File.LengthDefined) + { + if (VirtPos >= File.Length) + return VirtPos == File.Length ? S_OK : E_FAIL; + UInt64 rem = File.Length - VirtPos; + if (size > rem) + size = (UInt32)rem; + } + for (;;) + { + const UInt32 mask = kClusterSize - 1; + UInt64 mask2 = ~(UInt64)mask; + UInt64 alignedPos = VirtPos & mask2; + if (BufferSize > 0 && BufferStartPos == alignedPos) + { + UInt32 pos = (UInt32)VirtPos & mask; + if (pos >= BufferSize) + return S_OK; + UInt32 rem = MyMin(BufferSize - pos, size); + memcpy(data, Buffer + pos, rem); + VirtPos += rem; + if (processedSize != NULL) + *processedSize += rem; + return S_OK; + } + + bool useBuffer = false; + if ((VirtPos & mask) != 0 || ((ptrdiff_t)data & mask) != 0 ) + useBuffer = true; + else + { + UInt64 end = VirtPos + size; + if ((end & mask) != 0) + { + end &= mask2; + if (end <= VirtPos) + useBuffer = true; + else + size = (UInt32)(end - VirtPos); + } + } + if (!useBuffer) + break; + if (alignedPos != PhyPos) + { + UInt64 realNewPosition; + bool result = File.Seek(alignedPos, FILE_BEGIN, realNewPosition); + if (!result) + return ConvertBoolToHRESULT(result); + PhyPos = realNewPosition; + } + + BufferStartPos = alignedPos; + UInt32 readSize = kClusterSize; + if (File.LengthDefined) + readSize = (UInt32)MyMin(File.Length - PhyPos, (UInt64)kClusterSize); + + if (Buffer == 0) + { + Buffer = (Byte *)MidAlloc(kClusterSize); + if (Buffer == 0) + return E_OUTOFMEMORY; + } + bool result = File.Read1(Buffer, readSize, BufferSize); + if (!result) + return ConvertBoolToHRESULT(result); + + if (BufferSize == 0) + return S_OK; + PhyPos += BufferSize; + } + + if (VirtPos != PhyPos) + { + UInt64 realNewPosition; + bool result = File.Seek(VirtPos, FILE_BEGIN, realNewPosition); + if (!result) + return ConvertBoolToHRESULT(result); + PhyPos = VirtPos = realNewPosition; + } + } + #endif + UInt32 realProcessedSize; bool result = File.ReadPart(data, size, realProcessedSize); - if(processedSize != NULL) + if (processedSize != NULL) *processedSize = realProcessedSize; + #ifdef SUPPORT_DEVICE_FILE + VirtPos += realProcessedSize; + PhyPos += realProcessedSize; + #endif return ConvertBoolToHRESULT(result); #else - if(processedSize != NULL) + if (processedSize != NULL) *processedSize = 0; ssize_t res = File.Read(data, (size_t)size); if (res == -1) return E_FAIL; - if(processedSize != NULL) + if (processedSize != NULL) *processedSize = (UInt32)res; return S_OK; @@ -80,10 +199,13 @@ STDMETHODIMP CInFileStream::Read(void *data, UInt32 size, UInt32 *processedSize) STDMETHODIMP CStdInFileStream::Read(void *data, UInt32 size, UInt32 *processedSize) { #ifdef _WIN32 - UInt32 realProcessedSize; - BOOL res = ::ReadFile(GetStdHandle(STD_INPUT_HANDLE), - data, size, (DWORD *)&realProcessedSize, NULL); - if(processedSize != NULL) + + DWORD realProcessedSize; + UInt32 sizeTemp = (1 << 20); + if (sizeTemp > size) + sizeTemp = size; + BOOL res = ::ReadFile(GetStdHandle(STD_INPUT_HANDLE), data, sizeTemp, &realProcessedSize, NULL); + if (processedSize != NULL) *processedSize = realProcessedSize; if (res == FALSE && GetLastError() == ERROR_BROKEN_PIPE) return S_OK; @@ -91,7 +213,7 @@ STDMETHODIMP CStdInFileStream::Read(void *data, UInt32 size, UInt32 *processedSi #else - if(processedSize != NULL) + if (processedSize != NULL) *processedSize = 0; ssize_t res; do @@ -101,7 +223,7 @@ STDMETHODIMP CStdInFileStream::Read(void *data, UInt32 size, UInt32 *processedSi while (res < 0 && (errno == EINTR)); if (res == -1) return E_FAIL; - if(processedSize != NULL) + if (processedSize != NULL) *processedSize = (UInt32)res; return S_OK; @@ -113,14 +235,37 @@ STDMETHODIMP CStdInFileStream::Read(void *data, UInt32 size, UInt32 *processedSi STDMETHODIMP CInFileStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition) { - if(seekOrigin >= 3) + if (seekOrigin >= 3) return STG_E_INVALIDFUNCTION; #ifdef USE_WIN_FILE + #ifdef SUPPORT_DEVICE_FILE + if (File.IsDeviceFile) + { + UInt64 newVirtPos = offset; + switch(seekOrigin) + { + case STREAM_SEEK_SET: break; + case STREAM_SEEK_CUR: newVirtPos += VirtPos; break; + case STREAM_SEEK_END: newVirtPos += File.Length; break; + default: return STG_E_INVALIDFUNCTION; + } + VirtPos = newVirtPos; + if (newPosition) + *newPosition = newVirtPos; + return S_OK; + } + #endif + UInt64 realNewPosition; bool result = File.Seek(offset, seekOrigin, realNewPosition); - if(newPosition != NULL) + + #ifdef SUPPORT_DEVICE_FILE + PhyPos = VirtPos = realNewPosition; + #endif + + if (newPosition != NULL) *newPosition = realNewPosition; return ConvertBoolToHRESULT(result); @@ -129,7 +274,7 @@ STDMETHODIMP CInFileStream::Seek(Int64 offset, UInt32 seekOrigin, off_t res = File.Seek(offset, seekOrigin); if (res == -1) return E_FAIL; - if(newPosition != NULL) + if (newPosition != NULL) *newPosition = (UInt64)res; return S_OK; @@ -157,18 +302,18 @@ STDMETHODIMP COutFileStream::Write(const void *data, UInt32 size, UInt32 *proces UInt32 realProcessedSize; bool result = File.WritePart(data, size, realProcessedSize); ProcessedSize += realProcessedSize; - if(processedSize != NULL) + if (processedSize != NULL) *processedSize = realProcessedSize; return ConvertBoolToHRESULT(result); #else - if(processedSize != NULL) + if (processedSize != NULL) *processedSize = 0; ssize_t res = File.Write(data, (size_t)size); if (res == -1) return E_FAIL; - if(processedSize != NULL) + if (processedSize != NULL) *processedSize = (UInt32)res; ProcessedSize += res; return S_OK; @@ -178,13 +323,13 @@ STDMETHODIMP COutFileStream::Write(const void *data, UInt32 size, UInt32 *proces STDMETHODIMP COutFileStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition) { - if(seekOrigin >= 3) + if (seekOrigin >= 3) return STG_E_INVALIDFUNCTION; #ifdef USE_WIN_FILE UInt64 realNewPosition; bool result = File.Seek(offset, seekOrigin, realNewPosition); - if(newPosition != NULL) + if (newPosition != NULL) *newPosition = realNewPosition; return ConvertBoolToHRESULT(result); @@ -193,7 +338,7 @@ STDMETHODIMP COutFileStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPo off_t res = File.Seek(offset, seekOrigin); if (res == -1) return E_FAIL; - if(newPosition != NULL) + if (newPosition != NULL) *newPosition = (UInt64)res; return S_OK; @@ -204,7 +349,7 @@ STDMETHODIMP COutFileStream::SetSize(Int64 newSize) { #ifdef USE_WIN_FILE UInt64 currentPos; - if(!File.Seek(0, FILE_CURRENT, currentPos)) + if (!File.Seek(0, FILE_CURRENT, currentPos)) return E_FAIL; bool result = File.SetLength(newSize); UInt64 currentPos2; @@ -218,7 +363,7 @@ STDMETHODIMP COutFileStream::SetSize(Int64 newSize) #ifndef _WIN32_WCE STDMETHODIMP CStdOutFileStream::Write(const void *data, UInt32 size, UInt32 *processedSize) { - if(processedSize != NULL) + if (processedSize != NULL) *processedSize = 0; #ifdef _WIN32 @@ -235,7 +380,7 @@ STDMETHODIMP CStdOutFileStream::Write(const void *data, UInt32 size, UInt32 *pro data, sizeTemp, (DWORD *)&realProcessedSize, NULL); size -= realProcessedSize; data = (const void *)((const Byte *)data + realProcessedSize); - if(processedSize != NULL) + if (processedSize != NULL) *processedSize += realProcessedSize; } return ConvertBoolToHRESULT(res != FALSE); @@ -250,7 +395,7 @@ STDMETHODIMP CStdOutFileStream::Write(const void *data, UInt32 size, UInt32 *pro while (res < 0 && (errno == EINTR)); if (res == -1) return E_FAIL; - if(processedSize != NULL) + if (processedSize != NULL) *processedSize = (UInt32)res; return S_OK; |