xref: /aosp_15_r20/external/lzma/CPP/7zip/Archive/IhexHandler.cpp (revision f6dc9357d832569d4d1f5d24eacdb3935a1ae8e6)
1*f6dc9357SAndroid Build Coastguard Worker // IhexHandler.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 "../../../C/CpuArch.h"
6*f6dc9357SAndroid Build Coastguard Worker 
7*f6dc9357SAndroid Build Coastguard Worker #include "../../Common/ComTry.h"
8*f6dc9357SAndroid Build Coastguard Worker #include "../../Common/DynamicBuffer.h"
9*f6dc9357SAndroid Build Coastguard Worker #include "../../Common/IntToString.h"
10*f6dc9357SAndroid Build Coastguard Worker #include "../../Common/StringToInt.h"
11*f6dc9357SAndroid Build Coastguard Worker 
12*f6dc9357SAndroid Build Coastguard Worker #include "../../Windows/PropVariant.h"
13*f6dc9357SAndroid Build Coastguard Worker 
14*f6dc9357SAndroid Build Coastguard Worker #include "../Common/InBuffer.h"
15*f6dc9357SAndroid Build Coastguard Worker #include "../Common/ProgressUtils.h"
16*f6dc9357SAndroid Build Coastguard Worker #include "../Common/RegisterArc.h"
17*f6dc9357SAndroid Build Coastguard Worker #include "../Common/StreamUtils.h"
18*f6dc9357SAndroid Build Coastguard Worker 
19*f6dc9357SAndroid Build Coastguard Worker namespace NArchive {
20*f6dc9357SAndroid Build Coastguard Worker namespace NIhex {
21*f6dc9357SAndroid Build Coastguard Worker 
22*f6dc9357SAndroid Build Coastguard Worker /* We still don't support files with custom record types: 20, 22: used by Samsung */
23*f6dc9357SAndroid Build Coastguard Worker 
24*f6dc9357SAndroid Build Coastguard Worker struct CBlock
25*f6dc9357SAndroid Build Coastguard Worker {
26*f6dc9357SAndroid Build Coastguard Worker   CByteDynamicBuffer Data;
27*f6dc9357SAndroid Build Coastguard Worker   UInt32 Offset;
28*f6dc9357SAndroid Build Coastguard Worker };
29*f6dc9357SAndroid Build Coastguard Worker 
30*f6dc9357SAndroid Build Coastguard Worker 
31*f6dc9357SAndroid Build Coastguard Worker Z7_CLASS_IMP_CHandler_IInArchive_0
32*f6dc9357SAndroid Build Coastguard Worker 
33*f6dc9357SAndroid Build Coastguard Worker   bool _isArc;
34*f6dc9357SAndroid Build Coastguard Worker   bool _needMoreInput;
35*f6dc9357SAndroid Build Coastguard Worker   bool _dataError;
36*f6dc9357SAndroid Build Coastguard Worker 
37*f6dc9357SAndroid Build Coastguard Worker   UInt64 _phySize;
38*f6dc9357SAndroid Build Coastguard Worker 
39*f6dc9357SAndroid Build Coastguard Worker   CObjectVector<CBlock> _blocks;
40*f6dc9357SAndroid Build Coastguard Worker };
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   kpidVa
47*f6dc9357SAndroid Build Coastguard Worker };
48*f6dc9357SAndroid Build Coastguard Worker 
49*f6dc9357SAndroid Build Coastguard Worker IMP_IInArchive_Props
50*f6dc9357SAndroid Build Coastguard Worker IMP_IInArchive_ArcProps_NO_Table
51*f6dc9357SAndroid Build Coastguard Worker 
Z7_COM7F_IMF(CHandler::GetNumberOfItems (UInt32 * numItems))52*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems))
53*f6dc9357SAndroid Build Coastguard Worker {
54*f6dc9357SAndroid Build Coastguard Worker   *numItems = _blocks.Size();
55*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
56*f6dc9357SAndroid Build Coastguard Worker }
57*f6dc9357SAndroid Build Coastguard Worker 
Z7_COM7F_IMF(CHandler::GetArchiveProperty (PROPID propID,PROPVARIANT * value))58*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
59*f6dc9357SAndroid Build Coastguard Worker {
60*f6dc9357SAndroid Build Coastguard Worker   NWindows::NCOM::CPropVariant prop;
61*f6dc9357SAndroid Build Coastguard Worker   switch (propID)
62*f6dc9357SAndroid Build Coastguard Worker   {
63*f6dc9357SAndroid Build Coastguard Worker     case kpidPhySize: if (_phySize != 0) prop = _phySize; break;
64*f6dc9357SAndroid Build Coastguard Worker     case kpidErrorFlags:
65*f6dc9357SAndroid Build Coastguard Worker     {
66*f6dc9357SAndroid Build Coastguard Worker       UInt32 v = 0;
67*f6dc9357SAndroid Build Coastguard Worker       if (!_isArc) v |= kpv_ErrorFlags_IsNotArc;
68*f6dc9357SAndroid Build Coastguard Worker       if (_needMoreInput) v |= kpv_ErrorFlags_UnexpectedEnd;
69*f6dc9357SAndroid Build Coastguard Worker       if (_dataError) v |= kpv_ErrorFlags_DataError;
70*f6dc9357SAndroid Build Coastguard Worker       prop = v;
71*f6dc9357SAndroid Build Coastguard Worker       break;
72*f6dc9357SAndroid Build Coastguard Worker     }
73*f6dc9357SAndroid Build Coastguard Worker   }
74*f6dc9357SAndroid Build Coastguard Worker   prop.Detach(value);
75*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
76*f6dc9357SAndroid Build Coastguard Worker }
77*f6dc9357SAndroid Build Coastguard Worker 
Z7_COM7F_IMF(CHandler::GetProperty (UInt32 index,PROPID propID,PROPVARIANT * value))78*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value))
79*f6dc9357SAndroid Build Coastguard Worker {
80*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_BEGIN
81*f6dc9357SAndroid Build Coastguard Worker   NWindows::NCOM::CPropVariant prop;
82*f6dc9357SAndroid Build Coastguard Worker   const CBlock &block = _blocks[index];
83*f6dc9357SAndroid Build Coastguard Worker   switch (propID)
84*f6dc9357SAndroid Build Coastguard Worker   {
85*f6dc9357SAndroid Build Coastguard Worker     case kpidSize: prop = (UInt64)block.Data.GetPos(); break;
86*f6dc9357SAndroid Build Coastguard Worker     case kpidVa: prop = block.Offset; break;
87*f6dc9357SAndroid Build Coastguard Worker     case kpidPath:
88*f6dc9357SAndroid Build Coastguard Worker     {
89*f6dc9357SAndroid Build Coastguard Worker       if (_blocks.Size() != 1)
90*f6dc9357SAndroid Build Coastguard Worker       {
91*f6dc9357SAndroid Build Coastguard Worker         char s[16];
92*f6dc9357SAndroid Build Coastguard Worker         ConvertUInt32ToString(index, s);
93*f6dc9357SAndroid Build Coastguard Worker         prop = s;
94*f6dc9357SAndroid Build Coastguard Worker       }
95*f6dc9357SAndroid Build Coastguard Worker       break;
96*f6dc9357SAndroid Build Coastguard Worker     }
97*f6dc9357SAndroid Build Coastguard Worker   }
98*f6dc9357SAndroid Build Coastguard Worker   prop.Detach(value);
99*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
100*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_END
101*f6dc9357SAndroid Build Coastguard Worker }
102*f6dc9357SAndroid Build Coastguard Worker 
103*f6dc9357SAndroid Build Coastguard Worker 
Parse(const Byte * p)104*f6dc9357SAndroid Build Coastguard Worker static int Parse(const Byte *p)
105*f6dc9357SAndroid Build Coastguard Worker {
106*f6dc9357SAndroid Build Coastguard Worker   unsigned v0 = p[0];  Z7_PARSE_HEX_DIGIT(v0, return -1;)
107*f6dc9357SAndroid Build Coastguard Worker   unsigned v1 = p[1];  Z7_PARSE_HEX_DIGIT(v1, return -1;)
108*f6dc9357SAndroid Build Coastguard Worker   return (int)((v0 << 4) | v1);
109*f6dc9357SAndroid Build Coastguard Worker }
110*f6dc9357SAndroid Build Coastguard Worker 
111*f6dc9357SAndroid Build Coastguard Worker #define kType_Data 0
112*f6dc9357SAndroid Build Coastguard Worker #define kType_Eof  1
113*f6dc9357SAndroid Build Coastguard Worker #define kType_Seg  2
114*f6dc9357SAndroid Build Coastguard Worker // #define kType_CsIp 3
115*f6dc9357SAndroid Build Coastguard Worker #define kType_High 4
116*f6dc9357SAndroid Build Coastguard Worker // #define kType_Ip32 5
117*f6dc9357SAndroid Build Coastguard Worker 
118*f6dc9357SAndroid Build Coastguard Worker #define kType_MAX  5
119*f6dc9357SAndroid Build Coastguard Worker 
120*f6dc9357SAndroid Build Coastguard Worker // we don't want to read files with big number of spaces between records
121*f6dc9357SAndroid Build Coastguard Worker // it's our limitation (out of specification):
122*f6dc9357SAndroid Build Coastguard Worker static const unsigned k_NumSpaces_LIMIT = 16 + 1;
123*f6dc9357SAndroid Build Coastguard Worker 
124*f6dc9357SAndroid Build Coastguard Worker #define IS_LINE_DELIMITER(c) (/* (c) == 0 || */ (c) == 10 || (c) == 13)
125*f6dc9357SAndroid Build Coastguard Worker 
IsArc_Ihex(const Byte * p,size_t size)126*f6dc9357SAndroid Build Coastguard Worker API_FUNC_static_IsArc IsArc_Ihex(const Byte *p, size_t size)
127*f6dc9357SAndroid Build Coastguard Worker {
128*f6dc9357SAndroid Build Coastguard Worker   if (size < 1)
129*f6dc9357SAndroid Build Coastguard Worker     return k_IsArc_Res_NEED_MORE;
130*f6dc9357SAndroid Build Coastguard Worker   if (p[0] != ':')
131*f6dc9357SAndroid Build Coastguard Worker     return k_IsArc_Res_NO;
132*f6dc9357SAndroid Build Coastguard Worker   p++;
133*f6dc9357SAndroid Build Coastguard Worker   size--;
134*f6dc9357SAndroid Build Coastguard Worker 
135*f6dc9357SAndroid Build Coastguard Worker   const unsigned kNumLinesToCheck = 3; // 1 line is OK also, but we don't want false detection
136*f6dc9357SAndroid Build Coastguard Worker 
137*f6dc9357SAndroid Build Coastguard Worker   for (unsigned j = 0; j < kNumLinesToCheck; j++)
138*f6dc9357SAndroid Build Coastguard Worker   {
139*f6dc9357SAndroid Build Coastguard Worker     if (size < 4 * 2)
140*f6dc9357SAndroid Build Coastguard Worker       return k_IsArc_Res_NEED_MORE;
141*f6dc9357SAndroid Build Coastguard Worker 
142*f6dc9357SAndroid Build Coastguard Worker     const int num = Parse(p);
143*f6dc9357SAndroid Build Coastguard Worker     if (num < 0)
144*f6dc9357SAndroid Build Coastguard Worker       return k_IsArc_Res_NO;
145*f6dc9357SAndroid Build Coastguard Worker 
146*f6dc9357SAndroid Build Coastguard Worker     const int type = Parse(p + 6);
147*f6dc9357SAndroid Build Coastguard Worker     if (type < 0 || type > kType_MAX)
148*f6dc9357SAndroid Build Coastguard Worker       return k_IsArc_Res_NO;
149*f6dc9357SAndroid Build Coastguard Worker 
150*f6dc9357SAndroid Build Coastguard Worker     unsigned numChars = ((unsigned)num + 5) * 2;
151*f6dc9357SAndroid Build Coastguard Worker     unsigned sum = 0;
152*f6dc9357SAndroid Build Coastguard Worker 
153*f6dc9357SAndroid Build Coastguard Worker     for (unsigned i = 0; i < numChars; i += 2)
154*f6dc9357SAndroid Build Coastguard Worker     {
155*f6dc9357SAndroid Build Coastguard Worker       if (i + 2 > size)
156*f6dc9357SAndroid Build Coastguard Worker         return k_IsArc_Res_NEED_MORE;
157*f6dc9357SAndroid Build Coastguard Worker       int v = Parse(p + i);
158*f6dc9357SAndroid Build Coastguard Worker       if (v < 0)
159*f6dc9357SAndroid Build Coastguard Worker         return k_IsArc_Res_NO;
160*f6dc9357SAndroid Build Coastguard Worker       sum += (unsigned)v;
161*f6dc9357SAndroid Build Coastguard Worker     }
162*f6dc9357SAndroid Build Coastguard Worker 
163*f6dc9357SAndroid Build Coastguard Worker     if (sum & 0xFF)
164*f6dc9357SAndroid Build Coastguard Worker       return k_IsArc_Res_NO;
165*f6dc9357SAndroid Build Coastguard Worker 
166*f6dc9357SAndroid Build Coastguard Worker     if (type == kType_Data)
167*f6dc9357SAndroid Build Coastguard Worker     {
168*f6dc9357SAndroid Build Coastguard Worker       // we don't want to open :0000000000 files
169*f6dc9357SAndroid Build Coastguard Worker       if (num == 0)
170*f6dc9357SAndroid Build Coastguard Worker         return k_IsArc_Res_NO;
171*f6dc9357SAndroid Build Coastguard Worker     }
172*f6dc9357SAndroid Build Coastguard Worker     else
173*f6dc9357SAndroid Build Coastguard Worker     {
174*f6dc9357SAndroid Build Coastguard Worker       if (type == kType_Eof)
175*f6dc9357SAndroid Build Coastguard Worker       {
176*f6dc9357SAndroid Build Coastguard Worker         if (num != 0)
177*f6dc9357SAndroid Build Coastguard Worker           return k_IsArc_Res_NO;
178*f6dc9357SAndroid Build Coastguard Worker         return k_IsArc_Res_YES;
179*f6dc9357SAndroid Build Coastguard Worker       }
180*f6dc9357SAndroid Build Coastguard Worker       if (p[2] != 0 ||
181*f6dc9357SAndroid Build Coastguard Worker           p[3] != 0 ||
182*f6dc9357SAndroid Build Coastguard Worker           p[4] != 0 ||
183*f6dc9357SAndroid Build Coastguard Worker           p[5] != 0)
184*f6dc9357SAndroid Build Coastguard Worker         return k_IsArc_Res_NO;
185*f6dc9357SAndroid Build Coastguard Worker       if (type == kType_Seg || type == kType_High)
186*f6dc9357SAndroid Build Coastguard Worker       {
187*f6dc9357SAndroid Build Coastguard Worker         if (num != 2)
188*f6dc9357SAndroid Build Coastguard Worker           return k_IsArc_Res_NO;
189*f6dc9357SAndroid Build Coastguard Worker       }
190*f6dc9357SAndroid Build Coastguard Worker       else
191*f6dc9357SAndroid Build Coastguard Worker       {
192*f6dc9357SAndroid Build Coastguard Worker         if (num != 4)
193*f6dc9357SAndroid Build Coastguard Worker           return k_IsArc_Res_NO;
194*f6dc9357SAndroid Build Coastguard Worker       }
195*f6dc9357SAndroid Build Coastguard Worker     }
196*f6dc9357SAndroid Build Coastguard Worker 
197*f6dc9357SAndroid Build Coastguard Worker     p += numChars;
198*f6dc9357SAndroid Build Coastguard Worker     size -= numChars;
199*f6dc9357SAndroid Build Coastguard Worker 
200*f6dc9357SAndroid Build Coastguard Worker     unsigned numSpaces = k_NumSpaces_LIMIT;
201*f6dc9357SAndroid Build Coastguard Worker     for (;;)
202*f6dc9357SAndroid Build Coastguard Worker     {
203*f6dc9357SAndroid Build Coastguard Worker       if (size == 0)
204*f6dc9357SAndroid Build Coastguard Worker         return k_IsArc_Res_NEED_MORE;
205*f6dc9357SAndroid Build Coastguard Worker       const Byte b = *p++;
206*f6dc9357SAndroid Build Coastguard Worker       size--;
207*f6dc9357SAndroid Build Coastguard Worker       if (b == ':')
208*f6dc9357SAndroid Build Coastguard Worker         break;
209*f6dc9357SAndroid Build Coastguard Worker       if (--numSpaces == 0 || !IS_LINE_DELIMITER(b))
210*f6dc9357SAndroid Build Coastguard Worker         return k_IsArc_Res_NO;
211*f6dc9357SAndroid Build Coastguard Worker     }
212*f6dc9357SAndroid Build Coastguard Worker   }
213*f6dc9357SAndroid Build Coastguard Worker 
214*f6dc9357SAndroid Build Coastguard Worker   return k_IsArc_Res_YES;
215*f6dc9357SAndroid Build Coastguard Worker }
216*f6dc9357SAndroid Build Coastguard Worker }
217*f6dc9357SAndroid Build Coastguard Worker 
Z7_COM7F_IMF(CHandler::Open (IInStream * stream,const UInt64 *,IArchiveOpenCallback * openCallback))218*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *openCallback))
219*f6dc9357SAndroid Build Coastguard Worker {
220*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_BEGIN
221*f6dc9357SAndroid Build Coastguard Worker   {
222*f6dc9357SAndroid Build Coastguard Worker   Close();
223*f6dc9357SAndroid Build Coastguard Worker   try
224*f6dc9357SAndroid Build Coastguard Worker   {
225*f6dc9357SAndroid Build Coastguard Worker     const unsigned kStartSize = (2 + (256 + 5) + 2) * 2;
226*f6dc9357SAndroid Build Coastguard Worker     Byte temp[kStartSize];
227*f6dc9357SAndroid Build Coastguard Worker     {
228*f6dc9357SAndroid Build Coastguard Worker       size_t size = kStartSize;
229*f6dc9357SAndroid Build Coastguard Worker       RINOK(ReadStream(stream, temp, &size))
230*f6dc9357SAndroid Build Coastguard Worker       const UInt32 isArcRes = IsArc_Ihex(temp, size);
231*f6dc9357SAndroid Build Coastguard Worker       if (isArcRes == k_IsArc_Res_NO)
232*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
233*f6dc9357SAndroid Build Coastguard Worker       if (isArcRes == k_IsArc_Res_NEED_MORE && size != kStartSize)
234*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
235*f6dc9357SAndroid Build Coastguard Worker     }
236*f6dc9357SAndroid Build Coastguard Worker     _isArc = true;
237*f6dc9357SAndroid Build Coastguard Worker 
238*f6dc9357SAndroid Build Coastguard Worker     RINOK(InStream_SeekToBegin(stream))
239*f6dc9357SAndroid Build Coastguard Worker     CInBuffer s;
240*f6dc9357SAndroid Build Coastguard Worker     if (!s.Create(1 << 15))
241*f6dc9357SAndroid Build Coastguard Worker       return E_OUTOFMEMORY;
242*f6dc9357SAndroid Build Coastguard Worker     s.SetStream(stream);
243*f6dc9357SAndroid Build Coastguard Worker     s.Init();
244*f6dc9357SAndroid Build Coastguard Worker     {
245*f6dc9357SAndroid Build Coastguard Worker       Byte b;
246*f6dc9357SAndroid Build Coastguard Worker       if (!s.ReadByte(b))
247*f6dc9357SAndroid Build Coastguard Worker       {
248*f6dc9357SAndroid Build Coastguard Worker         _needMoreInput = true;
249*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
250*f6dc9357SAndroid Build Coastguard Worker       }
251*f6dc9357SAndroid Build Coastguard Worker       if (b != ':')
252*f6dc9357SAndroid Build Coastguard Worker       {
253*f6dc9357SAndroid Build Coastguard Worker         _dataError = true;
254*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
255*f6dc9357SAndroid Build Coastguard Worker       }
256*f6dc9357SAndroid Build Coastguard Worker     }
257*f6dc9357SAndroid Build Coastguard Worker 
258*f6dc9357SAndroid Build Coastguard Worker     UInt32 globalOffset = 0;
259*f6dc9357SAndroid Build Coastguard Worker     const UInt32 k_progressStep = 1 << 24;
260*f6dc9357SAndroid Build Coastguard Worker     UInt64 progressNext = k_progressStep;
261*f6dc9357SAndroid Build Coastguard Worker 
262*f6dc9357SAndroid Build Coastguard Worker     for (;;)
263*f6dc9357SAndroid Build Coastguard Worker     {
264*f6dc9357SAndroid Build Coastguard Worker       if (s.ReadBytes(temp, 2) != 2)
265*f6dc9357SAndroid Build Coastguard Worker       {
266*f6dc9357SAndroid Build Coastguard Worker         _needMoreInput = true;
267*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
268*f6dc9357SAndroid Build Coastguard Worker       }
269*f6dc9357SAndroid Build Coastguard Worker       const int num = Parse(temp);
270*f6dc9357SAndroid Build Coastguard Worker       if (num < 0)
271*f6dc9357SAndroid Build Coastguard Worker       {
272*f6dc9357SAndroid Build Coastguard Worker         _dataError = true;
273*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
274*f6dc9357SAndroid Build Coastguard Worker       }
275*f6dc9357SAndroid Build Coastguard Worker       {
276*f6dc9357SAndroid Build Coastguard Worker         const size_t numPairs = (unsigned)num + 4;
277*f6dc9357SAndroid Build Coastguard Worker         const size_t numBytes = numPairs * 2;
278*f6dc9357SAndroid Build Coastguard Worker         if (s.ReadBytes(temp, numBytes) != numBytes)
279*f6dc9357SAndroid Build Coastguard Worker         {
280*f6dc9357SAndroid Build Coastguard Worker           _needMoreInput = true;
281*f6dc9357SAndroid Build Coastguard Worker           return S_FALSE;
282*f6dc9357SAndroid Build Coastguard Worker         }
283*f6dc9357SAndroid Build Coastguard Worker         unsigned sum = (unsigned)num;
284*f6dc9357SAndroid Build Coastguard Worker         for (size_t i = 0; i < numPairs; i++)
285*f6dc9357SAndroid Build Coastguard Worker         {
286*f6dc9357SAndroid Build Coastguard Worker           const int a = Parse(temp + i * 2);
287*f6dc9357SAndroid Build Coastguard Worker           if (a < 0)
288*f6dc9357SAndroid Build Coastguard Worker           {
289*f6dc9357SAndroid Build Coastguard Worker             _dataError = true;
290*f6dc9357SAndroid Build Coastguard Worker             return S_FALSE;
291*f6dc9357SAndroid Build Coastguard Worker           }
292*f6dc9357SAndroid Build Coastguard Worker           temp[i] = (Byte)a;
293*f6dc9357SAndroid Build Coastguard Worker           sum += (unsigned)a;
294*f6dc9357SAndroid Build Coastguard Worker         }
295*f6dc9357SAndroid Build Coastguard Worker         if (sum & 0xFF)
296*f6dc9357SAndroid Build Coastguard Worker         {
297*f6dc9357SAndroid Build Coastguard Worker           _dataError = true;
298*f6dc9357SAndroid Build Coastguard Worker           return S_FALSE;
299*f6dc9357SAndroid Build Coastguard Worker         }
300*f6dc9357SAndroid Build Coastguard Worker       }
301*f6dc9357SAndroid Build Coastguard Worker 
302*f6dc9357SAndroid Build Coastguard Worker       const unsigned type = temp[2];
303*f6dc9357SAndroid Build Coastguard Worker       if (type > kType_MAX)
304*f6dc9357SAndroid Build Coastguard Worker       {
305*f6dc9357SAndroid Build Coastguard Worker         _dataError = true;
306*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
307*f6dc9357SAndroid Build Coastguard Worker       }
308*f6dc9357SAndroid Build Coastguard Worker 
309*f6dc9357SAndroid Build Coastguard Worker       const UInt32 a = GetBe16(temp);
310*f6dc9357SAndroid Build Coastguard Worker 
311*f6dc9357SAndroid Build Coastguard Worker       if (type == kType_Data)
312*f6dc9357SAndroid Build Coastguard Worker       {
313*f6dc9357SAndroid Build Coastguard Worker         if (num == 0)
314*f6dc9357SAndroid Build Coastguard Worker         {
315*f6dc9357SAndroid Build Coastguard Worker           // we don't want to open :0000000000 files
316*f6dc9357SAndroid Build Coastguard Worker           // maybe it can mean EOF in old-style files?
317*f6dc9357SAndroid Build Coastguard Worker           _dataError = true;
318*f6dc9357SAndroid Build Coastguard Worker           return S_FALSE;
319*f6dc9357SAndroid Build Coastguard Worker         }
320*f6dc9357SAndroid Build Coastguard Worker         // if (num != 0)
321*f6dc9357SAndroid Build Coastguard Worker         {
322*f6dc9357SAndroid Build Coastguard Worker           const UInt32 offs = globalOffset + a;
323*f6dc9357SAndroid Build Coastguard Worker           CBlock *block = NULL;
324*f6dc9357SAndroid Build Coastguard Worker           if (!_blocks.IsEmpty())
325*f6dc9357SAndroid Build Coastguard Worker           {
326*f6dc9357SAndroid Build Coastguard Worker             block = &_blocks.Back();
327*f6dc9357SAndroid Build Coastguard Worker             if (block->Offset + block->Data.GetPos() != offs)
328*f6dc9357SAndroid Build Coastguard Worker               block = NULL;
329*f6dc9357SAndroid Build Coastguard Worker           }
330*f6dc9357SAndroid Build Coastguard Worker           if (!block)
331*f6dc9357SAndroid Build Coastguard Worker           {
332*f6dc9357SAndroid Build Coastguard Worker             block = &_blocks.AddNew();
333*f6dc9357SAndroid Build Coastguard Worker             block->Offset = offs;
334*f6dc9357SAndroid Build Coastguard Worker           }
335*f6dc9357SAndroid Build Coastguard Worker           block->Data.AddData(temp + 3, (unsigned)num);
336*f6dc9357SAndroid Build Coastguard Worker         }
337*f6dc9357SAndroid Build Coastguard Worker       }
338*f6dc9357SAndroid Build Coastguard Worker       else
339*f6dc9357SAndroid Build Coastguard Worker       {
340*f6dc9357SAndroid Build Coastguard Worker         if (a != 0) // from description: the address field is typically 0.
341*f6dc9357SAndroid Build Coastguard Worker         {
342*f6dc9357SAndroid Build Coastguard Worker           _dataError = true;
343*f6dc9357SAndroid Build Coastguard Worker           return S_FALSE;
344*f6dc9357SAndroid Build Coastguard Worker         }
345*f6dc9357SAndroid Build Coastguard Worker         if (type == kType_Eof)
346*f6dc9357SAndroid Build Coastguard Worker         {
347*f6dc9357SAndroid Build Coastguard Worker           if (num != 0)
348*f6dc9357SAndroid Build Coastguard Worker           {
349*f6dc9357SAndroid Build Coastguard Worker             _dataError = true;
350*f6dc9357SAndroid Build Coastguard Worker             return S_FALSE;
351*f6dc9357SAndroid Build Coastguard Worker           }
352*f6dc9357SAndroid Build Coastguard Worker           _phySize = s.GetProcessedSize();
353*f6dc9357SAndroid Build Coastguard Worker           Byte b;
354*f6dc9357SAndroid Build Coastguard Worker           if (s.ReadByte(b))
355*f6dc9357SAndroid Build Coastguard Worker           {
356*f6dc9357SAndroid Build Coastguard Worker             if (b == 10)
357*f6dc9357SAndroid Build Coastguard Worker               _phySize++;
358*f6dc9357SAndroid Build Coastguard Worker             else if (b == 13)
359*f6dc9357SAndroid Build Coastguard Worker             {
360*f6dc9357SAndroid Build Coastguard Worker               _phySize++;
361*f6dc9357SAndroid Build Coastguard Worker               if (s.ReadByte(b))
362*f6dc9357SAndroid Build Coastguard Worker               {
363*f6dc9357SAndroid Build Coastguard Worker                 if (b == 10)
364*f6dc9357SAndroid Build Coastguard Worker                   _phySize++;
365*f6dc9357SAndroid Build Coastguard Worker               }
366*f6dc9357SAndroid Build Coastguard Worker             }
367*f6dc9357SAndroid Build Coastguard Worker           }
368*f6dc9357SAndroid Build Coastguard Worker           return S_OK;
369*f6dc9357SAndroid Build Coastguard Worker         }
370*f6dc9357SAndroid Build Coastguard Worker 
371*f6dc9357SAndroid Build Coastguard Worker         if (type == kType_Seg || type == kType_High)
372*f6dc9357SAndroid Build Coastguard Worker         {
373*f6dc9357SAndroid Build Coastguard Worker           if (num != 2)
374*f6dc9357SAndroid Build Coastguard Worker           {
375*f6dc9357SAndroid Build Coastguard Worker             _dataError = true;
376*f6dc9357SAndroid Build Coastguard Worker             return S_FALSE;
377*f6dc9357SAndroid Build Coastguard Worker           }
378*f6dc9357SAndroid Build Coastguard Worker           // here we use optimization trick for num shift calculation: (type == kType_Seg ? 4 : 16)
379*f6dc9357SAndroid Build Coastguard Worker           globalOffset = (UInt32)GetBe16(temp + 3) << (1u << type);
380*f6dc9357SAndroid Build Coastguard Worker         }
381*f6dc9357SAndroid Build Coastguard Worker         else
382*f6dc9357SAndroid Build Coastguard Worker         {
383*f6dc9357SAndroid Build Coastguard Worker           if (num != 4)
384*f6dc9357SAndroid Build Coastguard Worker           {
385*f6dc9357SAndroid Build Coastguard Worker             _dataError = true;
386*f6dc9357SAndroid Build Coastguard Worker             return S_FALSE;
387*f6dc9357SAndroid Build Coastguard Worker           }
388*f6dc9357SAndroid Build Coastguard Worker         }
389*f6dc9357SAndroid Build Coastguard Worker       }
390*f6dc9357SAndroid Build Coastguard Worker 
391*f6dc9357SAndroid Build Coastguard Worker       if (openCallback)
392*f6dc9357SAndroid Build Coastguard Worker       {
393*f6dc9357SAndroid Build Coastguard Worker         const UInt64 processed = s.GetProcessedSize();
394*f6dc9357SAndroid Build Coastguard Worker         if (processed >= progressNext)
395*f6dc9357SAndroid Build Coastguard Worker         {
396*f6dc9357SAndroid Build Coastguard Worker           progressNext = processed + k_progressStep;
397*f6dc9357SAndroid Build Coastguard Worker           const UInt64 numFiles = _blocks.Size();
398*f6dc9357SAndroid Build Coastguard Worker           RINOK(openCallback->SetCompleted(&numFiles, &processed))
399*f6dc9357SAndroid Build Coastguard Worker         }
400*f6dc9357SAndroid Build Coastguard Worker       }
401*f6dc9357SAndroid Build Coastguard Worker 
402*f6dc9357SAndroid Build Coastguard Worker       unsigned numSpaces = k_NumSpaces_LIMIT;
403*f6dc9357SAndroid Build Coastguard Worker       for (;;)
404*f6dc9357SAndroid Build Coastguard Worker       {
405*f6dc9357SAndroid Build Coastguard Worker         Byte b;
406*f6dc9357SAndroid Build Coastguard Worker         if (!s.ReadByte(b))
407*f6dc9357SAndroid Build Coastguard Worker         {
408*f6dc9357SAndroid Build Coastguard Worker           _needMoreInput = true;
409*f6dc9357SAndroid Build Coastguard Worker           return S_FALSE;
410*f6dc9357SAndroid Build Coastguard Worker         }
411*f6dc9357SAndroid Build Coastguard Worker         if (b == ':')
412*f6dc9357SAndroid Build Coastguard Worker           break;
413*f6dc9357SAndroid Build Coastguard Worker         if (--numSpaces == 0 || !IS_LINE_DELIMITER(b))
414*f6dc9357SAndroid Build Coastguard Worker         {
415*f6dc9357SAndroid Build Coastguard Worker           _dataError = true;
416*f6dc9357SAndroid Build Coastguard Worker           return S_FALSE;
417*f6dc9357SAndroid Build Coastguard Worker         }
418*f6dc9357SAndroid Build Coastguard Worker       }
419*f6dc9357SAndroid Build Coastguard Worker     }
420*f6dc9357SAndroid Build Coastguard Worker   }
421*f6dc9357SAndroid Build Coastguard Worker   catch(const CInBufferException &e) { return e.ErrorCode; }
422*f6dc9357SAndroid Build Coastguard Worker   }
423*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_END
424*f6dc9357SAndroid Build Coastguard Worker }
425*f6dc9357SAndroid Build Coastguard Worker 
426*f6dc9357SAndroid Build Coastguard Worker 
Z7_COM7F_IMF(CHandler::Close ())427*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::Close())
428*f6dc9357SAndroid Build Coastguard Worker {
429*f6dc9357SAndroid Build Coastguard Worker   _phySize = 0;
430*f6dc9357SAndroid Build Coastguard Worker   _isArc = false;
431*f6dc9357SAndroid Build Coastguard Worker   _needMoreInput = false;
432*f6dc9357SAndroid Build Coastguard Worker   _dataError = false;
433*f6dc9357SAndroid Build Coastguard Worker   _blocks.Clear();
434*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
435*f6dc9357SAndroid Build Coastguard Worker }
436*f6dc9357SAndroid Build Coastguard Worker 
437*f6dc9357SAndroid Build Coastguard Worker 
Z7_COM7F_IMF(CHandler::Extract (const UInt32 * indices,UInt32 numItems,Int32 testMode,IArchiveExtractCallback * extractCallback))438*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
439*f6dc9357SAndroid Build Coastguard Worker     Int32 testMode, IArchiveExtractCallback *extractCallback))
440*f6dc9357SAndroid Build Coastguard Worker {
441*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_BEGIN
442*f6dc9357SAndroid Build Coastguard Worker   const bool allFilesMode = (numItems == (UInt32)(Int32)-1);
443*f6dc9357SAndroid Build Coastguard Worker   if (allFilesMode)
444*f6dc9357SAndroid Build Coastguard Worker     numItems = _blocks.Size();
445*f6dc9357SAndroid Build Coastguard Worker   if (numItems == 0)
446*f6dc9357SAndroid Build Coastguard Worker     return S_OK;
447*f6dc9357SAndroid Build Coastguard Worker 
448*f6dc9357SAndroid Build Coastguard Worker   UInt64 totalSize = 0;
449*f6dc9357SAndroid Build Coastguard Worker   UInt32 i;
450*f6dc9357SAndroid Build Coastguard Worker   for (i = 0; i < numItems; i++)
451*f6dc9357SAndroid Build Coastguard Worker     totalSize += _blocks[allFilesMode ? i : indices[i]].Data.GetPos();
452*f6dc9357SAndroid Build Coastguard Worker   RINOK(extractCallback->SetTotal(totalSize))
453*f6dc9357SAndroid Build Coastguard Worker 
454*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr2_Create<ICompressProgressInfo, CLocalProgress> lps;
455*f6dc9357SAndroid Build Coastguard Worker   lps->Init(extractCallback, false);
456*f6dc9357SAndroid Build Coastguard Worker 
457*f6dc9357SAndroid Build Coastguard Worker   for (i = 0;; i++)
458*f6dc9357SAndroid Build Coastguard Worker   {
459*f6dc9357SAndroid Build Coastguard Worker     lps->InSize = lps->OutSize;
460*f6dc9357SAndroid Build Coastguard Worker     RINOK(lps->SetCur())
461*f6dc9357SAndroid Build Coastguard Worker     if (i >= numItems)
462*f6dc9357SAndroid Build Coastguard Worker       break;
463*f6dc9357SAndroid Build Coastguard Worker     const UInt32 index = allFilesMode ? i : indices[i];
464*f6dc9357SAndroid Build Coastguard Worker     const CByteDynamicBuffer &data = _blocks[index].Data;
465*f6dc9357SAndroid Build Coastguard Worker     lps->OutSize += data.GetPos();
466*f6dc9357SAndroid Build Coastguard Worker     {
467*f6dc9357SAndroid Build Coastguard Worker       CMyComPtr<ISequentialOutStream> realOutStream;
468*f6dc9357SAndroid Build Coastguard Worker       const Int32 askMode = testMode ?
469*f6dc9357SAndroid Build Coastguard Worker           NExtract::NAskMode::kTest :
470*f6dc9357SAndroid Build Coastguard Worker           NExtract::NAskMode::kExtract;
471*f6dc9357SAndroid Build Coastguard Worker       RINOK(extractCallback->GetStream(index, &realOutStream, askMode))
472*f6dc9357SAndroid Build Coastguard Worker       if (!testMode && !realOutStream)
473*f6dc9357SAndroid Build Coastguard Worker         continue;
474*f6dc9357SAndroid Build Coastguard Worker       RINOK(extractCallback->PrepareOperation(askMode))
475*f6dc9357SAndroid Build Coastguard Worker       if (realOutStream)
476*f6dc9357SAndroid Build Coastguard Worker         RINOK(WriteStream(realOutStream, (const Byte *)data, data.GetPos()))
477*f6dc9357SAndroid Build Coastguard Worker     }
478*f6dc9357SAndroid Build Coastguard Worker     RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK))
479*f6dc9357SAndroid Build Coastguard Worker   }
480*f6dc9357SAndroid Build Coastguard Worker 
481*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
482*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_END
483*f6dc9357SAndroid Build Coastguard Worker }
484*f6dc9357SAndroid Build Coastguard Worker 
485*f6dc9357SAndroid Build Coastguard Worker // k_Signature: { ':' }
486*f6dc9357SAndroid Build Coastguard Worker 
487*f6dc9357SAndroid Build Coastguard Worker REGISTER_ARC_I_NO_SIG(
488*f6dc9357SAndroid Build Coastguard Worker   "IHex", "ihex", NULL, 0xCD,
489*f6dc9357SAndroid Build Coastguard Worker   0,
490*f6dc9357SAndroid Build Coastguard Worker   NArcInfoFlags::kStartOpen,
491*f6dc9357SAndroid Build Coastguard Worker   IsArc_Ihex)
492*f6dc9357SAndroid Build Coastguard Worker 
493*f6dc9357SAndroid Build Coastguard Worker }}
494