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 
~CCopyCoder()13 CCopyCoder::~CCopyCoder()
14 {
15   ::MidFree(_buf);
16 }
17 
SetFinishMode(UInt32)18 STDMETHODIMP CCopyCoder::SetFinishMode(UInt32 /* finishMode */)
19 {
20   return S_OK;
21 }
22 
Code(ISequentialInStream * inStream,ISequentialOutStream * outStream,const UInt64 *,const UInt64 * outSize,ICompressProgressInfo * progress)23 STDMETHODIMP 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 && size > *outSize - TotalSize)
41       size = (UInt32)(*outSize - TotalSize);
42     if (size == 0)
43       return S_OK;
44 
45     HRESULT readRes = inStream->Read(_buf, size, &size);
46 
47     if (size == 0)
48       return readRes;
49 
50     if (outStream)
51     {
52       UInt32 pos = 0;
53       do
54       {
55         UInt32 curSize = size - pos;
56         HRESULT res = outStream->Write(_buf + pos, curSize, &curSize);
57         pos += curSize;
58         TotalSize += curSize;
59         RINOK(res);
60         if (curSize == 0)
61           return E_FAIL;
62       }
63       while (pos < size);
64     }
65     else
66       TotalSize += size;
67 
68     RINOK(readRes);
69 
70     if (progress)
71     {
72       RINOK(progress->SetRatioInfo(&TotalSize, &TotalSize));
73     }
74   }
75 }
76 
SetInStream(ISequentialInStream * inStream)77 STDMETHODIMP CCopyCoder::SetInStream(ISequentialInStream *inStream)
78 {
79   _inStream = inStream;
80   TotalSize = 0;
81   return S_OK;
82 }
83 
ReleaseInStream()84 STDMETHODIMP CCopyCoder::ReleaseInStream()
85 {
86   _inStream.Release();
87   return S_OK;
88 }
89 
Read(void * data,UInt32 size,UInt32 * processedSize)90 STDMETHODIMP CCopyCoder::Read(void *data, UInt32 size, UInt32 *processedSize)
91 {
92   UInt32 realProcessedSize = 0;
93   HRESULT res = _inStream->Read(data, size, &realProcessedSize);
94   TotalSize += realProcessedSize;
95   if (processedSize)
96     *processedSize = realProcessedSize;
97   return res;
98 }
99 
GetInStreamProcessedSize(UInt64 * value)100 STDMETHODIMP CCopyCoder::GetInStreamProcessedSize(UInt64 *value)
101 {
102   *value = TotalSize;
103   return S_OK;
104 }
105 
CopyStream(ISequentialInStream * inStream,ISequentialOutStream * outStream,ICompressProgressInfo * progress)106 HRESULT CopyStream(ISequentialInStream *inStream, ISequentialOutStream *outStream, ICompressProgressInfo *progress)
107 {
108   CMyComPtr<ICompressCoder> copyCoder = new CCopyCoder;
109   return copyCoder->Code(inStream, outStream, NULL, NULL, progress);
110 }
111 
CopyStream_ExactSize(ISequentialInStream * inStream,ISequentialOutStream * outStream,UInt64 size,ICompressProgressInfo * progress)112 HRESULT CopyStream_ExactSize(ISequentialInStream *inStream, ISequentialOutStream *outStream, UInt64 size, ICompressProgressInfo *progress)
113 {
114   NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder;
115   CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
116   RINOK(copyCoder->Code(inStream, outStream, NULL, &size, progress));
117   return copyCoderSpec->TotalSize == size ? S_OK : E_FAIL;
118 }
119 
120 }
121