1*f6dc9357SAndroid Build Coastguard Worker /* PpmdHandler.cpp -- PPMd format handler
2*f6dc9357SAndroid Build Coastguard Worker 2020 : Igor Pavlov : Public domain
3*f6dc9357SAndroid Build Coastguard Worker This code is based on:
4*f6dc9357SAndroid Build Coastguard Worker PPMd var.H (2001) / var.I (2002): Dmitry Shkarin : Public domain
5*f6dc9357SAndroid Build Coastguard Worker Carryless rangecoder (1999): Dmitry Subbotin : Public domain */
6*f6dc9357SAndroid Build Coastguard Worker
7*f6dc9357SAndroid Build Coastguard Worker #include "StdAfx.h"
8*f6dc9357SAndroid Build Coastguard Worker
9*f6dc9357SAndroid Build Coastguard Worker #include "../../../C/CpuArch.h"
10*f6dc9357SAndroid Build Coastguard Worker #include "../../../C/Alloc.h"
11*f6dc9357SAndroid Build Coastguard Worker #include "../../../C/Ppmd7.h"
12*f6dc9357SAndroid Build Coastguard Worker #include "../../../C/Ppmd8.h"
13*f6dc9357SAndroid Build Coastguard Worker
14*f6dc9357SAndroid Build Coastguard Worker #include "../../Common/ComTry.h"
15*f6dc9357SAndroid Build Coastguard Worker #include "../../Common/StringConvert.h"
16*f6dc9357SAndroid Build Coastguard Worker
17*f6dc9357SAndroid Build Coastguard Worker #include "../../Windows/PropVariant.h"
18*f6dc9357SAndroid Build Coastguard Worker #include "../../Windows/TimeUtils.h"
19*f6dc9357SAndroid Build Coastguard Worker
20*f6dc9357SAndroid Build Coastguard Worker #include "../Common/CWrappers.h"
21*f6dc9357SAndroid Build Coastguard Worker #include "../Common/ProgressUtils.h"
22*f6dc9357SAndroid Build Coastguard Worker #include "../Common/RegisterArc.h"
23*f6dc9357SAndroid Build Coastguard Worker #include "../Common/StreamUtils.h"
24*f6dc9357SAndroid Build Coastguard Worker
25*f6dc9357SAndroid Build Coastguard Worker using namespace NWindows;
26*f6dc9357SAndroid Build Coastguard Worker
27*f6dc9357SAndroid Build Coastguard Worker namespace NArchive {
28*f6dc9357SAndroid Build Coastguard Worker namespace NPpmd {
29*f6dc9357SAndroid Build Coastguard Worker
30*f6dc9357SAndroid Build Coastguard Worker static const UInt32 kBufSize = (1 << 20);
31*f6dc9357SAndroid Build Coastguard Worker
32*f6dc9357SAndroid Build Coastguard Worker struct CBuf
33*f6dc9357SAndroid Build Coastguard Worker {
34*f6dc9357SAndroid Build Coastguard Worker Byte *Buf;
35*f6dc9357SAndroid Build Coastguard Worker
CBufNArchive::NPpmd::CBuf36*f6dc9357SAndroid Build Coastguard Worker CBuf(): Buf(NULL) {}
~CBufNArchive::NPpmd::CBuf37*f6dc9357SAndroid Build Coastguard Worker ~CBuf() { ::MidFree(Buf); }
AllocNArchive::NPpmd::CBuf38*f6dc9357SAndroid Build Coastguard Worker bool Alloc()
39*f6dc9357SAndroid Build Coastguard Worker {
40*f6dc9357SAndroid Build Coastguard Worker if (!Buf)
41*f6dc9357SAndroid Build Coastguard Worker Buf = (Byte *)::MidAlloc(kBufSize);
42*f6dc9357SAndroid Build Coastguard Worker return (Buf != NULL);
43*f6dc9357SAndroid Build Coastguard Worker }
44*f6dc9357SAndroid Build Coastguard Worker };
45*f6dc9357SAndroid Build Coastguard Worker
46*f6dc9357SAndroid Build Coastguard Worker static const UInt32 kHeaderSize = 16;
47*f6dc9357SAndroid Build Coastguard Worker static const UInt32 kSignature = 0x84ACAF8F;
48*f6dc9357SAndroid Build Coastguard Worker static const unsigned kNewHeaderVer = 8;
49*f6dc9357SAndroid Build Coastguard Worker
50*f6dc9357SAndroid Build Coastguard Worker struct CItem
51*f6dc9357SAndroid Build Coastguard Worker {
52*f6dc9357SAndroid Build Coastguard Worker UInt32 Attrib;
53*f6dc9357SAndroid Build Coastguard Worker UInt32 Time;
54*f6dc9357SAndroid Build Coastguard Worker AString Name;
55*f6dc9357SAndroid Build Coastguard Worker
56*f6dc9357SAndroid Build Coastguard Worker unsigned Order;
57*f6dc9357SAndroid Build Coastguard Worker unsigned MemInMB;
58*f6dc9357SAndroid Build Coastguard Worker unsigned Ver;
59*f6dc9357SAndroid Build Coastguard Worker unsigned Restor;
60*f6dc9357SAndroid Build Coastguard Worker
61*f6dc9357SAndroid Build Coastguard Worker HRESULT ReadHeader(ISequentialInStream *s, UInt32 &headerSize);
IsSupportedNArchive::NPpmd::CItem62*f6dc9357SAndroid Build Coastguard Worker bool IsSupported() const
63*f6dc9357SAndroid Build Coastguard Worker {
64*f6dc9357SAndroid Build Coastguard Worker return (Ver == 7 && Order >= PPMD7_MIN_ORDER)
65*f6dc9357SAndroid Build Coastguard Worker || (Ver == 8 && Order >= PPMD8_MIN_ORDER && Restor < PPMD8_RESTORE_METHOD_UNSUPPPORTED);
66*f6dc9357SAndroid Build Coastguard Worker }
67*f6dc9357SAndroid Build Coastguard Worker };
68*f6dc9357SAndroid Build Coastguard Worker
ReadHeader(ISequentialInStream * s,UInt32 & headerSize)69*f6dc9357SAndroid Build Coastguard Worker HRESULT CItem::ReadHeader(ISequentialInStream *s, UInt32 &headerSize)
70*f6dc9357SAndroid Build Coastguard Worker {
71*f6dc9357SAndroid Build Coastguard Worker Byte h[kHeaderSize];
72*f6dc9357SAndroid Build Coastguard Worker RINOK(ReadStream_FALSE(s, h, kHeaderSize))
73*f6dc9357SAndroid Build Coastguard Worker if (GetUi32(h) != kSignature)
74*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
75*f6dc9357SAndroid Build Coastguard Worker Attrib = GetUi32(h + 4);
76*f6dc9357SAndroid Build Coastguard Worker Time = GetUi32(h + 12);
77*f6dc9357SAndroid Build Coastguard Worker const unsigned info = GetUi16(h + 8);
78*f6dc9357SAndroid Build Coastguard Worker Order = (info & 0xF) + 1;
79*f6dc9357SAndroid Build Coastguard Worker MemInMB = ((info >> 4) & 0xFF) + 1;
80*f6dc9357SAndroid Build Coastguard Worker Ver = info >> 12;
81*f6dc9357SAndroid Build Coastguard Worker
82*f6dc9357SAndroid Build Coastguard Worker if (Ver < 6 || Ver > 11) return S_FALSE;
83*f6dc9357SAndroid Build Coastguard Worker
84*f6dc9357SAndroid Build Coastguard Worker UInt32 nameLen = GetUi16(h + 10);
85*f6dc9357SAndroid Build Coastguard Worker Restor = nameLen >> 14;
86*f6dc9357SAndroid Build Coastguard Worker if (Restor > 2)
87*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
88*f6dc9357SAndroid Build Coastguard Worker if (Ver >= kNewHeaderVer)
89*f6dc9357SAndroid Build Coastguard Worker nameLen &= 0x3FFF;
90*f6dc9357SAndroid Build Coastguard Worker if (nameLen > (1 << 9))
91*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
92*f6dc9357SAndroid Build Coastguard Worker char *name = Name.GetBuf(nameLen);
93*f6dc9357SAndroid Build Coastguard Worker const HRESULT res = ReadStream_FALSE(s, name, nameLen);
94*f6dc9357SAndroid Build Coastguard Worker Name.ReleaseBuf_CalcLen(nameLen);
95*f6dc9357SAndroid Build Coastguard Worker headerSize = kHeaderSize + nameLen;
96*f6dc9357SAndroid Build Coastguard Worker return res;
97*f6dc9357SAndroid Build Coastguard Worker }
98*f6dc9357SAndroid Build Coastguard Worker
99*f6dc9357SAndroid Build Coastguard Worker
100*f6dc9357SAndroid Build Coastguard Worker Z7_CLASS_IMP_CHandler_IInArchive_1(
101*f6dc9357SAndroid Build Coastguard Worker IArchiveOpenSeq
102*f6dc9357SAndroid Build Coastguard Worker )
103*f6dc9357SAndroid Build Coastguard Worker CItem _item;
104*f6dc9357SAndroid Build Coastguard Worker UInt32 _headerSize;
105*f6dc9357SAndroid Build Coastguard Worker bool _packSize_Defined;
106*f6dc9357SAndroid Build Coastguard Worker UInt64 _packSize;
107*f6dc9357SAndroid Build Coastguard Worker CMyComPtr<ISequentialInStream> _stream;
108*f6dc9357SAndroid Build Coastguard Worker
109*f6dc9357SAndroid Build Coastguard Worker void GetVersion(NCOM::CPropVariant &prop);
110*f6dc9357SAndroid Build Coastguard Worker };
111*f6dc9357SAndroid Build Coastguard Worker
112*f6dc9357SAndroid Build Coastguard Worker static const Byte kProps[] =
113*f6dc9357SAndroid Build Coastguard Worker {
114*f6dc9357SAndroid Build Coastguard Worker kpidPath,
115*f6dc9357SAndroid Build Coastguard Worker kpidMTime,
116*f6dc9357SAndroid Build Coastguard Worker kpidAttrib,
117*f6dc9357SAndroid Build Coastguard Worker kpidMethod
118*f6dc9357SAndroid Build Coastguard Worker };
119*f6dc9357SAndroid Build Coastguard Worker
120*f6dc9357SAndroid Build Coastguard Worker static const Byte kArcProps[] =
121*f6dc9357SAndroid Build Coastguard Worker {
122*f6dc9357SAndroid Build Coastguard Worker kpidMethod
123*f6dc9357SAndroid Build Coastguard Worker };
124*f6dc9357SAndroid Build Coastguard Worker
125*f6dc9357SAndroid Build Coastguard Worker IMP_IInArchive_Props
126*f6dc9357SAndroid Build Coastguard Worker IMP_IInArchive_ArcProps
127*f6dc9357SAndroid Build Coastguard Worker
GetVersion(NCOM::CPropVariant & prop)128*f6dc9357SAndroid Build Coastguard Worker void CHandler::GetVersion(NCOM::CPropVariant &prop)
129*f6dc9357SAndroid Build Coastguard Worker {
130*f6dc9357SAndroid Build Coastguard Worker AString s ("PPMd");
131*f6dc9357SAndroid Build Coastguard Worker s.Add_Char((char)('A' + _item.Ver));
132*f6dc9357SAndroid Build Coastguard Worker s += ":o";
133*f6dc9357SAndroid Build Coastguard Worker s.Add_UInt32(_item.Order);
134*f6dc9357SAndroid Build Coastguard Worker s += ":mem";
135*f6dc9357SAndroid Build Coastguard Worker s.Add_UInt32(_item.MemInMB);
136*f6dc9357SAndroid Build Coastguard Worker s.Add_Char('m');
137*f6dc9357SAndroid Build Coastguard Worker if (_item.Ver >= kNewHeaderVer && _item.Restor != 0)
138*f6dc9357SAndroid Build Coastguard Worker {
139*f6dc9357SAndroid Build Coastguard Worker s += ":r";
140*f6dc9357SAndroid Build Coastguard Worker s.Add_UInt32(_item.Restor);
141*f6dc9357SAndroid Build Coastguard Worker }
142*f6dc9357SAndroid Build Coastguard Worker prop = s;
143*f6dc9357SAndroid Build Coastguard Worker }
144*f6dc9357SAndroid Build Coastguard Worker
Z7_COM7F_IMF(CHandler::GetArchiveProperty (PROPID propID,PROPVARIANT * value))145*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
146*f6dc9357SAndroid Build Coastguard Worker {
147*f6dc9357SAndroid Build Coastguard Worker NCOM::CPropVariant prop;
148*f6dc9357SAndroid Build Coastguard Worker switch (propID)
149*f6dc9357SAndroid Build Coastguard Worker {
150*f6dc9357SAndroid Build Coastguard Worker case kpidPhySize: if (_packSize_Defined) prop = _packSize; break;
151*f6dc9357SAndroid Build Coastguard Worker case kpidMethod: GetVersion(prop); break;
152*f6dc9357SAndroid Build Coastguard Worker }
153*f6dc9357SAndroid Build Coastguard Worker prop.Detach(value);
154*f6dc9357SAndroid Build Coastguard Worker return S_OK;
155*f6dc9357SAndroid Build Coastguard Worker }
156*f6dc9357SAndroid Build Coastguard Worker
157*f6dc9357SAndroid Build Coastguard Worker
Z7_COM7F_IMF(CHandler::GetNumberOfItems (UInt32 * numItems))158*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems))
159*f6dc9357SAndroid Build Coastguard Worker {
160*f6dc9357SAndroid Build Coastguard Worker *numItems = 1;
161*f6dc9357SAndroid Build Coastguard Worker return S_OK;
162*f6dc9357SAndroid Build Coastguard Worker }
163*f6dc9357SAndroid Build Coastguard Worker
Z7_COM7F_IMF(CHandler::GetProperty (UInt32,PROPID propID,PROPVARIANT * value))164*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value))
165*f6dc9357SAndroid Build Coastguard Worker {
166*f6dc9357SAndroid Build Coastguard Worker COM_TRY_BEGIN
167*f6dc9357SAndroid Build Coastguard Worker NCOM::CPropVariant prop;
168*f6dc9357SAndroid Build Coastguard Worker switch (propID)
169*f6dc9357SAndroid Build Coastguard Worker {
170*f6dc9357SAndroid Build Coastguard Worker case kpidPath: prop = MultiByteToUnicodeString(_item.Name, CP_ACP); break;
171*f6dc9357SAndroid Build Coastguard Worker case kpidMTime:
172*f6dc9357SAndroid Build Coastguard Worker {
173*f6dc9357SAndroid Build Coastguard Worker // time can be in Unix format ???
174*f6dc9357SAndroid Build Coastguard Worker FILETIME utc;
175*f6dc9357SAndroid Build Coastguard Worker if (NTime::DosTime_To_FileTime(_item.Time, utc))
176*f6dc9357SAndroid Build Coastguard Worker prop = utc;
177*f6dc9357SAndroid Build Coastguard Worker break;
178*f6dc9357SAndroid Build Coastguard Worker }
179*f6dc9357SAndroid Build Coastguard Worker case kpidAttrib: prop = _item.Attrib; break;
180*f6dc9357SAndroid Build Coastguard Worker case kpidPackSize: if (_packSize_Defined) prop = _packSize; break;
181*f6dc9357SAndroid Build Coastguard Worker case kpidMethod: GetVersion(prop); break;
182*f6dc9357SAndroid Build Coastguard Worker }
183*f6dc9357SAndroid Build Coastguard Worker prop.Detach(value);
184*f6dc9357SAndroid Build Coastguard Worker return S_OK;
185*f6dc9357SAndroid Build Coastguard Worker COM_TRY_END
186*f6dc9357SAndroid Build Coastguard Worker }
187*f6dc9357SAndroid Build Coastguard Worker
Z7_COM7F_IMF(CHandler::Open (IInStream * stream,const UInt64 *,IArchiveOpenCallback *))188*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *))
189*f6dc9357SAndroid Build Coastguard Worker {
190*f6dc9357SAndroid Build Coastguard Worker return OpenSeq(stream);
191*f6dc9357SAndroid Build Coastguard Worker }
192*f6dc9357SAndroid Build Coastguard Worker
Z7_COM7F_IMF(CHandler::OpenSeq (ISequentialInStream * stream))193*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::OpenSeq(ISequentialInStream *stream))
194*f6dc9357SAndroid Build Coastguard Worker {
195*f6dc9357SAndroid Build Coastguard Worker COM_TRY_BEGIN
196*f6dc9357SAndroid Build Coastguard Worker HRESULT res;
197*f6dc9357SAndroid Build Coastguard Worker try
198*f6dc9357SAndroid Build Coastguard Worker {
199*f6dc9357SAndroid Build Coastguard Worker Close();
200*f6dc9357SAndroid Build Coastguard Worker res = _item.ReadHeader(stream, _headerSize);
201*f6dc9357SAndroid Build Coastguard Worker }
202*f6dc9357SAndroid Build Coastguard Worker catch(...) { res = S_FALSE; }
203*f6dc9357SAndroid Build Coastguard Worker if (res == S_OK)
204*f6dc9357SAndroid Build Coastguard Worker _stream = stream;
205*f6dc9357SAndroid Build Coastguard Worker else
206*f6dc9357SAndroid Build Coastguard Worker Close();
207*f6dc9357SAndroid Build Coastguard Worker return res;
208*f6dc9357SAndroid Build Coastguard Worker COM_TRY_END
209*f6dc9357SAndroid Build Coastguard Worker }
210*f6dc9357SAndroid Build Coastguard Worker
Z7_COM7F_IMF(CHandler::Close ())211*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::Close())
212*f6dc9357SAndroid Build Coastguard Worker {
213*f6dc9357SAndroid Build Coastguard Worker _packSize = 0;
214*f6dc9357SAndroid Build Coastguard Worker _packSize_Defined = false;
215*f6dc9357SAndroid Build Coastguard Worker _stream.Release();
216*f6dc9357SAndroid Build Coastguard Worker return S_OK;
217*f6dc9357SAndroid Build Coastguard Worker }
218*f6dc9357SAndroid Build Coastguard Worker
219*f6dc9357SAndroid Build Coastguard Worker
220*f6dc9357SAndroid Build Coastguard Worker
221*f6dc9357SAndroid Build Coastguard Worker struct CPpmdCpp
222*f6dc9357SAndroid Build Coastguard Worker {
223*f6dc9357SAndroid Build Coastguard Worker unsigned Ver;
224*f6dc9357SAndroid Build Coastguard Worker CPpmd7 _ppmd7;
225*f6dc9357SAndroid Build Coastguard Worker CPpmd8 _ppmd8;
226*f6dc9357SAndroid Build Coastguard Worker
CPpmdCppNArchive::CPpmdCpp227*f6dc9357SAndroid Build Coastguard Worker CPpmdCpp(unsigned version)
228*f6dc9357SAndroid Build Coastguard Worker {
229*f6dc9357SAndroid Build Coastguard Worker Ver = version;
230*f6dc9357SAndroid Build Coastguard Worker Ppmd7_Construct(&_ppmd7);
231*f6dc9357SAndroid Build Coastguard Worker Ppmd8_Construct(&_ppmd8);
232*f6dc9357SAndroid Build Coastguard Worker }
233*f6dc9357SAndroid Build Coastguard Worker
~CPpmdCppNArchive::CPpmdCpp234*f6dc9357SAndroid Build Coastguard Worker ~CPpmdCpp()
235*f6dc9357SAndroid Build Coastguard Worker {
236*f6dc9357SAndroid Build Coastguard Worker Ppmd7_Free(&_ppmd7, &g_BigAlloc);
237*f6dc9357SAndroid Build Coastguard Worker Ppmd8_Free(&_ppmd8, &g_BigAlloc);
238*f6dc9357SAndroid Build Coastguard Worker }
239*f6dc9357SAndroid Build Coastguard Worker
AllocNArchive::CPpmdCpp240*f6dc9357SAndroid Build Coastguard Worker bool Alloc(UInt32 memInMB)
241*f6dc9357SAndroid Build Coastguard Worker {
242*f6dc9357SAndroid Build Coastguard Worker memInMB <<= 20;
243*f6dc9357SAndroid Build Coastguard Worker if (Ver == 7)
244*f6dc9357SAndroid Build Coastguard Worker return Ppmd7_Alloc(&_ppmd7, memInMB, &g_BigAlloc) != 0;
245*f6dc9357SAndroid Build Coastguard Worker return Ppmd8_Alloc(&_ppmd8, memInMB, &g_BigAlloc) != 0;
246*f6dc9357SAndroid Build Coastguard Worker }
247*f6dc9357SAndroid Build Coastguard Worker
InitNArchive::CPpmdCpp248*f6dc9357SAndroid Build Coastguard Worker void Init(unsigned order, unsigned restor)
249*f6dc9357SAndroid Build Coastguard Worker {
250*f6dc9357SAndroid Build Coastguard Worker if (Ver == 7)
251*f6dc9357SAndroid Build Coastguard Worker Ppmd7_Init(&_ppmd7, order);
252*f6dc9357SAndroid Build Coastguard Worker else
253*f6dc9357SAndroid Build Coastguard Worker Ppmd8_Init(&_ppmd8, order, restor);
254*f6dc9357SAndroid Build Coastguard Worker }
255*f6dc9357SAndroid Build Coastguard Worker
InitRcNArchive::CPpmdCpp256*f6dc9357SAndroid Build Coastguard Worker bool InitRc(CByteInBufWrap *inStream)
257*f6dc9357SAndroid Build Coastguard Worker {
258*f6dc9357SAndroid Build Coastguard Worker if (Ver == 7)
259*f6dc9357SAndroid Build Coastguard Worker {
260*f6dc9357SAndroid Build Coastguard Worker _ppmd7.rc.dec.Stream = &inStream->vt;
261*f6dc9357SAndroid Build Coastguard Worker return (Ppmd7a_RangeDec_Init(&_ppmd7.rc.dec) != 0);
262*f6dc9357SAndroid Build Coastguard Worker }
263*f6dc9357SAndroid Build Coastguard Worker else
264*f6dc9357SAndroid Build Coastguard Worker {
265*f6dc9357SAndroid Build Coastguard Worker _ppmd8.Stream.In = &inStream->vt;
266*f6dc9357SAndroid Build Coastguard Worker return Ppmd8_Init_RangeDec(&_ppmd8) != 0;
267*f6dc9357SAndroid Build Coastguard Worker }
268*f6dc9357SAndroid Build Coastguard Worker }
269*f6dc9357SAndroid Build Coastguard Worker
IsFinishedOKNArchive::CPpmdCpp270*f6dc9357SAndroid Build Coastguard Worker bool IsFinishedOK()
271*f6dc9357SAndroid Build Coastguard Worker {
272*f6dc9357SAndroid Build Coastguard Worker if (Ver == 7)
273*f6dc9357SAndroid Build Coastguard Worker return Ppmd7z_RangeDec_IsFinishedOK(&_ppmd7.rc.dec);
274*f6dc9357SAndroid Build Coastguard Worker return Ppmd8_RangeDec_IsFinishedOK(&_ppmd8);
275*f6dc9357SAndroid Build Coastguard Worker }
276*f6dc9357SAndroid Build Coastguard Worker };
277*f6dc9357SAndroid Build Coastguard Worker
278*f6dc9357SAndroid Build Coastguard Worker
Z7_COM7F_IMF(CHandler::Extract (const UInt32 * indices,UInt32 numItems,Int32 testMode,IArchiveExtractCallback * extractCallback))279*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
280*f6dc9357SAndroid Build Coastguard Worker Int32 testMode, IArchiveExtractCallback *extractCallback))
281*f6dc9357SAndroid Build Coastguard Worker {
282*f6dc9357SAndroid Build Coastguard Worker if (numItems == 0)
283*f6dc9357SAndroid Build Coastguard Worker return S_OK;
284*f6dc9357SAndroid Build Coastguard Worker if (numItems != (UInt32)(Int32)-1 && (numItems != 1 || indices[0] != 0))
285*f6dc9357SAndroid Build Coastguard Worker return E_INVALIDARG;
286*f6dc9357SAndroid Build Coastguard Worker
287*f6dc9357SAndroid Build Coastguard Worker // extractCallback->SetTotal(_packSize);
288*f6dc9357SAndroid Build Coastguard Worker UInt64 currentTotalPacked = 0;
289*f6dc9357SAndroid Build Coastguard Worker RINOK(extractCallback->SetCompleted(¤tTotalPacked))
290*f6dc9357SAndroid Build Coastguard Worker Int32 opRes;
291*f6dc9357SAndroid Build Coastguard Worker {
292*f6dc9357SAndroid Build Coastguard Worker CMyComPtr<ISequentialOutStream> realOutStream;
293*f6dc9357SAndroid Build Coastguard Worker const Int32 askMode = testMode ?
294*f6dc9357SAndroid Build Coastguard Worker NExtract::NAskMode::kTest :
295*f6dc9357SAndroid Build Coastguard Worker NExtract::NAskMode::kExtract;
296*f6dc9357SAndroid Build Coastguard Worker RINOK(extractCallback->GetStream(0, &realOutStream, askMode))
297*f6dc9357SAndroid Build Coastguard Worker if (!testMode && !realOutStream)
298*f6dc9357SAndroid Build Coastguard Worker return S_OK;
299*f6dc9357SAndroid Build Coastguard Worker
300*f6dc9357SAndroid Build Coastguard Worker RINOK(extractCallback->PrepareOperation(askMode))
301*f6dc9357SAndroid Build Coastguard Worker
302*f6dc9357SAndroid Build Coastguard Worker CByteInBufWrap inBuf;
303*f6dc9357SAndroid Build Coastguard Worker if (!inBuf.Alloc(1 << 20))
304*f6dc9357SAndroid Build Coastguard Worker return E_OUTOFMEMORY;
305*f6dc9357SAndroid Build Coastguard Worker inBuf.Stream = _stream;
306*f6dc9357SAndroid Build Coastguard Worker
307*f6dc9357SAndroid Build Coastguard Worker CBuf outBuf;
308*f6dc9357SAndroid Build Coastguard Worker if (!outBuf.Alloc())
309*f6dc9357SAndroid Build Coastguard Worker return E_OUTOFMEMORY;
310*f6dc9357SAndroid Build Coastguard Worker
311*f6dc9357SAndroid Build Coastguard Worker CMyComPtr2_Create<ICompressProgressInfo, CLocalProgress> lps;
312*f6dc9357SAndroid Build Coastguard Worker lps->Init(extractCallback, true);
313*f6dc9357SAndroid Build Coastguard Worker
314*f6dc9357SAndroid Build Coastguard Worker CPpmdCpp ppmd(_item.Ver);
315*f6dc9357SAndroid Build Coastguard Worker if (!ppmd.Alloc(_item.MemInMB))
316*f6dc9357SAndroid Build Coastguard Worker return E_OUTOFMEMORY;
317*f6dc9357SAndroid Build Coastguard Worker
318*f6dc9357SAndroid Build Coastguard Worker opRes = NExtract::NOperationResult::kUnsupportedMethod;
319*f6dc9357SAndroid Build Coastguard Worker
320*f6dc9357SAndroid Build Coastguard Worker if (_item.IsSupported())
321*f6dc9357SAndroid Build Coastguard Worker {
322*f6dc9357SAndroid Build Coastguard Worker opRes = NExtract::NOperationResult::kDataError;
323*f6dc9357SAndroid Build Coastguard Worker
324*f6dc9357SAndroid Build Coastguard Worker ppmd.Init(_item.Order, _item.Restor);
325*f6dc9357SAndroid Build Coastguard Worker inBuf.Init();
326*f6dc9357SAndroid Build Coastguard Worker UInt64 outSize = 0;
327*f6dc9357SAndroid Build Coastguard Worker
328*f6dc9357SAndroid Build Coastguard Worker if (ppmd.InitRc(&inBuf) && !inBuf.Extra && inBuf.Res == S_OK)
329*f6dc9357SAndroid Build Coastguard Worker for (;;)
330*f6dc9357SAndroid Build Coastguard Worker {
331*f6dc9357SAndroid Build Coastguard Worker lps->InSize = _packSize = inBuf.GetProcessed();
332*f6dc9357SAndroid Build Coastguard Worker lps->OutSize = outSize;
333*f6dc9357SAndroid Build Coastguard Worker RINOK(lps->SetCur())
334*f6dc9357SAndroid Build Coastguard Worker
335*f6dc9357SAndroid Build Coastguard Worker size_t i;
336*f6dc9357SAndroid Build Coastguard Worker int sym = 0;
337*f6dc9357SAndroid Build Coastguard Worker
338*f6dc9357SAndroid Build Coastguard Worker Byte *buf = outBuf.Buf;
339*f6dc9357SAndroid Build Coastguard Worker if (ppmd.Ver == 7)
340*f6dc9357SAndroid Build Coastguard Worker {
341*f6dc9357SAndroid Build Coastguard Worker for (i = 0; i < kBufSize; i++)
342*f6dc9357SAndroid Build Coastguard Worker {
343*f6dc9357SAndroid Build Coastguard Worker sym = Ppmd7a_DecodeSymbol(&ppmd._ppmd7);
344*f6dc9357SAndroid Build Coastguard Worker if (inBuf.Extra || sym < 0)
345*f6dc9357SAndroid Build Coastguard Worker break;
346*f6dc9357SAndroid Build Coastguard Worker buf[i] = (Byte)sym;
347*f6dc9357SAndroid Build Coastguard Worker }
348*f6dc9357SAndroid Build Coastguard Worker }
349*f6dc9357SAndroid Build Coastguard Worker else
350*f6dc9357SAndroid Build Coastguard Worker {
351*f6dc9357SAndroid Build Coastguard Worker for (i = 0; i < kBufSize; i++)
352*f6dc9357SAndroid Build Coastguard Worker {
353*f6dc9357SAndroid Build Coastguard Worker sym = Ppmd8_DecodeSymbol(&ppmd._ppmd8);
354*f6dc9357SAndroid Build Coastguard Worker if (inBuf.Extra || sym < 0)
355*f6dc9357SAndroid Build Coastguard Worker break;
356*f6dc9357SAndroid Build Coastguard Worker buf[i] = (Byte)sym;
357*f6dc9357SAndroid Build Coastguard Worker }
358*f6dc9357SAndroid Build Coastguard Worker }
359*f6dc9357SAndroid Build Coastguard Worker
360*f6dc9357SAndroid Build Coastguard Worker outSize += i;
361*f6dc9357SAndroid Build Coastguard Worker _packSize = _headerSize + inBuf.GetProcessed();
362*f6dc9357SAndroid Build Coastguard Worker _packSize_Defined = true;
363*f6dc9357SAndroid Build Coastguard Worker if (realOutStream)
364*f6dc9357SAndroid Build Coastguard Worker {
365*f6dc9357SAndroid Build Coastguard Worker RINOK(WriteStream(realOutStream, outBuf.Buf, i))
366*f6dc9357SAndroid Build Coastguard Worker }
367*f6dc9357SAndroid Build Coastguard Worker
368*f6dc9357SAndroid Build Coastguard Worker if (inBuf.Extra)
369*f6dc9357SAndroid Build Coastguard Worker {
370*f6dc9357SAndroid Build Coastguard Worker opRes = NExtract::NOperationResult::kUnexpectedEnd;
371*f6dc9357SAndroid Build Coastguard Worker break;
372*f6dc9357SAndroid Build Coastguard Worker }
373*f6dc9357SAndroid Build Coastguard Worker
374*f6dc9357SAndroid Build Coastguard Worker if (sym < 0)
375*f6dc9357SAndroid Build Coastguard Worker {
376*f6dc9357SAndroid Build Coastguard Worker if (sym == -1 && ppmd.IsFinishedOK())
377*f6dc9357SAndroid Build Coastguard Worker opRes = NExtract::NOperationResult::kOK;
378*f6dc9357SAndroid Build Coastguard Worker break;
379*f6dc9357SAndroid Build Coastguard Worker }
380*f6dc9357SAndroid Build Coastguard Worker }
381*f6dc9357SAndroid Build Coastguard Worker
382*f6dc9357SAndroid Build Coastguard Worker RINOK(inBuf.Res)
383*f6dc9357SAndroid Build Coastguard Worker }
384*f6dc9357SAndroid Build Coastguard Worker }
385*f6dc9357SAndroid Build Coastguard Worker return extractCallback->SetOperationResult(opRes);
386*f6dc9357SAndroid Build Coastguard Worker }
387*f6dc9357SAndroid Build Coastguard Worker
388*f6dc9357SAndroid Build Coastguard Worker
389*f6dc9357SAndroid Build Coastguard Worker static const Byte k_Signature[] = { 0x8F, 0xAF, 0xAC, 0x84 };
390*f6dc9357SAndroid Build Coastguard Worker
391*f6dc9357SAndroid Build Coastguard Worker REGISTER_ARC_I(
392*f6dc9357SAndroid Build Coastguard Worker "Ppmd", "pmd", NULL, 0xD,
393*f6dc9357SAndroid Build Coastguard Worker k_Signature,
394*f6dc9357SAndroid Build Coastguard Worker 0,
395*f6dc9357SAndroid Build Coastguard Worker 0,
396*f6dc9357SAndroid Build Coastguard Worker NULL)
397*f6dc9357SAndroid Build Coastguard Worker
398*f6dc9357SAndroid Build Coastguard Worker }}
399