• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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