// Compress/CopyCoder.cpp #include "StdAfx.h" #include "../../../C/Alloc.h" #include "CopyCoder.h" namespace NCompress { static const UInt32 kBufSize = 1 << 17; CCopyCoder::~CCopyCoder() { ::MidFree(_buf); } STDMETHODIMP CCopyCoder::SetFinishMode(UInt32 /* finishMode */) { return S_OK; } STDMETHODIMP CCopyCoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, const UInt64 * /* inSize */, const UInt64 *outSize, ICompressProgressInfo *progress) { if (!_buf) { _buf = (Byte *)::MidAlloc(kBufSize); if (!_buf) return E_OUTOFMEMORY; } TotalSize = 0; for (;;) { UInt32 size = kBufSize; if (outSize && size > *outSize - TotalSize) size = (UInt32)(*outSize - TotalSize); if (size == 0) return S_OK; HRESULT readRes = inStream->Read(_buf, size, &size); if (size == 0) return readRes; if (outStream) { UInt32 pos = 0; do { UInt32 curSize = size - pos; HRESULT res = outStream->Write(_buf + pos, curSize, &curSize); pos += curSize; TotalSize += curSize; RINOK(res); if (curSize == 0) return E_FAIL; } while (pos < size); } else TotalSize += size; RINOK(readRes); if (progress) { RINOK(progress->SetRatioInfo(&TotalSize, &TotalSize)); } } } STDMETHODIMP CCopyCoder::SetInStream(ISequentialInStream *inStream) { _inStream = inStream; TotalSize = 0; return S_OK; } STDMETHODIMP CCopyCoder::ReleaseInStream() { _inStream.Release(); return S_OK; } STDMETHODIMP CCopyCoder::Read(void *data, UInt32 size, UInt32 *processedSize) { UInt32 realProcessedSize = 0; HRESULT res = _inStream->Read(data, size, &realProcessedSize); TotalSize += realProcessedSize; if (processedSize) *processedSize = realProcessedSize; return res; } STDMETHODIMP CCopyCoder::GetInStreamProcessedSize(UInt64 *value) { *value = TotalSize; return S_OK; } HRESULT CopyStream(ISequentialInStream *inStream, ISequentialOutStream *outStream, ICompressProgressInfo *progress) { CMyComPtr copyCoder = new CCopyCoder; return copyCoder->Code(inStream, outStream, NULL, NULL, progress); } HRESULT CopyStream_ExactSize(ISequentialInStream *inStream, ISequentialOutStream *outStream, UInt64 size, ICompressProgressInfo *progress) { NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder; CMyComPtr copyCoder = copyCoderSpec; RINOK(copyCoder->Code(inStream, outStream, NULL, &size, progress)); return copyCoderSpec->TotalSize == size ? S_OK : E_FAIL; } }