1// Compress/CopyCoder.cpp 2 3#include "StdAfx.h" 4 5#include "../../../C/Alloc.h" 6 7#include "CopyCoder.h" 8 9namespace NCompress { 10 11static const UInt32 kBufSize = 1 << 17; 12 13CCopyCoder::~CCopyCoder() 14{ 15 ::MidFree(_buf); 16} 17 18Z7_COM7F_IMF(CCopyCoder::SetFinishMode(UInt32 /* finishMode */)) 19{ 20 return S_OK; 21} 22 23Z7_COM7F_IMF(CCopyCoder::Code(ISequentialInStream *inStream, 24 ISequentialOutStream *outStream, 25 const UInt64 * /* inSize */, const UInt64 *outSize, 26 ICompressProgressInfo *progress)) 27{ 28 if (!_buf) 29 { 30 _buf = (Byte *)::MidAlloc(kBufSize); 31 if (!_buf) 32 return E_OUTOFMEMORY; 33 } 34 35 TotalSize = 0; 36 37 for (;;) 38 { 39 UInt32 size = kBufSize; 40 if (outSize) 41 { 42 const UInt64 rem = *outSize - TotalSize; 43 if (size > rem) 44 { 45 size = (UInt32)rem; 46 if (size == 0) 47 { 48 /* if we enable the following check, 49 we will make one call of Read(_buf, 0) for empty stream */ 50 // if (TotalSize != 0) 51 return S_OK; 52 } 53 } 54 } 55 56 HRESULT readRes; 57 { 58 UInt32 pos = 0; 59 do 60 { 61 const UInt32 curSize = size - pos; 62 UInt32 processed = 0; 63 readRes = inStream->Read(_buf + pos, curSize, &processed); 64 if (processed > curSize) 65 return E_FAIL; // internal code failure 66 pos += processed; 67 if (readRes != S_OK || processed == 0) 68 break; 69 } 70 while (pos < kBufSize); 71 size = pos; 72 } 73 74 if (size == 0) 75 return readRes; 76 77 if (outStream) 78 { 79 UInt32 pos = 0; 80 do 81 { 82 const UInt32 curSize = size - pos; 83 UInt32 processed = 0; 84 const HRESULT res = outStream->Write(_buf + pos, curSize, &processed); 85 if (processed > curSize) 86 return E_FAIL; // internal code failure 87 pos += processed; 88 TotalSize += processed; 89 RINOK(res) 90 if (processed == 0) 91 return E_FAIL; 92 } 93 while (pos < size); 94 } 95 else 96 TotalSize += size; 97 98 RINOK(readRes) 99 100 if (size != kBufSize) 101 return S_OK; 102 103 if (progress && (TotalSize & (((UInt32)1 << 22) - 1)) == 0) 104 { 105 RINOK(progress->SetRatioInfo(&TotalSize, &TotalSize)) 106 } 107 } 108} 109 110Z7_COM7F_IMF(CCopyCoder::SetInStream(ISequentialInStream *inStream)) 111{ 112 _inStream = inStream; 113 TotalSize = 0; 114 return S_OK; 115} 116 117Z7_COM7F_IMF(CCopyCoder::ReleaseInStream()) 118{ 119 _inStream.Release(); 120 return S_OK; 121} 122 123Z7_COM7F_IMF(CCopyCoder::Read(void *data, UInt32 size, UInt32 *processedSize)) 124{ 125 UInt32 realProcessedSize = 0; 126 HRESULT res = _inStream->Read(data, size, &realProcessedSize); 127 TotalSize += realProcessedSize; 128 if (processedSize) 129 *processedSize = realProcessedSize; 130 return res; 131} 132 133Z7_COM7F_IMF(CCopyCoder::GetInStreamProcessedSize(UInt64 *value)) 134{ 135 *value = TotalSize; 136 return S_OK; 137} 138 139HRESULT CopyStream(ISequentialInStream *inStream, ISequentialOutStream *outStream, ICompressProgressInfo *progress) 140{ 141 CMyComPtr<ICompressCoder> copyCoder = new CCopyCoder; 142 return copyCoder->Code(inStream, outStream, NULL, NULL, progress); 143} 144 145HRESULT CopyStream_ExactSize(ISequentialInStream *inStream, ISequentialOutStream *outStream, UInt64 size, ICompressProgressInfo *progress) 146{ 147 NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder; 148 CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec; 149 RINOK(copyCoder->Code(inStream, outStream, NULL, &size, progress)) 150 return copyCoderSpec->TotalSize == size ? S_OK : E_FAIL; 151} 152 153} 154