1 // Compress/CopyCoder.cpp 2 3 #include "StdAfx.h" 4 5 #include "../../../C/Alloc.h" 6 7 #include "CopyCoder.h" 8 9 namespace NCompress { 10 11 static const UInt32 kBufSize = 1 << 17; 12 13 CCopyCoder::~CCopyCoder() 14 { 15 ::MidFree(_buf); 16 } 17 18 STDMETHODIMP CCopyCoder::Code(ISequentialInStream *inStream, 19 ISequentialOutStream *outStream, 20 const UInt64 * /* inSize */, const UInt64 *outSize, 21 ICompressProgressInfo *progress) 22 { 23 if (!_buf) 24 { 25 _buf = (Byte *)::MidAlloc(kBufSize); 26 if (!_buf) 27 return E_OUTOFMEMORY; 28 } 29 30 TotalSize = 0; 31 32 for (;;) 33 { 34 UInt32 size = kBufSize; 35 if (outSize && size > *outSize - TotalSize) 36 size = (UInt32)(*outSize - TotalSize); 37 if (size == 0) 38 return S_OK; 39 40 HRESULT readRes = inStream->Read(_buf, size, &size); 41 42 if (size == 0) 43 return readRes; 44 45 if (outStream) 46 { 47 UInt32 pos = 0; 48 do 49 { 50 UInt32 curSize = size - pos; 51 HRESULT res = outStream->Write(_buf + pos, curSize, &curSize); 52 pos += curSize; 53 TotalSize += curSize; 54 RINOK(res); 55 if (curSize == 0) 56 return E_FAIL; 57 } 58 while (pos < size); 59 } 60 else 61 TotalSize += size; 62 63 RINOK(readRes); 64 65 if (progress) 66 { 67 RINOK(progress->SetRatioInfo(&TotalSize, &TotalSize)); 68 } 69 } 70 } 71 72 STDMETHODIMP CCopyCoder::SetInStream(ISequentialInStream *inStream) 73 { 74 _inStream = inStream; 75 TotalSize = 0; 76 return S_OK; 77 } 78 79 STDMETHODIMP CCopyCoder::ReleaseInStream() 80 { 81 _inStream.Release(); 82 return S_OK; 83 } 84 85 STDMETHODIMP CCopyCoder::Read(void *data, UInt32 size, UInt32 *processedSize) 86 { 87 UInt32 realProcessedSize = 0; 88 HRESULT res = _inStream->Read(data, size, &realProcessedSize); 89 TotalSize += realProcessedSize; 90 if (processedSize) 91 *processedSize = realProcessedSize; 92 return res; 93 } 94 95 STDMETHODIMP CCopyCoder::GetInStreamProcessedSize(UInt64 *value) 96 { 97 *value = TotalSize; 98 return S_OK; 99 } 100 101 HRESULT CopyStream(ISequentialInStream *inStream, ISequentialOutStream *outStream, ICompressProgressInfo *progress) 102 { 103 CMyComPtr<ICompressCoder> copyCoder = new CCopyCoder; 104 return copyCoder->Code(inStream, outStream, NULL, NULL, progress); 105 } 106 107 HRESULT CopyStream_ExactSize(ISequentialInStream *inStream, ISequentialOutStream *outStream, UInt64 size, ICompressProgressInfo *progress) 108 { 109 NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder; 110 CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec; 111 RINOK(copyCoder->Code(inStream, outStream, NULL, &size, progress)); 112 return copyCoderSpec->TotalSize == size ? S_OK : E_FAIL; 113 } 114 115 } 116