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