xref: /aosp_15_r20/external/lzma/CPP/7zip/Archive/Chm/ChmHandler.cpp (revision f6dc9357d832569d4d1f5d24eacdb3935a1ae8e6)
1*f6dc9357SAndroid Build Coastguard Worker // ChmHandler.cpp
2*f6dc9357SAndroid Build Coastguard Worker 
3*f6dc9357SAndroid Build Coastguard Worker #include "StdAfx.h"
4*f6dc9357SAndroid Build Coastguard Worker 
5*f6dc9357SAndroid Build Coastguard Worker #include "../../../Common/AutoPtr.h"
6*f6dc9357SAndroid Build Coastguard Worker #include "../../../Common/ComTry.h"
7*f6dc9357SAndroid Build Coastguard Worker #include "../../../Common/StringConvert.h"
8*f6dc9357SAndroid Build Coastguard Worker #include "../../../Common/UTFConvert.h"
9*f6dc9357SAndroid Build Coastguard Worker 
10*f6dc9357SAndroid Build Coastguard Worker #include "../../../Windows/PropVariant.h"
11*f6dc9357SAndroid Build Coastguard Worker #include "../../../Windows/TimeUtils.h"
12*f6dc9357SAndroid Build Coastguard Worker 
13*f6dc9357SAndroid Build Coastguard Worker #include "../../Common/LimitedStreams.h"
14*f6dc9357SAndroid Build Coastguard Worker #include "../../Common/ProgressUtils.h"
15*f6dc9357SAndroid Build Coastguard Worker #include "../../Common/StreamUtils.h"
16*f6dc9357SAndroid Build Coastguard Worker #include "../../Common/RegisterArc.h"
17*f6dc9357SAndroid Build Coastguard Worker 
18*f6dc9357SAndroid Build Coastguard Worker #include "../../Compress/CopyCoder.h"
19*f6dc9357SAndroid Build Coastguard Worker #include "../../Compress/LzxDecoder.h"
20*f6dc9357SAndroid Build Coastguard Worker 
21*f6dc9357SAndroid Build Coastguard Worker #include "../Common/ItemNameUtils.h"
22*f6dc9357SAndroid Build Coastguard Worker 
23*f6dc9357SAndroid Build Coastguard Worker #include "ChmHandler.h"
24*f6dc9357SAndroid Build Coastguard Worker 
25*f6dc9357SAndroid Build Coastguard Worker using namespace NWindows;
26*f6dc9357SAndroid Build Coastguard Worker using namespace NTime;
27*f6dc9357SAndroid Build Coastguard Worker 
28*f6dc9357SAndroid Build Coastguard Worker namespace NArchive {
29*f6dc9357SAndroid Build Coastguard Worker namespace NChm {
30*f6dc9357SAndroid Build Coastguard Worker 
31*f6dc9357SAndroid Build Coastguard Worker // #define CHM_DETAILS
32*f6dc9357SAndroid Build Coastguard Worker 
33*f6dc9357SAndroid Build Coastguard Worker #ifdef CHM_DETAILS
34*f6dc9357SAndroid Build Coastguard Worker 
35*f6dc9357SAndroid Build Coastguard Worker enum
36*f6dc9357SAndroid Build Coastguard Worker {
37*f6dc9357SAndroid Build Coastguard Worker   kpidSection = kpidUserDefined
38*f6dc9357SAndroid Build Coastguard Worker };
39*f6dc9357SAndroid Build Coastguard Worker 
40*f6dc9357SAndroid Build Coastguard Worker #endif
41*f6dc9357SAndroid Build Coastguard Worker 
42*f6dc9357SAndroid Build Coastguard Worker static const Byte kProps[] =
43*f6dc9357SAndroid Build Coastguard Worker {
44*f6dc9357SAndroid Build Coastguard Worker   kpidPath,
45*f6dc9357SAndroid Build Coastguard Worker   kpidSize,
46*f6dc9357SAndroid Build Coastguard Worker   kpidMethod,
47*f6dc9357SAndroid Build Coastguard Worker   kpidBlock
48*f6dc9357SAndroid Build Coastguard Worker 
49*f6dc9357SAndroid Build Coastguard Worker   #ifdef CHM_DETAILS
50*f6dc9357SAndroid Build Coastguard Worker   ,
51*f6dc9357SAndroid Build Coastguard Worker   L"Section", kpidSection,
52*f6dc9357SAndroid Build Coastguard Worker   kpidOffset
53*f6dc9357SAndroid Build Coastguard Worker   #endif
54*f6dc9357SAndroid Build Coastguard Worker };
55*f6dc9357SAndroid Build Coastguard Worker 
56*f6dc9357SAndroid Build Coastguard Worker /*
57*f6dc9357SAndroid Build Coastguard Worker static const Byte kArcProps[] =
58*f6dc9357SAndroid Build Coastguard Worker {
59*f6dc9357SAndroid Build Coastguard Worker   // kpidNumBlocks,
60*f6dc9357SAndroid Build Coastguard Worker };
61*f6dc9357SAndroid Build Coastguard Worker */
62*f6dc9357SAndroid Build Coastguard Worker 
63*f6dc9357SAndroid Build Coastguard Worker IMP_IInArchive_Props
64*f6dc9357SAndroid Build Coastguard Worker 
65*f6dc9357SAndroid Build Coastguard Worker IMP_IInArchive_ArcProps_NO_Table
66*f6dc9357SAndroid Build Coastguard Worker 
Z7_COM7F_IMF(CHandler::GetArchiveProperty (PROPID propID,PROPVARIANT * value))67*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
68*f6dc9357SAndroid Build Coastguard Worker {
69*f6dc9357SAndroid Build Coastguard Worker   // COM_TRY_BEGIN
70*f6dc9357SAndroid Build Coastguard Worker   NCOM::CPropVariant prop;
71*f6dc9357SAndroid Build Coastguard Worker   switch (propID)
72*f6dc9357SAndroid Build Coastguard Worker   {
73*f6dc9357SAndroid Build Coastguard Worker     /*
74*f6dc9357SAndroid Build Coastguard Worker     case kpidNumBlocks:
75*f6dc9357SAndroid Build Coastguard Worker     {
76*f6dc9357SAndroid Build Coastguard Worker       UInt64 numBlocks = 0;
77*f6dc9357SAndroid Build Coastguard Worker       FOR_VECTOR(i, m_Database.Sections)
78*f6dc9357SAndroid Build Coastguard Worker       {
79*f6dc9357SAndroid Build Coastguard Worker         const CSectionInfo &s = m_Database.Sections[i];
80*f6dc9357SAndroid Build Coastguard Worker         FOR_VECTOR(j, s.Methods)
81*f6dc9357SAndroid Build Coastguard Worker         {
82*f6dc9357SAndroid Build Coastguard Worker           const CMethodInfo &m = s.Methods[j];
83*f6dc9357SAndroid Build Coastguard Worker           if (m.IsLzx())
84*f6dc9357SAndroid Build Coastguard Worker             numBlocks += m.LzxInfo.ResetTable.GetNumBlocks();
85*f6dc9357SAndroid Build Coastguard Worker         }
86*f6dc9357SAndroid Build Coastguard Worker       }
87*f6dc9357SAndroid Build Coastguard Worker       prop = numBlocks;
88*f6dc9357SAndroid Build Coastguard Worker       break;
89*f6dc9357SAndroid Build Coastguard Worker     }
90*f6dc9357SAndroid Build Coastguard Worker     */
91*f6dc9357SAndroid Build Coastguard Worker     case kpidOffset: prop = m_Database.StartPosition; break;
92*f6dc9357SAndroid Build Coastguard Worker     case kpidPhySize: prop = m_Database.PhySize; break;
93*f6dc9357SAndroid Build Coastguard Worker 
94*f6dc9357SAndroid Build Coastguard Worker     case kpidErrorFlags: prop = m_ErrorFlags; break;
95*f6dc9357SAndroid Build Coastguard Worker   }
96*f6dc9357SAndroid Build Coastguard Worker   prop.Detach(value);
97*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
98*f6dc9357SAndroid Build Coastguard Worker   // COM_TRY_END
99*f6dc9357SAndroid Build Coastguard Worker }
100*f6dc9357SAndroid Build Coastguard Worker 
Z7_COM7F_IMF(CHandler::GetProperty (UInt32 index,PROPID propID,PROPVARIANT * value))101*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value))
102*f6dc9357SAndroid Build Coastguard Worker {
103*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_BEGIN
104*f6dc9357SAndroid Build Coastguard Worker   NCOM::CPropVariant prop;
105*f6dc9357SAndroid Build Coastguard Worker 
106*f6dc9357SAndroid Build Coastguard Worker   if (m_Database.NewFormat)
107*f6dc9357SAndroid Build Coastguard Worker   {
108*f6dc9357SAndroid Build Coastguard Worker     switch (propID)
109*f6dc9357SAndroid Build Coastguard Worker     {
110*f6dc9357SAndroid Build Coastguard Worker       case kpidSize:
111*f6dc9357SAndroid Build Coastguard Worker         prop = (UInt64)m_Database.NewFormatString.Len();
112*f6dc9357SAndroid Build Coastguard Worker       break;
113*f6dc9357SAndroid Build Coastguard Worker     }
114*f6dc9357SAndroid Build Coastguard Worker     prop.Detach(value);
115*f6dc9357SAndroid Build Coastguard Worker     return S_OK;
116*f6dc9357SAndroid Build Coastguard Worker   }
117*f6dc9357SAndroid Build Coastguard Worker 
118*f6dc9357SAndroid Build Coastguard Worker   unsigned entryIndex;
119*f6dc9357SAndroid Build Coastguard Worker   if (m_Database.LowLevel)
120*f6dc9357SAndroid Build Coastguard Worker     entryIndex = index;
121*f6dc9357SAndroid Build Coastguard Worker   else
122*f6dc9357SAndroid Build Coastguard Worker     entryIndex = m_Database.Indices[index];
123*f6dc9357SAndroid Build Coastguard Worker 
124*f6dc9357SAndroid Build Coastguard Worker   const CItem &item = m_Database.Items[entryIndex];
125*f6dc9357SAndroid Build Coastguard Worker 
126*f6dc9357SAndroid Build Coastguard Worker   switch (propID)
127*f6dc9357SAndroid Build Coastguard Worker   {
128*f6dc9357SAndroid Build Coastguard Worker     case kpidPath:
129*f6dc9357SAndroid Build Coastguard Worker     {
130*f6dc9357SAndroid Build Coastguard Worker       UString us;
131*f6dc9357SAndroid Build Coastguard Worker       // if (
132*f6dc9357SAndroid Build Coastguard Worker       ConvertUTF8ToUnicode(item.Name, us);
133*f6dc9357SAndroid Build Coastguard Worker       {
134*f6dc9357SAndroid Build Coastguard Worker         if (!m_Database.LowLevel)
135*f6dc9357SAndroid Build Coastguard Worker         {
136*f6dc9357SAndroid Build Coastguard Worker           if (us.Len() > 1 && us[0] == L'/')
137*f6dc9357SAndroid Build Coastguard Worker             us.Delete(0);
138*f6dc9357SAndroid Build Coastguard Worker         }
139*f6dc9357SAndroid Build Coastguard Worker         NItemName::ReplaceToOsSlashes_Remove_TailSlash(us);
140*f6dc9357SAndroid Build Coastguard Worker         prop = us;
141*f6dc9357SAndroid Build Coastguard Worker       }
142*f6dc9357SAndroid Build Coastguard Worker       break;
143*f6dc9357SAndroid Build Coastguard Worker     }
144*f6dc9357SAndroid Build Coastguard Worker     case kpidIsDir:  prop = item.IsDir(); break;
145*f6dc9357SAndroid Build Coastguard Worker     case kpidSize:  prop = item.Size; break;
146*f6dc9357SAndroid Build Coastguard Worker     case kpidMethod:
147*f6dc9357SAndroid Build Coastguard Worker     {
148*f6dc9357SAndroid Build Coastguard Worker       if (!item.IsDir())
149*f6dc9357SAndroid Build Coastguard Worker       {
150*f6dc9357SAndroid Build Coastguard Worker         if (item.Section == 0)
151*f6dc9357SAndroid Build Coastguard Worker           prop = "Copy";
152*f6dc9357SAndroid Build Coastguard Worker         else if (item.Section < m_Database.Sections.Size())
153*f6dc9357SAndroid Build Coastguard Worker           prop = m_Database.Sections[(unsigned)item.Section].GetMethodName();
154*f6dc9357SAndroid Build Coastguard Worker       }
155*f6dc9357SAndroid Build Coastguard Worker       break;
156*f6dc9357SAndroid Build Coastguard Worker     }
157*f6dc9357SAndroid Build Coastguard Worker     case kpidBlock:
158*f6dc9357SAndroid Build Coastguard Worker       if (m_Database.LowLevel)
159*f6dc9357SAndroid Build Coastguard Worker         prop = item.Section;
160*f6dc9357SAndroid Build Coastguard Worker       else if (item.Section != 0 && item.Section < m_Database.Sections.Size())
161*f6dc9357SAndroid Build Coastguard Worker         prop = m_Database.GetFolder(index);
162*f6dc9357SAndroid Build Coastguard Worker       break;
163*f6dc9357SAndroid Build Coastguard Worker 
164*f6dc9357SAndroid Build Coastguard Worker     #ifdef CHM_DETAILS
165*f6dc9357SAndroid Build Coastguard Worker 
166*f6dc9357SAndroid Build Coastguard Worker     case kpidSection:  prop = (UInt32)item.Section; break;
167*f6dc9357SAndroid Build Coastguard Worker     case kpidOffset:  prop = (UInt32)item.Offset; break;
168*f6dc9357SAndroid Build Coastguard Worker 
169*f6dc9357SAndroid Build Coastguard Worker     #endif
170*f6dc9357SAndroid Build Coastguard Worker   }
171*f6dc9357SAndroid Build Coastguard Worker 
172*f6dc9357SAndroid Build Coastguard Worker   prop.Detach(value);
173*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
174*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_END
175*f6dc9357SAndroid Build Coastguard Worker }
176*f6dc9357SAndroid Build Coastguard Worker 
177*f6dc9357SAndroid Build Coastguard Worker 
Z7_COM7F_IMF(CHandler::Open (IInStream * inStream,const UInt64 * maxCheckStartPosition,IArchiveOpenCallback *))178*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::Open(IInStream *inStream,
179*f6dc9357SAndroid Build Coastguard Worker     const UInt64 *maxCheckStartPosition,
180*f6dc9357SAndroid Build Coastguard Worker     IArchiveOpenCallback * /* openArchiveCallback */))
181*f6dc9357SAndroid Build Coastguard Worker {
182*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_BEGIN
183*f6dc9357SAndroid Build Coastguard Worker   Close();
184*f6dc9357SAndroid Build Coastguard Worker   try
185*f6dc9357SAndroid Build Coastguard Worker   {
186*f6dc9357SAndroid Build Coastguard Worker     CInArchive archive(_help2);
187*f6dc9357SAndroid Build Coastguard Worker     // CProgressImp progressImp(openArchiveCallback);
188*f6dc9357SAndroid Build Coastguard Worker     const HRESULT res = archive.Open(inStream, maxCheckStartPosition, m_Database);
189*f6dc9357SAndroid Build Coastguard Worker     if (!archive.IsArc) m_ErrorFlags |= kpv_ErrorFlags_IsNotArc;
190*f6dc9357SAndroid Build Coastguard Worker     if (archive.HeadersError) m_ErrorFlags |= kpv_ErrorFlags_HeadersError;
191*f6dc9357SAndroid Build Coastguard Worker     if (archive.UnexpectedEnd)  m_ErrorFlags |= kpv_ErrorFlags_UnexpectedEnd;
192*f6dc9357SAndroid Build Coastguard Worker     if (archive.UnsupportedFeature)  m_ErrorFlags |= kpv_ErrorFlags_UnsupportedFeature;
193*f6dc9357SAndroid Build Coastguard Worker 
194*f6dc9357SAndroid Build Coastguard Worker     RINOK(res)
195*f6dc9357SAndroid Build Coastguard Worker     /*
196*f6dc9357SAndroid Build Coastguard Worker     if (m_Database.LowLevel)
197*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
198*f6dc9357SAndroid Build Coastguard Worker     */
199*f6dc9357SAndroid Build Coastguard Worker     m_Stream = inStream;
200*f6dc9357SAndroid Build Coastguard Worker   }
201*f6dc9357SAndroid Build Coastguard Worker   catch(...)
202*f6dc9357SAndroid Build Coastguard Worker   {
203*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
204*f6dc9357SAndroid Build Coastguard Worker   }
205*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
206*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_END
207*f6dc9357SAndroid Build Coastguard Worker }
208*f6dc9357SAndroid Build Coastguard Worker 
Z7_COM7F_IMF(CHandler::Close ())209*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::Close())
210*f6dc9357SAndroid Build Coastguard Worker {
211*f6dc9357SAndroid Build Coastguard Worker   m_ErrorFlags = 0;
212*f6dc9357SAndroid Build Coastguard Worker   m_Database.Clear();
213*f6dc9357SAndroid Build Coastguard Worker   m_Stream.Release();
214*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
215*f6dc9357SAndroid Build Coastguard Worker }
216*f6dc9357SAndroid Build Coastguard Worker 
217*f6dc9357SAndroid Build Coastguard Worker Z7_CLASS_IMP_NOQIB_1(
218*f6dc9357SAndroid Build Coastguard Worker   CChmFolderOutStream
219*f6dc9357SAndroid Build Coastguard Worker   , ISequentialOutStream
220*f6dc9357SAndroid Build Coastguard Worker )
221*f6dc9357SAndroid Build Coastguard Worker   bool m_TestMode;
222*f6dc9357SAndroid Build Coastguard Worker   bool m_IsOk;
223*f6dc9357SAndroid Build Coastguard Worker   bool m_FileIsOpen;
224*f6dc9357SAndroid Build Coastguard Worker   const CFilesDatabase *m_Database;
225*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr<IArchiveExtractCallback> m_ExtractCallback;
226*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr<ISequentialOutStream> m_RealOutStream;
227*f6dc9357SAndroid Build Coastguard Worker   UInt64 m_RemainFileSize;
228*f6dc9357SAndroid Build Coastguard Worker 
229*f6dc9357SAndroid Build Coastguard Worker   HRESULT OpenFile();
230*f6dc9357SAndroid Build Coastguard Worker   HRESULT WriteEmptyFiles();
231*f6dc9357SAndroid Build Coastguard Worker   HRESULT Write2(const void *data, UInt32 size, UInt32 *processedSize, bool isOK);
232*f6dc9357SAndroid Build Coastguard Worker public:
233*f6dc9357SAndroid Build Coastguard Worker 
234*f6dc9357SAndroid Build Coastguard Worker   UInt64 m_FolderSize;
235*f6dc9357SAndroid Build Coastguard Worker   UInt64 m_PosInFolder;
236*f6dc9357SAndroid Build Coastguard Worker   UInt64 m_PosInSection;
237*f6dc9357SAndroid Build Coastguard Worker   const CRecordVector<bool> *m_ExtractStatuses;
238*f6dc9357SAndroid Build Coastguard Worker   unsigned m_StartIndex;
239*f6dc9357SAndroid Build Coastguard Worker   unsigned m_CurrentIndex;
240*f6dc9357SAndroid Build Coastguard Worker   unsigned m_NumFiles;
241*f6dc9357SAndroid Build Coastguard Worker 
242*f6dc9357SAndroid Build Coastguard Worker   void Init(
243*f6dc9357SAndroid Build Coastguard Worker     const CFilesDatabase *database,
244*f6dc9357SAndroid Build Coastguard Worker     IArchiveExtractCallback *extractCallback,
245*f6dc9357SAndroid Build Coastguard Worker     bool testMode);
246*f6dc9357SAndroid Build Coastguard Worker   HRESULT FlushCorrupted(UInt64 maxSize);
247*f6dc9357SAndroid Build Coastguard Worker };
248*f6dc9357SAndroid Build Coastguard Worker 
249*f6dc9357SAndroid Build Coastguard Worker void CChmFolderOutStream::Init(
250*f6dc9357SAndroid Build Coastguard Worker     const CFilesDatabase *database,
251*f6dc9357SAndroid Build Coastguard Worker     IArchiveExtractCallback *extractCallback,
252*f6dc9357SAndroid Build Coastguard Worker     bool testMode)
253*f6dc9357SAndroid Build Coastguard Worker {
254*f6dc9357SAndroid Build Coastguard Worker   m_Database = database;
255*f6dc9357SAndroid Build Coastguard Worker   m_ExtractCallback = extractCallback;
256*f6dc9357SAndroid Build Coastguard Worker   m_TestMode = testMode;
257*f6dc9357SAndroid Build Coastguard Worker 
258*f6dc9357SAndroid Build Coastguard Worker   m_CurrentIndex = 0;
259*f6dc9357SAndroid Build Coastguard Worker   m_FileIsOpen = false;
260*f6dc9357SAndroid Build Coastguard Worker }
261*f6dc9357SAndroid Build Coastguard Worker 
262*f6dc9357SAndroid Build Coastguard Worker HRESULT CChmFolderOutStream::OpenFile()
263*f6dc9357SAndroid Build Coastguard Worker {
264*f6dc9357SAndroid Build Coastguard Worker   Int32 askMode = (*m_ExtractStatuses)[m_CurrentIndex] ? m_TestMode ?
265*f6dc9357SAndroid Build Coastguard Worker       NExtract::NAskMode::kTest :
266*f6dc9357SAndroid Build Coastguard Worker       NExtract::NAskMode::kExtract :
267*f6dc9357SAndroid Build Coastguard Worker       NExtract::NAskMode::kSkip;
268*f6dc9357SAndroid Build Coastguard Worker   m_RealOutStream.Release();
269*f6dc9357SAndroid Build Coastguard Worker   RINOK(m_ExtractCallback->GetStream(m_StartIndex + m_CurrentIndex, &m_RealOutStream, askMode))
270*f6dc9357SAndroid Build Coastguard Worker   if (!m_RealOutStream && !m_TestMode)
271*f6dc9357SAndroid Build Coastguard Worker     askMode = NExtract::NAskMode::kSkip;
272*f6dc9357SAndroid Build Coastguard Worker   return m_ExtractCallback->PrepareOperation(askMode);
273*f6dc9357SAndroid Build Coastguard Worker }
274*f6dc9357SAndroid Build Coastguard Worker 
275*f6dc9357SAndroid Build Coastguard Worker HRESULT CChmFolderOutStream::WriteEmptyFiles()
276*f6dc9357SAndroid Build Coastguard Worker {
277*f6dc9357SAndroid Build Coastguard Worker   if (m_FileIsOpen)
278*f6dc9357SAndroid Build Coastguard Worker     return S_OK;
279*f6dc9357SAndroid Build Coastguard Worker   for (; m_CurrentIndex < m_NumFiles; m_CurrentIndex++)
280*f6dc9357SAndroid Build Coastguard Worker   {
281*f6dc9357SAndroid Build Coastguard Worker     const UInt64 fileSize = m_Database->GetFileSize(m_StartIndex + m_CurrentIndex);
282*f6dc9357SAndroid Build Coastguard Worker     if (fileSize != 0)
283*f6dc9357SAndroid Build Coastguard Worker       return S_OK;
284*f6dc9357SAndroid Build Coastguard Worker     const HRESULT result = OpenFile();
285*f6dc9357SAndroid Build Coastguard Worker     m_RealOutStream.Release();
286*f6dc9357SAndroid Build Coastguard Worker     RINOK(result)
287*f6dc9357SAndroid Build Coastguard Worker     RINOK(m_ExtractCallback->SetOperationResult(NExtract::NOperationResult::kOK))
288*f6dc9357SAndroid Build Coastguard Worker   }
289*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
290*f6dc9357SAndroid Build Coastguard Worker }
291*f6dc9357SAndroid Build Coastguard Worker 
292*f6dc9357SAndroid Build Coastguard Worker // This is WritePart function
293*f6dc9357SAndroid Build Coastguard Worker HRESULT CChmFolderOutStream::Write2(const void *data, UInt32 size, UInt32 *processedSize, bool isOK)
294*f6dc9357SAndroid Build Coastguard Worker {
295*f6dc9357SAndroid Build Coastguard Worker   UInt32 realProcessed = 0;
296*f6dc9357SAndroid Build Coastguard Worker   if (processedSize)
297*f6dc9357SAndroid Build Coastguard Worker    *processedSize = 0;
298*f6dc9357SAndroid Build Coastguard Worker 
299*f6dc9357SAndroid Build Coastguard Worker   while (size != 0)
300*f6dc9357SAndroid Build Coastguard Worker   {
301*f6dc9357SAndroid Build Coastguard Worker     if (m_FileIsOpen)
302*f6dc9357SAndroid Build Coastguard Worker     {
303*f6dc9357SAndroid Build Coastguard Worker       UInt32 numBytesToWrite = (UInt32)MyMin(m_RemainFileSize, (UInt64)(size));
304*f6dc9357SAndroid Build Coastguard Worker       HRESULT res = S_OK;
305*f6dc9357SAndroid Build Coastguard Worker       if (numBytesToWrite > 0)
306*f6dc9357SAndroid Build Coastguard Worker       {
307*f6dc9357SAndroid Build Coastguard Worker         if (!isOK)
308*f6dc9357SAndroid Build Coastguard Worker           m_IsOk = false;
309*f6dc9357SAndroid Build Coastguard Worker         if (m_RealOutStream)
310*f6dc9357SAndroid Build Coastguard Worker         {
311*f6dc9357SAndroid Build Coastguard Worker           UInt32 processedSizeLocal = 0;
312*f6dc9357SAndroid Build Coastguard Worker           res = m_RealOutStream->Write((const Byte *)data, numBytesToWrite, &processedSizeLocal);
313*f6dc9357SAndroid Build Coastguard Worker           numBytesToWrite = processedSizeLocal;
314*f6dc9357SAndroid Build Coastguard Worker         }
315*f6dc9357SAndroid Build Coastguard Worker       }
316*f6dc9357SAndroid Build Coastguard Worker       realProcessed += numBytesToWrite;
317*f6dc9357SAndroid Build Coastguard Worker       if (processedSize)
318*f6dc9357SAndroid Build Coastguard Worker         *processedSize = realProcessed;
319*f6dc9357SAndroid Build Coastguard Worker       data = (const void *)((const Byte *)data + numBytesToWrite);
320*f6dc9357SAndroid Build Coastguard Worker       size -= numBytesToWrite;
321*f6dc9357SAndroid Build Coastguard Worker       m_RemainFileSize -= numBytesToWrite;
322*f6dc9357SAndroid Build Coastguard Worker       m_PosInSection += numBytesToWrite;
323*f6dc9357SAndroid Build Coastguard Worker       m_PosInFolder += numBytesToWrite;
324*f6dc9357SAndroid Build Coastguard Worker       if (res != S_OK)
325*f6dc9357SAndroid Build Coastguard Worker         return res;
326*f6dc9357SAndroid Build Coastguard Worker       if (m_RemainFileSize == 0)
327*f6dc9357SAndroid Build Coastguard Worker       {
328*f6dc9357SAndroid Build Coastguard Worker         m_RealOutStream.Release();
329*f6dc9357SAndroid Build Coastguard Worker         RINOK(m_ExtractCallback->SetOperationResult(
330*f6dc9357SAndroid Build Coastguard Worker           m_IsOk ?
331*f6dc9357SAndroid Build Coastguard Worker             NExtract::NOperationResult::kOK:
332*f6dc9357SAndroid Build Coastguard Worker             NExtract::NOperationResult::kDataError))
333*f6dc9357SAndroid Build Coastguard Worker         m_FileIsOpen = false;
334*f6dc9357SAndroid Build Coastguard Worker       }
335*f6dc9357SAndroid Build Coastguard Worker       if (realProcessed > 0)
336*f6dc9357SAndroid Build Coastguard Worker         break; // with this break this function works as write part
337*f6dc9357SAndroid Build Coastguard Worker     }
338*f6dc9357SAndroid Build Coastguard Worker     else
339*f6dc9357SAndroid Build Coastguard Worker     {
340*f6dc9357SAndroid Build Coastguard Worker       if (m_CurrentIndex >= m_NumFiles)
341*f6dc9357SAndroid Build Coastguard Worker       {
342*f6dc9357SAndroid Build Coastguard Worker         realProcessed += size;
343*f6dc9357SAndroid Build Coastguard Worker         if (processedSize)
344*f6dc9357SAndroid Build Coastguard Worker           *processedSize = realProcessed;
345*f6dc9357SAndroid Build Coastguard Worker         return S_OK;
346*f6dc9357SAndroid Build Coastguard Worker         // return E_FAIL;
347*f6dc9357SAndroid Build Coastguard Worker       }
348*f6dc9357SAndroid Build Coastguard Worker 
349*f6dc9357SAndroid Build Coastguard Worker       unsigned fullIndex = m_StartIndex + m_CurrentIndex;
350*f6dc9357SAndroid Build Coastguard Worker       m_RemainFileSize = m_Database->GetFileSize(fullIndex);
351*f6dc9357SAndroid Build Coastguard Worker       UInt64 fileOffset = m_Database->GetFileOffset(fullIndex);
352*f6dc9357SAndroid Build Coastguard Worker       if (fileOffset < m_PosInSection)
353*f6dc9357SAndroid Build Coastguard Worker         return E_FAIL;
354*f6dc9357SAndroid Build Coastguard Worker 
355*f6dc9357SAndroid Build Coastguard Worker       if (fileOffset > m_PosInSection)
356*f6dc9357SAndroid Build Coastguard Worker       {
357*f6dc9357SAndroid Build Coastguard Worker         UInt32 numBytesToWrite = (UInt32)MyMin(fileOffset - m_PosInSection, UInt64(size));
358*f6dc9357SAndroid Build Coastguard Worker         realProcessed += numBytesToWrite;
359*f6dc9357SAndroid Build Coastguard Worker         if (processedSize)
360*f6dc9357SAndroid Build Coastguard Worker           *processedSize = realProcessed;
361*f6dc9357SAndroid Build Coastguard Worker         data = (const void *)((const Byte *)data + numBytesToWrite);
362*f6dc9357SAndroid Build Coastguard Worker         size -= numBytesToWrite;
363*f6dc9357SAndroid Build Coastguard Worker         m_PosInSection += numBytesToWrite;
364*f6dc9357SAndroid Build Coastguard Worker         m_PosInFolder += numBytesToWrite;
365*f6dc9357SAndroid Build Coastguard Worker       }
366*f6dc9357SAndroid Build Coastguard Worker 
367*f6dc9357SAndroid Build Coastguard Worker       if (fileOffset == m_PosInSection)
368*f6dc9357SAndroid Build Coastguard Worker       {
369*f6dc9357SAndroid Build Coastguard Worker         RINOK(OpenFile())
370*f6dc9357SAndroid Build Coastguard Worker         m_FileIsOpen = true;
371*f6dc9357SAndroid Build Coastguard Worker         m_CurrentIndex++;
372*f6dc9357SAndroid Build Coastguard Worker         m_IsOk = true;
373*f6dc9357SAndroid Build Coastguard Worker       }
374*f6dc9357SAndroid Build Coastguard Worker     }
375*f6dc9357SAndroid Build Coastguard Worker   }
376*f6dc9357SAndroid Build Coastguard Worker 
377*f6dc9357SAndroid Build Coastguard Worker   return WriteEmptyFiles();
378*f6dc9357SAndroid Build Coastguard Worker }
379*f6dc9357SAndroid Build Coastguard Worker 
380*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CChmFolderOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize))
381*f6dc9357SAndroid Build Coastguard Worker {
382*f6dc9357SAndroid Build Coastguard Worker   return Write2(data, size, processedSize, true);
383*f6dc9357SAndroid Build Coastguard Worker }
384*f6dc9357SAndroid Build Coastguard Worker 
385*f6dc9357SAndroid Build Coastguard Worker HRESULT CChmFolderOutStream::FlushCorrupted(UInt64 maxSize)
386*f6dc9357SAndroid Build Coastguard Worker {
387*f6dc9357SAndroid Build Coastguard Worker   const UInt32 kBufferSize = (1 << 10);
388*f6dc9357SAndroid Build Coastguard Worker   Byte buffer[kBufferSize];
389*f6dc9357SAndroid Build Coastguard Worker   for (unsigned i = 0; i < kBufferSize; i++)
390*f6dc9357SAndroid Build Coastguard Worker     buffer[i] = 0;
391*f6dc9357SAndroid Build Coastguard Worker   if (maxSize > m_FolderSize)
392*f6dc9357SAndroid Build Coastguard Worker     maxSize = m_FolderSize;
393*f6dc9357SAndroid Build Coastguard Worker   while (m_PosInFolder < maxSize)
394*f6dc9357SAndroid Build Coastguard Worker   {
395*f6dc9357SAndroid Build Coastguard Worker     UInt32 size = (UInt32)MyMin(maxSize - m_PosInFolder, (UInt64)kBufferSize);
396*f6dc9357SAndroid Build Coastguard Worker     UInt32 processedSizeLocal = 0;
397*f6dc9357SAndroid Build Coastguard Worker     RINOK(Write2(buffer, size, &processedSizeLocal, false))
398*f6dc9357SAndroid Build Coastguard Worker     if (processedSizeLocal == 0)
399*f6dc9357SAndroid Build Coastguard Worker       return S_OK;
400*f6dc9357SAndroid Build Coastguard Worker   }
401*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
402*f6dc9357SAndroid Build Coastguard Worker }
403*f6dc9357SAndroid Build Coastguard Worker 
404*f6dc9357SAndroid Build Coastguard Worker 
405*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
406*f6dc9357SAndroid Build Coastguard Worker     Int32 testModeSpec, IArchiveExtractCallback *extractCallback))
407*f6dc9357SAndroid Build Coastguard Worker {
408*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_BEGIN
409*f6dc9357SAndroid Build Coastguard Worker   const bool allFilesMode = (numItems == (UInt32)(Int32)-1);
410*f6dc9357SAndroid Build Coastguard Worker 
411*f6dc9357SAndroid Build Coastguard Worker   if (allFilesMode)
412*f6dc9357SAndroid Build Coastguard Worker     numItems = m_Database.NewFormat ? 1:
413*f6dc9357SAndroid Build Coastguard Worker       (m_Database.LowLevel ?
414*f6dc9357SAndroid Build Coastguard Worker       m_Database.Items.Size():
415*f6dc9357SAndroid Build Coastguard Worker       m_Database.Indices.Size());
416*f6dc9357SAndroid Build Coastguard Worker   if (numItems == 0)
417*f6dc9357SAndroid Build Coastguard Worker     return S_OK;
418*f6dc9357SAndroid Build Coastguard Worker   const bool testMode = (testModeSpec != 0);
419*f6dc9357SAndroid Build Coastguard Worker 
420*f6dc9357SAndroid Build Coastguard Worker   UInt64 currentTotalSize = 0;
421*f6dc9357SAndroid Build Coastguard Worker 
422*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr2_Create<ICompressProgressInfo, CLocalProgress> lps;
423*f6dc9357SAndroid Build Coastguard Worker   lps->Init(extractCallback, false);
424*f6dc9357SAndroid Build Coastguard Worker 
425*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr2_Create<ICompressCoder, NCompress::CCopyCoder> copyCoder;
426*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr2_Create<ISequentialInStream, CLimitedSequentialInStream> inStream;
427*f6dc9357SAndroid Build Coastguard Worker   inStream->SetStream(m_Stream);
428*f6dc9357SAndroid Build Coastguard Worker 
429*f6dc9357SAndroid Build Coastguard Worker   UInt32 i;
430*f6dc9357SAndroid Build Coastguard Worker 
431*f6dc9357SAndroid Build Coastguard Worker   if (m_Database.LowLevel)
432*f6dc9357SAndroid Build Coastguard Worker   {
433*f6dc9357SAndroid Build Coastguard Worker     UInt64 currentItemSize = 0;
434*f6dc9357SAndroid Build Coastguard Worker     UInt64 totalSize = 0;
435*f6dc9357SAndroid Build Coastguard Worker 
436*f6dc9357SAndroid Build Coastguard Worker     if (m_Database.NewFormat)
437*f6dc9357SAndroid Build Coastguard Worker       totalSize = m_Database.NewFormatString.Len();
438*f6dc9357SAndroid Build Coastguard Worker     else
439*f6dc9357SAndroid Build Coastguard Worker       for (i = 0; i < numItems; i++)
440*f6dc9357SAndroid Build Coastguard Worker         totalSize += m_Database.Items[allFilesMode ? i : indices[i]].Size;
441*f6dc9357SAndroid Build Coastguard Worker 
442*f6dc9357SAndroid Build Coastguard Worker     RINOK(extractCallback->SetTotal(totalSize))
443*f6dc9357SAndroid Build Coastguard Worker 
444*f6dc9357SAndroid Build Coastguard Worker     for (i = 0; i < numItems; i++, currentTotalSize += currentItemSize)
445*f6dc9357SAndroid Build Coastguard Worker     {
446*f6dc9357SAndroid Build Coastguard Worker       currentItemSize = 0;
447*f6dc9357SAndroid Build Coastguard Worker       lps->InSize = currentTotalSize; // Change it
448*f6dc9357SAndroid Build Coastguard Worker       lps->OutSize = currentTotalSize;
449*f6dc9357SAndroid Build Coastguard Worker 
450*f6dc9357SAndroid Build Coastguard Worker       RINOK(lps->SetCur())
451*f6dc9357SAndroid Build Coastguard Worker       CMyComPtr<ISequentialOutStream> realOutStream;
452*f6dc9357SAndroid Build Coastguard Worker       const Int32 askMode= testMode ?
453*f6dc9357SAndroid Build Coastguard Worker           NExtract::NAskMode::kTest :
454*f6dc9357SAndroid Build Coastguard Worker           NExtract::NAskMode::kExtract;
455*f6dc9357SAndroid Build Coastguard Worker       const UInt32 index = allFilesMode ? i : indices[i];
456*f6dc9357SAndroid Build Coastguard Worker       RINOK(extractCallback->GetStream(index, &realOutStream, askMode))
457*f6dc9357SAndroid Build Coastguard Worker 
458*f6dc9357SAndroid Build Coastguard Worker       if (m_Database.NewFormat)
459*f6dc9357SAndroid Build Coastguard Worker       {
460*f6dc9357SAndroid Build Coastguard Worker         if (index != 0)
461*f6dc9357SAndroid Build Coastguard Worker           return E_FAIL;
462*f6dc9357SAndroid Build Coastguard Worker         if (!testMode && !realOutStream)
463*f6dc9357SAndroid Build Coastguard Worker           continue;
464*f6dc9357SAndroid Build Coastguard Worker         if (!testMode)
465*f6dc9357SAndroid Build Coastguard Worker         {
466*f6dc9357SAndroid Build Coastguard Worker           const unsigned size = m_Database.NewFormatString.Len();
467*f6dc9357SAndroid Build Coastguard Worker           RINOK(WriteStream(realOutStream, (const char *)m_Database.NewFormatString, size))
468*f6dc9357SAndroid Build Coastguard Worker         }
469*f6dc9357SAndroid Build Coastguard Worker         RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK))
470*f6dc9357SAndroid Build Coastguard Worker         continue;
471*f6dc9357SAndroid Build Coastguard Worker       }
472*f6dc9357SAndroid Build Coastguard Worker 
473*f6dc9357SAndroid Build Coastguard Worker       const CItem &item = m_Database.Items[index];
474*f6dc9357SAndroid Build Coastguard Worker 
475*f6dc9357SAndroid Build Coastguard Worker       currentItemSize = item.Size;
476*f6dc9357SAndroid Build Coastguard Worker 
477*f6dc9357SAndroid Build Coastguard Worker       if (!testMode && !realOutStream)
478*f6dc9357SAndroid Build Coastguard Worker         continue;
479*f6dc9357SAndroid Build Coastguard Worker       RINOK(extractCallback->PrepareOperation(askMode))
480*f6dc9357SAndroid Build Coastguard Worker       if (item.Section != 0)
481*f6dc9357SAndroid Build Coastguard Worker       {
482*f6dc9357SAndroid Build Coastguard Worker         RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kUnsupportedMethod))
483*f6dc9357SAndroid Build Coastguard Worker         continue;
484*f6dc9357SAndroid Build Coastguard Worker       }
485*f6dc9357SAndroid Build Coastguard Worker 
486*f6dc9357SAndroid Build Coastguard Worker       if (testMode)
487*f6dc9357SAndroid Build Coastguard Worker       {
488*f6dc9357SAndroid Build Coastguard Worker         RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK))
489*f6dc9357SAndroid Build Coastguard Worker         continue;
490*f6dc9357SAndroid Build Coastguard Worker       }
491*f6dc9357SAndroid Build Coastguard Worker 
492*f6dc9357SAndroid Build Coastguard Worker       RINOK(InStream_SeekSet(m_Stream, m_Database.ContentOffset + item.Offset))
493*f6dc9357SAndroid Build Coastguard Worker       inStream->Init(item.Size);
494*f6dc9357SAndroid Build Coastguard Worker 
495*f6dc9357SAndroid Build Coastguard Worker       RINOK(copyCoder.Interface()->Code(inStream, realOutStream, NULL, NULL, lps))
496*f6dc9357SAndroid Build Coastguard Worker       realOutStream.Release();
497*f6dc9357SAndroid Build Coastguard Worker       RINOK(extractCallback->SetOperationResult((copyCoder->TotalSize == item.Size) ?
498*f6dc9357SAndroid Build Coastguard Worker           NExtract::NOperationResult::kOK:
499*f6dc9357SAndroid Build Coastguard Worker           NExtract::NOperationResult::kDataError))
500*f6dc9357SAndroid Build Coastguard Worker     }
501*f6dc9357SAndroid Build Coastguard Worker     return S_OK;
502*f6dc9357SAndroid Build Coastguard Worker   }
503*f6dc9357SAndroid Build Coastguard Worker 
504*f6dc9357SAndroid Build Coastguard Worker   UInt64 lastFolderIndex = (UInt64)0 - 1;
505*f6dc9357SAndroid Build Coastguard Worker 
506*f6dc9357SAndroid Build Coastguard Worker   for (i = 0; i < numItems; i++)
507*f6dc9357SAndroid Build Coastguard Worker   {
508*f6dc9357SAndroid Build Coastguard Worker     const UInt32 index = allFilesMode ? i : indices[i];
509*f6dc9357SAndroid Build Coastguard Worker     const CItem &item = m_Database.Items[m_Database.Indices[index]];
510*f6dc9357SAndroid Build Coastguard Worker     const UInt64 sectionIndex = item.Section;
511*f6dc9357SAndroid Build Coastguard Worker     if (item.IsDir() || item.Size == 0)
512*f6dc9357SAndroid Build Coastguard Worker       continue;
513*f6dc9357SAndroid Build Coastguard Worker     if (sectionIndex == 0)
514*f6dc9357SAndroid Build Coastguard Worker     {
515*f6dc9357SAndroid Build Coastguard Worker       currentTotalSize += item.Size;
516*f6dc9357SAndroid Build Coastguard Worker       continue;
517*f6dc9357SAndroid Build Coastguard Worker     }
518*f6dc9357SAndroid Build Coastguard Worker 
519*f6dc9357SAndroid Build Coastguard Worker     if (sectionIndex >= m_Database.Sections.Size())
520*f6dc9357SAndroid Build Coastguard Worker       continue;
521*f6dc9357SAndroid Build Coastguard Worker 
522*f6dc9357SAndroid Build Coastguard Worker     const CSectionInfo &section = m_Database.Sections[(unsigned)sectionIndex];
523*f6dc9357SAndroid Build Coastguard Worker     if (section.IsLzx())
524*f6dc9357SAndroid Build Coastguard Worker     {
525*f6dc9357SAndroid Build Coastguard Worker       const CLzxInfo &lzxInfo = section.Methods[0].LzxInfo;
526*f6dc9357SAndroid Build Coastguard Worker       UInt64 folderIndex = m_Database.GetFolder(index);
527*f6dc9357SAndroid Build Coastguard Worker       if (lastFolderIndex == folderIndex)
528*f6dc9357SAndroid Build Coastguard Worker         folderIndex++;
529*f6dc9357SAndroid Build Coastguard Worker       lastFolderIndex = m_Database.GetLastFolder(index);
530*f6dc9357SAndroid Build Coastguard Worker       for (; folderIndex <= lastFolderIndex; folderIndex++)
531*f6dc9357SAndroid Build Coastguard Worker         currentTotalSize += lzxInfo.GetFolderSize();
532*f6dc9357SAndroid Build Coastguard Worker     }
533*f6dc9357SAndroid Build Coastguard Worker   }
534*f6dc9357SAndroid Build Coastguard Worker 
535*f6dc9357SAndroid Build Coastguard Worker   RINOK(extractCallback->SetTotal(currentTotalSize))
536*f6dc9357SAndroid Build Coastguard Worker 
537*f6dc9357SAndroid Build Coastguard Worker   CMyUniquePtr<NCompress::NLzx::CDecoder> lzxDecoder;
538*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr2_Create<ISequentialOutStream, CChmFolderOutStream> chmFolderOutStream;
539*f6dc9357SAndroid Build Coastguard Worker 
540*f6dc9357SAndroid Build Coastguard Worker   currentTotalSize = 0;
541*f6dc9357SAndroid Build Coastguard Worker 
542*f6dc9357SAndroid Build Coastguard Worker   CRecordVector<bool> extractStatuses;
543*f6dc9357SAndroid Build Coastguard Worker 
544*f6dc9357SAndroid Build Coastguard Worker   CByteBuffer packBuf;
545*f6dc9357SAndroid Build Coastguard Worker 
546*f6dc9357SAndroid Build Coastguard Worker   for (i = 0;;)
547*f6dc9357SAndroid Build Coastguard Worker   {
548*f6dc9357SAndroid Build Coastguard Worker     RINOK(extractCallback->SetCompleted(&currentTotalSize))
549*f6dc9357SAndroid Build Coastguard Worker 
550*f6dc9357SAndroid Build Coastguard Worker     if (i >= numItems)
551*f6dc9357SAndroid Build Coastguard Worker       break;
552*f6dc9357SAndroid Build Coastguard Worker 
553*f6dc9357SAndroid Build Coastguard Worker     UInt32 index = allFilesMode ? i : indices[i];
554*f6dc9357SAndroid Build Coastguard Worker     i++;
555*f6dc9357SAndroid Build Coastguard Worker     const CItem &item = m_Database.Items[m_Database.Indices[index]];
556*f6dc9357SAndroid Build Coastguard Worker     const UInt64 sectionIndex = item.Section;
557*f6dc9357SAndroid Build Coastguard Worker     const Int32 askMode= testMode ?
558*f6dc9357SAndroid Build Coastguard Worker         NExtract::NAskMode::kTest :
559*f6dc9357SAndroid Build Coastguard Worker         NExtract::NAskMode::kExtract;
560*f6dc9357SAndroid Build Coastguard Worker 
561*f6dc9357SAndroid Build Coastguard Worker     if (item.IsDir())
562*f6dc9357SAndroid Build Coastguard Worker     {
563*f6dc9357SAndroid Build Coastguard Worker       CMyComPtr<ISequentialOutStream> realOutStream;
564*f6dc9357SAndroid Build Coastguard Worker       RINOK(extractCallback->GetStream(index, &realOutStream, askMode))
565*f6dc9357SAndroid Build Coastguard Worker       RINOK(extractCallback->PrepareOperation(askMode))
566*f6dc9357SAndroid Build Coastguard Worker       realOutStream.Release();
567*f6dc9357SAndroid Build Coastguard Worker       RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK))
568*f6dc9357SAndroid Build Coastguard Worker       continue;
569*f6dc9357SAndroid Build Coastguard Worker     }
570*f6dc9357SAndroid Build Coastguard Worker 
571*f6dc9357SAndroid Build Coastguard Worker     lps->InSize = currentTotalSize; // Change it
572*f6dc9357SAndroid Build Coastguard Worker     lps->OutSize = currentTotalSize;
573*f6dc9357SAndroid Build Coastguard Worker 
574*f6dc9357SAndroid Build Coastguard Worker     if (item.Size == 0 || sectionIndex == 0)
575*f6dc9357SAndroid Build Coastguard Worker     {
576*f6dc9357SAndroid Build Coastguard Worker       CMyComPtr<ISequentialOutStream> realOutStream;
577*f6dc9357SAndroid Build Coastguard Worker       RINOK(extractCallback->GetStream(index, &realOutStream, askMode))
578*f6dc9357SAndroid Build Coastguard Worker       if (!testMode && !realOutStream)
579*f6dc9357SAndroid Build Coastguard Worker         continue;
580*f6dc9357SAndroid Build Coastguard Worker       RINOK(extractCallback->PrepareOperation(askMode))
581*f6dc9357SAndroid Build Coastguard Worker       Int32 opRes = NExtract::NOperationResult::kOK;
582*f6dc9357SAndroid Build Coastguard Worker       if (!testMode && item.Size != 0)
583*f6dc9357SAndroid Build Coastguard Worker       {
584*f6dc9357SAndroid Build Coastguard Worker         RINOK(InStream_SeekSet(m_Stream, m_Database.ContentOffset + item.Offset))
585*f6dc9357SAndroid Build Coastguard Worker         inStream->Init(item.Size);
586*f6dc9357SAndroid Build Coastguard Worker         RINOK(copyCoder.Interface()->Code(inStream, realOutStream, NULL, NULL, lps))
587*f6dc9357SAndroid Build Coastguard Worker         if (copyCoder->TotalSize != item.Size)
588*f6dc9357SAndroid Build Coastguard Worker           opRes = NExtract::NOperationResult::kDataError;
589*f6dc9357SAndroid Build Coastguard Worker       }
590*f6dc9357SAndroid Build Coastguard Worker       realOutStream.Release();
591*f6dc9357SAndroid Build Coastguard Worker       RINOK(extractCallback->SetOperationResult(opRes))
592*f6dc9357SAndroid Build Coastguard Worker       currentTotalSize += item.Size;
593*f6dc9357SAndroid Build Coastguard Worker       continue;
594*f6dc9357SAndroid Build Coastguard Worker     }
595*f6dc9357SAndroid Build Coastguard Worker 
596*f6dc9357SAndroid Build Coastguard Worker     if (sectionIndex >= m_Database.Sections.Size())
597*f6dc9357SAndroid Build Coastguard Worker     {
598*f6dc9357SAndroid Build Coastguard Worker       // we must report error here;
599*f6dc9357SAndroid Build Coastguard Worker       CMyComPtr<ISequentialOutStream> realOutStream;
600*f6dc9357SAndroid Build Coastguard Worker       RINOK(extractCallback->GetStream(index, &realOutStream, askMode))
601*f6dc9357SAndroid Build Coastguard Worker       if (!testMode && !realOutStream)
602*f6dc9357SAndroid Build Coastguard Worker         continue;
603*f6dc9357SAndroid Build Coastguard Worker       RINOK(extractCallback->PrepareOperation(askMode))
604*f6dc9357SAndroid Build Coastguard Worker       RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kHeadersError))
605*f6dc9357SAndroid Build Coastguard Worker       continue;
606*f6dc9357SAndroid Build Coastguard Worker     }
607*f6dc9357SAndroid Build Coastguard Worker 
608*f6dc9357SAndroid Build Coastguard Worker     const CSectionInfo &section = m_Database.Sections[(unsigned)sectionIndex];
609*f6dc9357SAndroid Build Coastguard Worker 
610*f6dc9357SAndroid Build Coastguard Worker     if (!section.IsLzx())
611*f6dc9357SAndroid Build Coastguard Worker     {
612*f6dc9357SAndroid Build Coastguard Worker       CMyComPtr<ISequentialOutStream> realOutStream;
613*f6dc9357SAndroid Build Coastguard Worker       RINOK(extractCallback->GetStream(index, &realOutStream, askMode))
614*f6dc9357SAndroid Build Coastguard Worker       if (!testMode && !realOutStream)
615*f6dc9357SAndroid Build Coastguard Worker         continue;
616*f6dc9357SAndroid Build Coastguard Worker       RINOK(extractCallback->PrepareOperation(askMode))
617*f6dc9357SAndroid Build Coastguard Worker       RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kUnsupportedMethod))
618*f6dc9357SAndroid Build Coastguard Worker       continue;
619*f6dc9357SAndroid Build Coastguard Worker     }
620*f6dc9357SAndroid Build Coastguard Worker 
621*f6dc9357SAndroid Build Coastguard Worker     const CLzxInfo &lzxInfo = section.Methods[0].LzxInfo;
622*f6dc9357SAndroid Build Coastguard Worker 
623*f6dc9357SAndroid Build Coastguard Worker     chmFolderOutStream->Init(&m_Database, extractCallback, testMode);
624*f6dc9357SAndroid Build Coastguard Worker 
625*f6dc9357SAndroid Build Coastguard Worker     lzxDecoder.Create_if_Empty();
626*f6dc9357SAndroid Build Coastguard Worker 
627*f6dc9357SAndroid Build Coastguard Worker     UInt64 folderIndex = m_Database.GetFolder(index);
628*f6dc9357SAndroid Build Coastguard Worker 
629*f6dc9357SAndroid Build Coastguard Worker     const UInt64 compressedPos = m_Database.ContentOffset + section.Offset;
630*f6dc9357SAndroid Build Coastguard Worker     RINOK(lzxDecoder->Set_DictBits_and_Alloc(lzxInfo.GetNumDictBits()))
631*f6dc9357SAndroid Build Coastguard Worker 
632*f6dc9357SAndroid Build Coastguard Worker     const CItem *lastItem = &item;
633*f6dc9357SAndroid Build Coastguard Worker     extractStatuses.Clear();
634*f6dc9357SAndroid Build Coastguard Worker     extractStatuses.Add(true);
635*f6dc9357SAndroid Build Coastguard Worker 
636*f6dc9357SAndroid Build Coastguard Worker     for (;; folderIndex++)
637*f6dc9357SAndroid Build Coastguard Worker     {
638*f6dc9357SAndroid Build Coastguard Worker       RINOK(extractCallback->SetCompleted(&currentTotalSize))
639*f6dc9357SAndroid Build Coastguard Worker 
640*f6dc9357SAndroid Build Coastguard Worker       const UInt64 startPos = lzxInfo.GetFolderPos(folderIndex);
641*f6dc9357SAndroid Build Coastguard Worker       UInt64 finishPos = lastItem->Offset + lastItem->Size;
642*f6dc9357SAndroid Build Coastguard Worker       const UInt64 limitFolderIndex = lzxInfo.GetFolder(finishPos);
643*f6dc9357SAndroid Build Coastguard Worker 
644*f6dc9357SAndroid Build Coastguard Worker       lastFolderIndex = m_Database.GetLastFolder(index);
645*f6dc9357SAndroid Build Coastguard Worker       const UInt64 folderSize = lzxInfo.GetFolderSize();
646*f6dc9357SAndroid Build Coastguard Worker       UInt64 unPackSize = folderSize;
647*f6dc9357SAndroid Build Coastguard Worker 
648*f6dc9357SAndroid Build Coastguard Worker       if (extractStatuses.IsEmpty())
649*f6dc9357SAndroid Build Coastguard Worker         chmFolderOutStream->m_StartIndex = index + 1;
650*f6dc9357SAndroid Build Coastguard Worker       else
651*f6dc9357SAndroid Build Coastguard Worker         chmFolderOutStream->m_StartIndex = index;
652*f6dc9357SAndroid Build Coastguard Worker 
653*f6dc9357SAndroid Build Coastguard Worker       if (limitFolderIndex == folderIndex)
654*f6dc9357SAndroid Build Coastguard Worker       {
655*f6dc9357SAndroid Build Coastguard Worker         for (; i < numItems; i++)
656*f6dc9357SAndroid Build Coastguard Worker         {
657*f6dc9357SAndroid Build Coastguard Worker           const UInt32 nextIndex = allFilesMode ? i : indices[i];
658*f6dc9357SAndroid Build Coastguard Worker           const CItem &nextItem = m_Database.Items[m_Database.Indices[nextIndex]];
659*f6dc9357SAndroid Build Coastguard Worker           if (nextItem.Section != sectionIndex)
660*f6dc9357SAndroid Build Coastguard Worker             break;
661*f6dc9357SAndroid Build Coastguard Worker           const UInt64 nextFolderIndex = m_Database.GetFolder(nextIndex);
662*f6dc9357SAndroid Build Coastguard Worker           if (nextFolderIndex != folderIndex)
663*f6dc9357SAndroid Build Coastguard Worker             break;
664*f6dc9357SAndroid Build Coastguard Worker           for (index++; index < nextIndex; index++)
665*f6dc9357SAndroid Build Coastguard Worker             extractStatuses.Add(false);
666*f6dc9357SAndroid Build Coastguard Worker           extractStatuses.Add(true);
667*f6dc9357SAndroid Build Coastguard Worker           index = nextIndex;
668*f6dc9357SAndroid Build Coastguard Worker           lastItem = &nextItem;
669*f6dc9357SAndroid Build Coastguard Worker           if (nextItem.Size != 0)
670*f6dc9357SAndroid Build Coastguard Worker             finishPos = nextItem.Offset + nextItem.Size;
671*f6dc9357SAndroid Build Coastguard Worker           lastFolderIndex = m_Database.GetLastFolder(index);
672*f6dc9357SAndroid Build Coastguard Worker         }
673*f6dc9357SAndroid Build Coastguard Worker       }
674*f6dc9357SAndroid Build Coastguard Worker 
675*f6dc9357SAndroid Build Coastguard Worker       unPackSize = MyMin(finishPos - startPos, unPackSize);
676*f6dc9357SAndroid Build Coastguard Worker 
677*f6dc9357SAndroid Build Coastguard Worker       chmFolderOutStream->m_FolderSize = folderSize;
678*f6dc9357SAndroid Build Coastguard Worker       chmFolderOutStream->m_PosInFolder = 0;
679*f6dc9357SAndroid Build Coastguard Worker       chmFolderOutStream->m_PosInSection = startPos;
680*f6dc9357SAndroid Build Coastguard Worker       chmFolderOutStream->m_ExtractStatuses = &extractStatuses;
681*f6dc9357SAndroid Build Coastguard Worker       chmFolderOutStream->m_NumFiles = extractStatuses.Size();
682*f6dc9357SAndroid Build Coastguard Worker       chmFolderOutStream->m_CurrentIndex = 0;
683*f6dc9357SAndroid Build Coastguard Worker 
684*f6dc9357SAndroid Build Coastguard Worker       try
685*f6dc9357SAndroid Build Coastguard Worker       {
686*f6dc9357SAndroid Build Coastguard Worker         const UInt64 startBlock = lzxInfo.GetBlockIndexFromFolderIndex(folderIndex);
687*f6dc9357SAndroid Build Coastguard Worker         const CResetTable &rt = lzxInfo.ResetTable;
688*f6dc9357SAndroid Build Coastguard Worker         const UInt32 numBlocks = (UInt32)rt.GetNumBlocks(unPackSize);
689*f6dc9357SAndroid Build Coastguard Worker 
690*f6dc9357SAndroid Build Coastguard Worker         for (UInt32 b = 0; b < numBlocks; b++)
691*f6dc9357SAndroid Build Coastguard Worker         {
692*f6dc9357SAndroid Build Coastguard Worker           UInt64 completedSize = currentTotalSize + chmFolderOutStream->m_PosInSection - startPos;
693*f6dc9357SAndroid Build Coastguard Worker           RINOK(extractCallback->SetCompleted(&completedSize))
694*f6dc9357SAndroid Build Coastguard Worker           UInt64 bCur = startBlock + b;
695*f6dc9357SAndroid Build Coastguard Worker           if (bCur >= rt.ResetOffsets.Size())
696*f6dc9357SAndroid Build Coastguard Worker             return E_FAIL;
697*f6dc9357SAndroid Build Coastguard Worker           const UInt64 offset = rt.ResetOffsets[(unsigned)bCur];
698*f6dc9357SAndroid Build Coastguard Worker           UInt64 compressedSize;
699*f6dc9357SAndroid Build Coastguard Worker           rt.GetCompressedSizeOfBlock(bCur, compressedSize);
700*f6dc9357SAndroid Build Coastguard Worker 
701*f6dc9357SAndroid Build Coastguard Worker           // chm writes full blocks. So we don't need to use reduced size for last block
702*f6dc9357SAndroid Build Coastguard Worker 
703*f6dc9357SAndroid Build Coastguard Worker           RINOK(InStream_SeekSet(m_Stream, compressedPos + offset))
704*f6dc9357SAndroid Build Coastguard Worker           inStream->Init(compressedSize);
705*f6dc9357SAndroid Build Coastguard Worker 
706*f6dc9357SAndroid Build Coastguard Worker           lzxDecoder->Set_KeepHistory(b > 0);
707*f6dc9357SAndroid Build Coastguard Worker 
708*f6dc9357SAndroid Build Coastguard Worker           HRESULT res = S_FALSE;
709*f6dc9357SAndroid Build Coastguard Worker           if (compressedSize <= (1u << 30))
710*f6dc9357SAndroid Build Coastguard Worker           {
711*f6dc9357SAndroid Build Coastguard Worker             const unsigned kAdditionalInputSize = 32;
712*f6dc9357SAndroid Build Coastguard Worker             const size_t compressedSizeT = (size_t)compressedSize;
713*f6dc9357SAndroid Build Coastguard Worker             const size_t allocSize = compressedSizeT + kAdditionalInputSize;
714*f6dc9357SAndroid Build Coastguard Worker             if (allocSize <= compressedSize)
715*f6dc9357SAndroid Build Coastguard Worker               throw 2;
716*f6dc9357SAndroid Build Coastguard Worker             packBuf.AllocAtLeast(allocSize);
717*f6dc9357SAndroid Build Coastguard Worker             res = ReadStream_FALSE(inStream, packBuf, compressedSizeT);
718*f6dc9357SAndroid Build Coastguard Worker             if (res == S_OK)
719*f6dc9357SAndroid Build Coastguard Worker             {
720*f6dc9357SAndroid Build Coastguard Worker               memset(packBuf + compressedSizeT, 0xff, kAdditionalInputSize);
721*f6dc9357SAndroid Build Coastguard Worker               lzxDecoder->Set_KeepHistoryForNext(true);
722*f6dc9357SAndroid Build Coastguard Worker               res = lzxDecoder->Code_WithExceedReadWrite(packBuf, compressedSizeT, kBlockSize); // rt.BlockSize;
723*f6dc9357SAndroid Build Coastguard Worker               if (res == S_OK)
724*f6dc9357SAndroid Build Coastguard Worker                 res = WriteStream(chmFolderOutStream,
725*f6dc9357SAndroid Build Coastguard Worker                   lzxDecoder->GetUnpackData(),
726*f6dc9357SAndroid Build Coastguard Worker                   lzxDecoder->GetUnpackSize());
727*f6dc9357SAndroid Build Coastguard Worker             }
728*f6dc9357SAndroid Build Coastguard Worker           }
729*f6dc9357SAndroid Build Coastguard Worker 
730*f6dc9357SAndroid Build Coastguard Worker           if (res != S_OK)
731*f6dc9357SAndroid Build Coastguard Worker           {
732*f6dc9357SAndroid Build Coastguard Worker             if (res != S_FALSE)
733*f6dc9357SAndroid Build Coastguard Worker               return res;
734*f6dc9357SAndroid Build Coastguard Worker             throw 1;
735*f6dc9357SAndroid Build Coastguard Worker           }
736*f6dc9357SAndroid Build Coastguard Worker         }
737*f6dc9357SAndroid Build Coastguard Worker       }
738*f6dc9357SAndroid Build Coastguard Worker       catch(...)
739*f6dc9357SAndroid Build Coastguard Worker       {
740*f6dc9357SAndroid Build Coastguard Worker         RINOK(chmFolderOutStream->FlushCorrupted(unPackSize))
741*f6dc9357SAndroid Build Coastguard Worker       }
742*f6dc9357SAndroid Build Coastguard Worker 
743*f6dc9357SAndroid Build Coastguard Worker       currentTotalSize += folderSize;
744*f6dc9357SAndroid Build Coastguard Worker       if (folderIndex == lastFolderIndex)
745*f6dc9357SAndroid Build Coastguard Worker         break;
746*f6dc9357SAndroid Build Coastguard Worker       extractStatuses.Clear();
747*f6dc9357SAndroid Build Coastguard Worker     }
748*f6dc9357SAndroid Build Coastguard Worker   }
749*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
750*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_END
751*f6dc9357SAndroid Build Coastguard Worker }
752*f6dc9357SAndroid Build Coastguard Worker 
753*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems))
754*f6dc9357SAndroid Build Coastguard Worker {
755*f6dc9357SAndroid Build Coastguard Worker   *numItems = m_Database.NewFormat ? 1:
756*f6dc9357SAndroid Build Coastguard Worker       (m_Database.LowLevel ?
757*f6dc9357SAndroid Build Coastguard Worker       m_Database.Items.Size():
758*f6dc9357SAndroid Build Coastguard Worker       m_Database.Indices.Size());
759*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
760*f6dc9357SAndroid Build Coastguard Worker }
761*f6dc9357SAndroid Build Coastguard Worker 
762*f6dc9357SAndroid Build Coastguard Worker namespace NChm {
763*f6dc9357SAndroid Build Coastguard Worker 
764*f6dc9357SAndroid Build Coastguard Worker static const Byte k_Signature[] = { 'I', 'T', 'S', 'F', 3, 0, 0, 0, 0x60, 0,  0, 0 };
765*f6dc9357SAndroid Build Coastguard Worker 
766*f6dc9357SAndroid Build Coastguard Worker REGISTER_ARC_I_CLS(
767*f6dc9357SAndroid Build Coastguard Worker   CHandler(false),
768*f6dc9357SAndroid Build Coastguard Worker   "Chm", "chm chi chq chw", NULL, 0xE9,
769*f6dc9357SAndroid Build Coastguard Worker   k_Signature,
770*f6dc9357SAndroid Build Coastguard Worker   0,
771*f6dc9357SAndroid Build Coastguard Worker   0,
772*f6dc9357SAndroid Build Coastguard Worker   NULL)
773*f6dc9357SAndroid Build Coastguard Worker 
774*f6dc9357SAndroid Build Coastguard Worker }
775*f6dc9357SAndroid Build Coastguard Worker 
776*f6dc9357SAndroid Build Coastguard Worker namespace NHxs {
777*f6dc9357SAndroid Build Coastguard Worker 
778*f6dc9357SAndroid Build Coastguard Worker static const Byte k_Signature[] = { 'I', 'T', 'O', 'L', 'I', 'T', 'L', 'S', 1, 0, 0, 0, 0x28, 0, 0, 0 };
779*f6dc9357SAndroid Build Coastguard Worker 
780*f6dc9357SAndroid Build Coastguard Worker REGISTER_ARC_I_CLS(
781*f6dc9357SAndroid Build Coastguard Worker   CHandler(true),
782*f6dc9357SAndroid Build Coastguard Worker   "Hxs", "hxs hxi hxr hxq hxw lit", NULL, 0xCE,
783*f6dc9357SAndroid Build Coastguard Worker   k_Signature,
784*f6dc9357SAndroid Build Coastguard Worker   0,
785*f6dc9357SAndroid Build Coastguard Worker   NArcInfoFlags::kFindSignature,
786*f6dc9357SAndroid Build Coastguard Worker   NULL)
787*f6dc9357SAndroid Build Coastguard Worker 
788*f6dc9357SAndroid Build Coastguard Worker }
789*f6dc9357SAndroid Build Coastguard Worker 
790*f6dc9357SAndroid Build Coastguard Worker }}
791