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)
41 {
42 const UInt64 rem = *outSize - TotalSize;
43 if (size > rem)
44 {
45 size = (UInt32)rem;
46 if (size == 0)
47 return S_OK;
48 }
49 }
50
51 HRESULT readRes;
52 {
53 UInt32 pos = 0;
54 do
55 {
56 const UInt32 curSize = size - pos;
57 UInt32 processed = 0;
58 readRes = inStream->Read(_buf + pos, curSize, &processed);
59 if (processed > curSize)
60 return E_FAIL; // internal code failure
61 pos += processed;
62 if (readRes != S_OK || processed == 0)
63 break;
64 }
65 while (pos < kBufSize);
66 size = pos;
67 }
68
69 if (size == 0)
70 return readRes;
71
72 if (outStream)
73 {
74 UInt32 pos = 0;
75 do
76 {
77 const UInt32 curSize = size - pos;
78 UInt32 processed = 0;
79 const HRESULT res = outStream->Write(_buf + pos, curSize, &processed);
80 if (processed > curSize)
81 return E_FAIL; // internal code failure
82 pos += processed;
83 TotalSize += processed;
84 RINOK(res);
85 if (processed == 0)
86 return E_FAIL;
87 }
88 while (pos < size);
89 }
90 else
91 TotalSize += size;
92
93 RINOK(readRes);
94
95 if (size != kBufSize)
96 return S_OK;
97
98 if (progress && (TotalSize & (((UInt32)1 << 22) - 1)) == 0)
99 {
100 RINOK(progress->SetRatioInfo(&TotalSize, &TotalSize));
101 }
102 }
103 }
104
SetInStream(ISequentialInStream * inStream)105 STDMETHODIMP CCopyCoder::SetInStream(ISequentialInStream *inStream)
106 {
107 _inStream = inStream;
108 TotalSize = 0;
109 return S_OK;
110 }
111
ReleaseInStream()112 STDMETHODIMP CCopyCoder::ReleaseInStream()
113 {
114 _inStream.Release();
115 return S_OK;
116 }
117
Read(void * data,UInt32 size,UInt32 * processedSize)118 STDMETHODIMP CCopyCoder::Read(void *data, UInt32 size, UInt32 *processedSize)
119 {
120 UInt32 realProcessedSize = 0;
121 HRESULT res = _inStream->Read(data, size, &realProcessedSize);
122 TotalSize += realProcessedSize;
123 if (processedSize)
124 *processedSize = realProcessedSize;
125 return res;
126 }
127
GetInStreamProcessedSize(UInt64 * value)128 STDMETHODIMP CCopyCoder::GetInStreamProcessedSize(UInt64 *value)
129 {
130 *value = TotalSize;
131 return S_OK;
132 }
133
CopyStream(ISequentialInStream * inStream,ISequentialOutStream * outStream,ICompressProgressInfo * progress)134 HRESULT CopyStream(ISequentialInStream *inStream, ISequentialOutStream *outStream, ICompressProgressInfo *progress)
135 {
136 CMyComPtr<ICompressCoder> copyCoder = new CCopyCoder;
137 return copyCoder->Code(inStream, outStream, NULL, NULL, progress);
138 }
139
CopyStream_ExactSize(ISequentialInStream * inStream,ISequentialOutStream * outStream,UInt64 size,ICompressProgressInfo * progress)140 HRESULT CopyStream_ExactSize(ISequentialInStream *inStream, ISequentialOutStream *outStream, UInt64 size, ICompressProgressInfo *progress)
141 {
142 NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder;
143 CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
144 RINOK(copyCoder->Code(inStream, outStream, NULL, &size, progress));
145 return copyCoderSpec->TotalSize == size ? S_OK : E_FAIL;
146 }
147
148 }
149