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 
Code(ISequentialInStream * inStream,ISequentialOutStream * outStream,const UInt64 *,const UInt64 * outSize,ICompressProgressInfo * progress)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 
SetInStream(ISequentialInStream * inStream)72 STDMETHODIMP CCopyCoder::SetInStream(ISequentialInStream *inStream)
73 {
74   _inStream = inStream;
75   TotalSize = 0;
76   return S_OK;
77 }
78 
ReleaseInStream()79 STDMETHODIMP CCopyCoder::ReleaseInStream()
80 {
81   _inStream.Release();
82   return S_OK;
83 }
84 
Read(void * data,UInt32 size,UInt32 * processedSize)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 
GetInStreamProcessedSize(UInt64 * value)95 STDMETHODIMP CCopyCoder::GetInStreamProcessedSize(UInt64 *value)
96 {
97   *value = TotalSize;
98   return S_OK;
99 }
100 
CopyStream(ISequentialInStream * inStream,ISequentialOutStream * outStream,ICompressProgressInfo * progress)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 
CopyStream_ExactSize(ISequentialInStream * inStream,ISequentialOutStream * outStream,UInt64 size,ICompressProgressInfo * progress)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