xref: /aosp_15_r20/external/lzma/CPP/7zip/Archive/PpmdHandler.cpp (revision f6dc9357d832569d4d1f5d24eacdb3935a1ae8e6)
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(&currentTotalPacked))
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