xref: /aosp_15_r20/external/lzma/CPP/7zip/Archive/DmgHandler.cpp (revision f6dc9357d832569d4d1f5d24eacdb3935a1ae8e6)
1*f6dc9357SAndroid Build Coastguard Worker // DmgHandler.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/Alloc.h"
6*f6dc9357SAndroid Build Coastguard Worker #include "../../../C/CpuArch.h"
7*f6dc9357SAndroid Build Coastguard Worker 
8*f6dc9357SAndroid Build Coastguard Worker #include "../../Common/AutoPtr.h"
9*f6dc9357SAndroid Build Coastguard Worker #include "../../Common/ComTry.h"
10*f6dc9357SAndroid Build Coastguard Worker #include "../../Common/IntToString.h"
11*f6dc9357SAndroid Build Coastguard Worker #include "../../Common/MyBuffer2.h"
12*f6dc9357SAndroid Build Coastguard Worker #include "../../Common/MyXml.h"
13*f6dc9357SAndroid Build Coastguard Worker #include "../../Common/UTFConvert.h"
14*f6dc9357SAndroid Build Coastguard Worker 
15*f6dc9357SAndroid Build Coastguard Worker #include "../../Windows/PropVariant.h"
16*f6dc9357SAndroid Build Coastguard Worker 
17*f6dc9357SAndroid Build Coastguard Worker #include "../Common/LimitedStreams.h"
18*f6dc9357SAndroid Build Coastguard Worker #include "../Common/ProgressUtils.h"
19*f6dc9357SAndroid Build Coastguard Worker #include "../Common/RegisterArc.h"
20*f6dc9357SAndroid Build Coastguard Worker #include "../Common/StreamObjects.h"
21*f6dc9357SAndroid Build Coastguard Worker #include "../Common/StreamUtils.h"
22*f6dc9357SAndroid Build Coastguard Worker 
23*f6dc9357SAndroid Build Coastguard Worker #include "../Compress/BZip2Decoder.h"
24*f6dc9357SAndroid Build Coastguard Worker #include "../Compress/CopyCoder.h"
25*f6dc9357SAndroid Build Coastguard Worker #include "../Compress/LzfseDecoder.h"
26*f6dc9357SAndroid Build Coastguard Worker #include "../Compress/XzDecoder.h"
27*f6dc9357SAndroid Build Coastguard Worker #include "../Compress/ZlibDecoder.h"
28*f6dc9357SAndroid Build Coastguard Worker 
29*f6dc9357SAndroid Build Coastguard Worker #include "Common/OutStreamWithCRC.h"
30*f6dc9357SAndroid Build Coastguard Worker 
31*f6dc9357SAndroid Build Coastguard Worker // #define DMG_SHOW_RAW
32*f6dc9357SAndroid Build Coastguard Worker 
33*f6dc9357SAndroid Build Coastguard Worker // #define SHOW_DEBUG_INFO
34*f6dc9357SAndroid Build Coastguard Worker 
35*f6dc9357SAndroid Build Coastguard Worker /* for debug only: we can use block cache also for METHOD_COPY blocks.
36*f6dc9357SAndroid Build Coastguard Worker    It can reduce the number of Stream->Read() requests.
37*f6dc9357SAndroid Build Coastguard Worker    But it can increase memory usage.
38*f6dc9357SAndroid Build Coastguard Worker    Note: METHOD_COPY blocks are not fused usually.
39*f6dc9357SAndroid Build Coastguard Worker    But if METHOD_COPY blocks is fused in some dmg example,
40*f6dc9357SAndroid Build Coastguard Worker    block size can exceed k_Chunk_Size_MAX.
41*f6dc9357SAndroid Build Coastguard Worker    So we don't use cache for METHOD_COPY block, if (block_size > k_Chunk_Size_MAX)
42*f6dc9357SAndroid Build Coastguard Worker */
43*f6dc9357SAndroid Build Coastguard Worker // for debug only:
44*f6dc9357SAndroid Build Coastguard Worker // #define Z7_DMG_USE_CACHE_FOR_COPY_BLOCKS
45*f6dc9357SAndroid Build Coastguard Worker 
46*f6dc9357SAndroid Build Coastguard Worker #ifdef SHOW_DEBUG_INFO
47*f6dc9357SAndroid Build Coastguard Worker #include <stdio.h>
48*f6dc9357SAndroid Build Coastguard Worker #define PRF(x) x
49*f6dc9357SAndroid Build Coastguard Worker #else
50*f6dc9357SAndroid Build Coastguard Worker #define PRF(x)
51*f6dc9357SAndroid Build Coastguard Worker #endif
52*f6dc9357SAndroid Build Coastguard Worker 
53*f6dc9357SAndroid Build Coastguard Worker 
54*f6dc9357SAndroid Build Coastguard Worker #define Get16(p) GetBe16(p)
55*f6dc9357SAndroid Build Coastguard Worker #define Get32(p) GetBe32(p)
56*f6dc9357SAndroid Build Coastguard Worker #define Get64(p) GetBe64(p)
57*f6dc9357SAndroid Build Coastguard Worker 
58*f6dc9357SAndroid Build Coastguard Worker #define Get32a(p) GetBe32a(p)
59*f6dc9357SAndroid Build Coastguard Worker #define Get64a(p) GetBe64a(p)
60*f6dc9357SAndroid Build Coastguard Worker 
61*f6dc9357SAndroid Build Coastguard Worker Byte *Base64ToBin(Byte *dest, const char *src);
62*f6dc9357SAndroid Build Coastguard Worker 
63*f6dc9357SAndroid Build Coastguard Worker namespace NArchive {
64*f6dc9357SAndroid Build Coastguard Worker namespace NDmg {
65*f6dc9357SAndroid Build Coastguard Worker 
66*f6dc9357SAndroid Build Coastguard Worker // allocation limits for compressed blocks for GetStream() interface:
67*f6dc9357SAndroid Build Coastguard Worker static const unsigned k_NumChunks_MAX = 128;
68*f6dc9357SAndroid Build Coastguard Worker static const size_t k_Chunk_Size_MAX = (size_t)1 << 28;
69*f6dc9357SAndroid Build Coastguard Worker // 256 MB cache for 32-bit:
70*f6dc9357SAndroid Build Coastguard Worker //   4 GB cache for 64-bit:
71*f6dc9357SAndroid Build Coastguard Worker static const size_t k_Chunks_TotalSize_MAX = (size_t)1 << (sizeof(size_t) + 24);
72*f6dc9357SAndroid Build Coastguard Worker 
73*f6dc9357SAndroid Build Coastguard Worker // 2 GB limit for 32-bit:
74*f6dc9357SAndroid Build Coastguard Worker // 4 GB limit for 64-bit:
75*f6dc9357SAndroid Build Coastguard Worker // that limit can be increased for 64-bit mode, if there are such dmg files
76*f6dc9357SAndroid Build Coastguard Worker static const size_t k_XmlSize_MAX =
77*f6dc9357SAndroid Build Coastguard Worker     ((size_t)1 << (sizeof(size_t) / 4 + 30)) - 256;
78*f6dc9357SAndroid Build Coastguard Worker 
79*f6dc9357SAndroid Build Coastguard Worker static const UInt32  METHOD_ZERO_0  = 0; // sparse
80*f6dc9357SAndroid Build Coastguard Worker static const UInt32  METHOD_COPY    = 1;
81*f6dc9357SAndroid Build Coastguard Worker static const UInt32  METHOD_ZERO_2  = 2; // sparse : without file CRC calculation
82*f6dc9357SAndroid Build Coastguard Worker static const UInt32  METHOD_ADC     = 0x80000004;
83*f6dc9357SAndroid Build Coastguard Worker static const UInt32  METHOD_ZLIB    = 0x80000005;
84*f6dc9357SAndroid Build Coastguard Worker static const UInt32  METHOD_BZIP2   = 0x80000006;
85*f6dc9357SAndroid Build Coastguard Worker static const UInt32  METHOD_LZFSE   = 0x80000007;
86*f6dc9357SAndroid Build Coastguard Worker static const UInt32  METHOD_XZ      = 0x80000008;
87*f6dc9357SAndroid Build Coastguard Worker static const UInt32  METHOD_COMMENT = 0x7FFFFFFE; // is used to comment "+beg" and "+end" in extra field.
88*f6dc9357SAndroid Build Coastguard Worker static const UInt32  METHOD_END     = 0xFFFFFFFF;
89*f6dc9357SAndroid Build Coastguard Worker 
90*f6dc9357SAndroid Build Coastguard Worker 
91*f6dc9357SAndroid Build Coastguard Worker struct CBlock
92*f6dc9357SAndroid Build Coastguard Worker {
93*f6dc9357SAndroid Build Coastguard Worker   UInt32 Type;
94*f6dc9357SAndroid Build Coastguard Worker   UInt64 UnpPos;
95*f6dc9357SAndroid Build Coastguard Worker   // UInt64 UnpSize;
96*f6dc9357SAndroid Build Coastguard Worker   UInt64 PackPos;
97*f6dc9357SAndroid Build Coastguard Worker   UInt64 PackSize;
98*f6dc9357SAndroid Build Coastguard Worker 
NeedCrcNArchive::NDmg::CBlock99*f6dc9357SAndroid Build Coastguard Worker   bool NeedCrc() const { return Type != METHOD_ZERO_2; }
IsZeroMethodNArchive::NDmg::CBlock100*f6dc9357SAndroid Build Coastguard Worker   bool IsZeroMethod() const
101*f6dc9357SAndroid Build Coastguard Worker   {
102*f6dc9357SAndroid Build Coastguard Worker     return (Type & ~(UInt32)METHOD_ZERO_2) == 0;
103*f6dc9357SAndroid Build Coastguard Worker     // return Type == METHOD_ZERO_0 || Type == METHOD_ZERO_2;
104*f6dc9357SAndroid Build Coastguard Worker   }
105*f6dc9357SAndroid Build Coastguard Worker 
IsClusteredMethodNArchive::NDmg::CBlock106*f6dc9357SAndroid Build Coastguard Worker   bool IsClusteredMethod() const
107*f6dc9357SAndroid Build Coastguard Worker   {
108*f6dc9357SAndroid Build Coastguard Worker     // most of dmg files have non-fused COPY_METHOD blocks.
109*f6dc9357SAndroid Build Coastguard Worker     // so we don't exclude COPY_METHOD blocks when we try to detect size of cluster.
110*f6dc9357SAndroid Build Coastguard Worker     return !IsZeroMethod(); // include COPY_METHOD blocks.
111*f6dc9357SAndroid Build Coastguard Worker     // Type > METHOD_ZERO_2; // for debug: exclude COPY_METHOD blocks.
112*f6dc9357SAndroid Build Coastguard Worker   }
113*f6dc9357SAndroid Build Coastguard Worker 
NeedAllocateBufferNArchive::NDmg::CBlock114*f6dc9357SAndroid Build Coastguard Worker   bool NeedAllocateBuffer() const
115*f6dc9357SAndroid Build Coastguard Worker   {
116*f6dc9357SAndroid Build Coastguard Worker     return
117*f6dc9357SAndroid Build Coastguard Worker #ifdef Z7_DMG_USE_CACHE_FOR_COPY_BLOCKS
118*f6dc9357SAndroid Build Coastguard Worker         !IsZeroMethod();
119*f6dc9357SAndroid Build Coastguard Worker #else
120*f6dc9357SAndroid Build Coastguard Worker         Type > METHOD_ZERO_2;
121*f6dc9357SAndroid Build Coastguard Worker         // !IsZeroMethod() && Type != METHOD_COPY;
122*f6dc9357SAndroid Build Coastguard Worker #endif
123*f6dc9357SAndroid Build Coastguard Worker   }
124*f6dc9357SAndroid Build Coastguard Worker   // we don't store non-data blocks now
125*f6dc9357SAndroid Build Coastguard Worker   // bool ThereAreDataInBlock() const { return Type != METHOD_COMMENT && Type != METHOD_END; }
126*f6dc9357SAndroid Build Coastguard Worker };
127*f6dc9357SAndroid Build Coastguard Worker 
128*f6dc9357SAndroid Build Coastguard Worker static const UInt32 kCheckSumType_CRC = 2;
129*f6dc9357SAndroid Build Coastguard Worker static const unsigned kChecksumSize_Max = 0x80;
130*f6dc9357SAndroid Build Coastguard Worker 
131*f6dc9357SAndroid Build Coastguard Worker struct CChecksum
132*f6dc9357SAndroid Build Coastguard Worker {
133*f6dc9357SAndroid Build Coastguard Worker   UInt32 Type;
134*f6dc9357SAndroid Build Coastguard Worker   UInt32 NumBits;
135*f6dc9357SAndroid Build Coastguard Worker   Byte Data[kChecksumSize_Max];
136*f6dc9357SAndroid Build Coastguard Worker 
IsCrc32NArchive::NDmg::CChecksum137*f6dc9357SAndroid Build Coastguard Worker   bool IsCrc32() const { return Type == kCheckSumType_CRC && NumBits == 32; }
GetCrc32NArchive::NDmg::CChecksum138*f6dc9357SAndroid Build Coastguard Worker   UInt32 GetCrc32() const { return Get32(Data); }
139*f6dc9357SAndroid Build Coastguard Worker   void Parse(const Byte *p);
140*f6dc9357SAndroid Build Coastguard Worker 
141*f6dc9357SAndroid Build Coastguard Worker   void PrintType(AString &s) const;
142*f6dc9357SAndroid Build Coastguard Worker   void Print(AString &s) const;
143*f6dc9357SAndroid Build Coastguard Worker   void Print_with_Name(AString &s) const;
144*f6dc9357SAndroid Build Coastguard Worker   void AddToComment(AString &s, const char *name) const;
145*f6dc9357SAndroid Build Coastguard Worker };
146*f6dc9357SAndroid Build Coastguard Worker 
Parse(const Byte * p)147*f6dc9357SAndroid Build Coastguard Worker void CChecksum::Parse(const Byte *p)
148*f6dc9357SAndroid Build Coastguard Worker {
149*f6dc9357SAndroid Build Coastguard Worker   Type = Get32(p);
150*f6dc9357SAndroid Build Coastguard Worker   NumBits = Get32(p + 4);
151*f6dc9357SAndroid Build Coastguard Worker   memcpy(Data, p + 8, kChecksumSize_Max);
152*f6dc9357SAndroid Build Coastguard Worker }
153*f6dc9357SAndroid Build Coastguard Worker 
154*f6dc9357SAndroid Build Coastguard Worker 
PrintType(AString & s) const155*f6dc9357SAndroid Build Coastguard Worker void CChecksum::PrintType(AString &s) const
156*f6dc9357SAndroid Build Coastguard Worker {
157*f6dc9357SAndroid Build Coastguard Worker   if (NumBits == 0)
158*f6dc9357SAndroid Build Coastguard Worker     return;
159*f6dc9357SAndroid Build Coastguard Worker   if (IsCrc32())
160*f6dc9357SAndroid Build Coastguard Worker     s += "CRC";
161*f6dc9357SAndroid Build Coastguard Worker   else
162*f6dc9357SAndroid Build Coastguard Worker   {
163*f6dc9357SAndroid Build Coastguard Worker     s += "Checksum";
164*f6dc9357SAndroid Build Coastguard Worker     s.Add_UInt32(Type);
165*f6dc9357SAndroid Build Coastguard Worker     s.Add_Minus();
166*f6dc9357SAndroid Build Coastguard Worker     s.Add_UInt32(NumBits);
167*f6dc9357SAndroid Build Coastguard Worker   }
168*f6dc9357SAndroid Build Coastguard Worker }
169*f6dc9357SAndroid Build Coastguard Worker 
Print(AString & s) const170*f6dc9357SAndroid Build Coastguard Worker void CChecksum::Print(AString &s) const
171*f6dc9357SAndroid Build Coastguard Worker {
172*f6dc9357SAndroid Build Coastguard Worker   if (NumBits == 0)
173*f6dc9357SAndroid Build Coastguard Worker     return;
174*f6dc9357SAndroid Build Coastguard Worker   char temp[kChecksumSize_Max * 2 + 2];
175*f6dc9357SAndroid Build Coastguard Worker   /*
176*f6dc9357SAndroid Build Coastguard Worker   if (IsCrc32())
177*f6dc9357SAndroid Build Coastguard Worker     ConvertUInt32ToHex8Digits(GetCrc32(), temp);
178*f6dc9357SAndroid Build Coastguard Worker   else
179*f6dc9357SAndroid Build Coastguard Worker   */
180*f6dc9357SAndroid Build Coastguard Worker   {
181*f6dc9357SAndroid Build Coastguard Worker     UInt32 numBits = kChecksumSize_Max * 8;
182*f6dc9357SAndroid Build Coastguard Worker     if (numBits > NumBits)
183*f6dc9357SAndroid Build Coastguard Worker         numBits = NumBits;
184*f6dc9357SAndroid Build Coastguard Worker     const unsigned numBytes = (numBits + 7) >> 3;
185*f6dc9357SAndroid Build Coastguard Worker     if (numBytes <= 8)
186*f6dc9357SAndroid Build Coastguard Worker       ConvertDataToHex_Upper(temp, Data, numBytes);
187*f6dc9357SAndroid Build Coastguard Worker     else
188*f6dc9357SAndroid Build Coastguard Worker       ConvertDataToHex_Lower(temp, Data, numBytes);
189*f6dc9357SAndroid Build Coastguard Worker   }
190*f6dc9357SAndroid Build Coastguard Worker   s += temp;
191*f6dc9357SAndroid Build Coastguard Worker }
192*f6dc9357SAndroid Build Coastguard Worker 
Print_with_Name(AString & s) const193*f6dc9357SAndroid Build Coastguard Worker void CChecksum::Print_with_Name(AString &s) const
194*f6dc9357SAndroid Build Coastguard Worker {
195*f6dc9357SAndroid Build Coastguard Worker   if (NumBits == 0)
196*f6dc9357SAndroid Build Coastguard Worker     return;
197*f6dc9357SAndroid Build Coastguard Worker   PrintType(s);
198*f6dc9357SAndroid Build Coastguard Worker   s += ": ";
199*f6dc9357SAndroid Build Coastguard Worker   Print(s);
200*f6dc9357SAndroid Build Coastguard Worker }
201*f6dc9357SAndroid Build Coastguard Worker 
AddToComment_Prop(AString & s,const char * name,const char * val)202*f6dc9357SAndroid Build Coastguard Worker static void AddToComment_Prop(AString &s, const char *name, const char *val)
203*f6dc9357SAndroid Build Coastguard Worker {
204*f6dc9357SAndroid Build Coastguard Worker   s += name;
205*f6dc9357SAndroid Build Coastguard Worker   s += ": ";
206*f6dc9357SAndroid Build Coastguard Worker   s += val;
207*f6dc9357SAndroid Build Coastguard Worker   s.Add_LF();
208*f6dc9357SAndroid Build Coastguard Worker }
209*f6dc9357SAndroid Build Coastguard Worker 
AddToComment(AString & s,const char * name) const210*f6dc9357SAndroid Build Coastguard Worker void CChecksum::AddToComment(AString &s, const char *name) const
211*f6dc9357SAndroid Build Coastguard Worker {
212*f6dc9357SAndroid Build Coastguard Worker   AString s2;
213*f6dc9357SAndroid Build Coastguard Worker   Print_with_Name(s2);
214*f6dc9357SAndroid Build Coastguard Worker   if (!s2.IsEmpty())
215*f6dc9357SAndroid Build Coastguard Worker     AddToComment_Prop(s, name, s2);
216*f6dc9357SAndroid Build Coastguard Worker }
217*f6dc9357SAndroid Build Coastguard Worker 
218*f6dc9357SAndroid Build Coastguard Worker 
219*f6dc9357SAndroid Build Coastguard Worker struct CFile
220*f6dc9357SAndroid Build Coastguard Worker {
221*f6dc9357SAndroid Build Coastguard Worker   UInt64 Size;
222*f6dc9357SAndroid Build Coastguard Worker   CRecordVector<CBlock> Blocks;
223*f6dc9357SAndroid Build Coastguard Worker   UInt64 PackSize;
224*f6dc9357SAndroid Build Coastguard Worker   UInt64 StartPackPos;
225*f6dc9357SAndroid Build Coastguard Worker   UInt64 BlockSize_MAX;
226*f6dc9357SAndroid Build Coastguard Worker   UInt64 StartUnpackSector;  // unpack sector position of this file from all files
227*f6dc9357SAndroid Build Coastguard Worker   UInt64 NumUnpackSectors;
228*f6dc9357SAndroid Build Coastguard Worker   Int32 Descriptor;
229*f6dc9357SAndroid Build Coastguard Worker   bool IsCorrect;
230*f6dc9357SAndroid Build Coastguard Worker   bool FullFileChecksum;
231*f6dc9357SAndroid Build Coastguard Worker   AString Name;
232*f6dc9357SAndroid Build Coastguard Worker   // AString Id;
233*f6dc9357SAndroid Build Coastguard Worker   CChecksum Checksum;
234*f6dc9357SAndroid Build Coastguard Worker 
GetUnpackSize_of_BlockNArchive::NDmg::CFile235*f6dc9357SAndroid Build Coastguard Worker   UInt64 GetUnpackSize_of_Block(unsigned blockIndex) const
236*f6dc9357SAndroid Build Coastguard Worker   {
237*f6dc9357SAndroid Build Coastguard Worker     return (blockIndex == Blocks.Size() - 1 ?
238*f6dc9357SAndroid Build Coastguard Worker         Size : Blocks[blockIndex + 1].UnpPos) - Blocks[blockIndex].UnpPos;
239*f6dc9357SAndroid Build Coastguard Worker   }
240*f6dc9357SAndroid Build Coastguard Worker 
CFileNArchive::NDmg::CFile241*f6dc9357SAndroid Build Coastguard Worker   CFile():
242*f6dc9357SAndroid Build Coastguard Worker       Size(0),
243*f6dc9357SAndroid Build Coastguard Worker       PackSize(0),
244*f6dc9357SAndroid Build Coastguard Worker       StartPackPos(0),
245*f6dc9357SAndroid Build Coastguard Worker       BlockSize_MAX(0),
246*f6dc9357SAndroid Build Coastguard Worker       StartUnpackSector(0),
247*f6dc9357SAndroid Build Coastguard Worker       NumUnpackSectors(0),
248*f6dc9357SAndroid Build Coastguard Worker       Descriptor(0),
249*f6dc9357SAndroid Build Coastguard Worker       IsCorrect(false),
250*f6dc9357SAndroid Build Coastguard Worker       FullFileChecksum(false)
251*f6dc9357SAndroid Build Coastguard Worker   {
252*f6dc9357SAndroid Build Coastguard Worker     Checksum.Type = 0;
253*f6dc9357SAndroid Build Coastguard Worker     Checksum.NumBits = 0;
254*f6dc9357SAndroid Build Coastguard Worker   }
255*f6dc9357SAndroid Build Coastguard Worker   HRESULT Parse(const Byte *p, UInt32 size);
256*f6dc9357SAndroid Build Coastguard Worker };
257*f6dc9357SAndroid Build Coastguard Worker 
258*f6dc9357SAndroid Build Coastguard Worker #ifdef DMG_SHOW_RAW
259*f6dc9357SAndroid Build Coastguard Worker struct CExtraFile
260*f6dc9357SAndroid Build Coastguard Worker {
261*f6dc9357SAndroid Build Coastguard Worker   CByteBuffer Data;
262*f6dc9357SAndroid Build Coastguard Worker   AString Name;
263*f6dc9357SAndroid Build Coastguard Worker };
264*f6dc9357SAndroid Build Coastguard Worker #endif
265*f6dc9357SAndroid Build Coastguard Worker 
266*f6dc9357SAndroid Build Coastguard Worker 
AddToComment_UInt64(AString & s,UInt64 v,const char * name)267*f6dc9357SAndroid Build Coastguard Worker static void AddToComment_UInt64(AString &s, UInt64 v, const char *name)
268*f6dc9357SAndroid Build Coastguard Worker {
269*f6dc9357SAndroid Build Coastguard Worker   s += name;
270*f6dc9357SAndroid Build Coastguard Worker   s += ": ";
271*f6dc9357SAndroid Build Coastguard Worker   s.Add_UInt64(v);
272*f6dc9357SAndroid Build Coastguard Worker   s.Add_LF();
273*f6dc9357SAndroid Build Coastguard Worker }
274*f6dc9357SAndroid Build Coastguard Worker 
275*f6dc9357SAndroid Build Coastguard Worker struct CForkPair
276*f6dc9357SAndroid Build Coastguard Worker {
277*f6dc9357SAndroid Build Coastguard Worker   UInt64 Offset;
278*f6dc9357SAndroid Build Coastguard Worker   UInt64 Len;
279*f6dc9357SAndroid Build Coastguard Worker 
280*f6dc9357SAndroid Build Coastguard Worker   // (p) is aligned for 8-bytes
ParseNArchive::NDmg::CForkPair281*f6dc9357SAndroid Build Coastguard Worker   void Parse(const Byte *p)
282*f6dc9357SAndroid Build Coastguard Worker   {
283*f6dc9357SAndroid Build Coastguard Worker     Offset = Get64a(p);
284*f6dc9357SAndroid Build Coastguard Worker     Len = Get64a(p + 8);
285*f6dc9357SAndroid Build Coastguard Worker   }
286*f6dc9357SAndroid Build Coastguard Worker 
GetEndPosNArchive::NDmg::CForkPair287*f6dc9357SAndroid Build Coastguard Worker   bool GetEndPos(UInt64 &endPos)
288*f6dc9357SAndroid Build Coastguard Worker   {
289*f6dc9357SAndroid Build Coastguard Worker     endPos = Offset + Len;
290*f6dc9357SAndroid Build Coastguard Worker     return endPos >= Offset;
291*f6dc9357SAndroid Build Coastguard Worker   }
292*f6dc9357SAndroid Build Coastguard Worker 
UpdateTopNArchive::NDmg::CForkPair293*f6dc9357SAndroid Build Coastguard Worker   bool UpdateTop(UInt64 limit, UInt64 &top)
294*f6dc9357SAndroid Build Coastguard Worker   {
295*f6dc9357SAndroid Build Coastguard Worker     if (Offset > limit || Len > limit - Offset)
296*f6dc9357SAndroid Build Coastguard Worker       return false;
297*f6dc9357SAndroid Build Coastguard Worker     const UInt64 top2 = Offset + Len;
298*f6dc9357SAndroid Build Coastguard Worker     if (top <= top2)
299*f6dc9357SAndroid Build Coastguard Worker       top = top2;
300*f6dc9357SAndroid Build Coastguard Worker     return true;
301*f6dc9357SAndroid Build Coastguard Worker   }
302*f6dc9357SAndroid Build Coastguard Worker 
303*f6dc9357SAndroid Build Coastguard Worker   void Print(AString &s, const char *name) const;
304*f6dc9357SAndroid Build Coastguard Worker };
305*f6dc9357SAndroid Build Coastguard Worker 
Print(AString & s,const char * name) const306*f6dc9357SAndroid Build Coastguard Worker void CForkPair::Print(AString &s, const char *name) const
307*f6dc9357SAndroid Build Coastguard Worker {
308*f6dc9357SAndroid Build Coastguard Worker   if (Offset != 0 || Len != 0)
309*f6dc9357SAndroid Build Coastguard Worker   {
310*f6dc9357SAndroid Build Coastguard Worker     s += name;  s.Add_Minus();  AddToComment_UInt64(s, Offset, "offset");
311*f6dc9357SAndroid Build Coastguard Worker     s += name;  s.Add_Minus();  AddToComment_UInt64(s, Len,    "length");
312*f6dc9357SAndroid Build Coastguard Worker   }
313*f6dc9357SAndroid Build Coastguard Worker }
314*f6dc9357SAndroid Build Coastguard Worker 
315*f6dc9357SAndroid Build Coastguard Worker 
316*f6dc9357SAndroid Build Coastguard Worker Z7_CLASS_IMP_CHandler_IInArchive_1(
317*f6dc9357SAndroid Build Coastguard Worker   IInArchiveGetStream
318*f6dc9357SAndroid Build Coastguard Worker )
319*f6dc9357SAndroid Build Coastguard Worker   bool _masterCrcError;
320*f6dc9357SAndroid Build Coastguard Worker   bool _headersError;
321*f6dc9357SAndroid Build Coastguard Worker   bool _dataForkError;
322*f6dc9357SAndroid Build Coastguard Worker   bool _rsrcMode_wasUsed;
323*f6dc9357SAndroid Build Coastguard Worker 
324*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr<IInStream> _inStream;
325*f6dc9357SAndroid Build Coastguard Worker   CObjectVector<CFile> _files;
326*f6dc9357SAndroid Build Coastguard Worker 
327*f6dc9357SAndroid Build Coastguard Worker   // UInt32 _dataStartOffset;
328*f6dc9357SAndroid Build Coastguard Worker   UInt64 _startPos;
329*f6dc9357SAndroid Build Coastguard Worker   UInt64 _phySize;
330*f6dc9357SAndroid Build Coastguard Worker 
331*f6dc9357SAndroid Build Coastguard Worker   AString _name;
332*f6dc9357SAndroid Build Coastguard Worker 
333*f6dc9357SAndroid Build Coastguard Worker   CForkPair _dataForkPair;
334*f6dc9357SAndroid Build Coastguard Worker   CForkPair rsrcPair, xmlPair, blobPair;
335*f6dc9357SAndroid Build Coastguard Worker 
336*f6dc9357SAndroid Build Coastguard Worker   // UInt64 _runningDataForkOffset;
337*f6dc9357SAndroid Build Coastguard Worker   // UInt32 _segmentNumber;
338*f6dc9357SAndroid Build Coastguard Worker   // UInt32 _segmentCount;
339*f6dc9357SAndroid Build Coastguard Worker   UInt64 _numSectors; // total unpacked number of sectors
340*f6dc9357SAndroid Build Coastguard Worker   Byte _segmentGUID[16];
341*f6dc9357SAndroid Build Coastguard Worker 
342*f6dc9357SAndroid Build Coastguard Worker   CChecksum _dataForkChecksum;
343*f6dc9357SAndroid Build Coastguard Worker   CChecksum _masterChecksum;
344*f6dc9357SAndroid Build Coastguard Worker 
345*f6dc9357SAndroid Build Coastguard Worker #ifdef DMG_SHOW_RAW
346*f6dc9357SAndroid Build Coastguard Worker   CObjectVector<CExtraFile> _extras;
347*f6dc9357SAndroid Build Coastguard Worker #endif
348*f6dc9357SAndroid Build Coastguard Worker 
349*f6dc9357SAndroid Build Coastguard Worker   HRESULT ReadData(IInStream *stream, const CForkPair &pair, CByteBuffer &buf);
350*f6dc9357SAndroid Build Coastguard Worker   bool ParseBlob(const CByteBuffer &data);
351*f6dc9357SAndroid Build Coastguard Worker   HRESULT Open2(IInStream *stream, IArchiveOpenCallback *openArchiveCallback);
352*f6dc9357SAndroid Build Coastguard Worker   HRESULT Extract(IInStream *stream);
353*f6dc9357SAndroid Build Coastguard Worker };
354*f6dc9357SAndroid Build Coastguard Worker 
355*f6dc9357SAndroid Build Coastguard Worker 
356*f6dc9357SAndroid Build Coastguard Worker struct CMethods
357*f6dc9357SAndroid Build Coastguard Worker {
358*f6dc9357SAndroid Build Coastguard Worker   CRecordVector<UInt32> Types;
359*f6dc9357SAndroid Build Coastguard Worker 
360*f6dc9357SAndroid Build Coastguard Worker   void Update(const CFile &file);
361*f6dc9357SAndroid Build Coastguard Worker   void AddToString(AString &s) const;
362*f6dc9357SAndroid Build Coastguard Worker };
363*f6dc9357SAndroid Build Coastguard Worker 
Update(const CFile & file)364*f6dc9357SAndroid Build Coastguard Worker void CMethods::Update(const CFile &file)
365*f6dc9357SAndroid Build Coastguard Worker {
366*f6dc9357SAndroid Build Coastguard Worker   FOR_VECTOR (i, file.Blocks)
367*f6dc9357SAndroid Build Coastguard Worker   {
368*f6dc9357SAndroid Build Coastguard Worker     if (Types.Size() >= (1 << 8))
369*f6dc9357SAndroid Build Coastguard Worker       break;
370*f6dc9357SAndroid Build Coastguard Worker     Types.AddToUniqueSorted(file.Blocks[i].Type);
371*f6dc9357SAndroid Build Coastguard Worker   }
372*f6dc9357SAndroid Build Coastguard Worker }
373*f6dc9357SAndroid Build Coastguard Worker 
AddToString(AString & res) const374*f6dc9357SAndroid Build Coastguard Worker void CMethods::AddToString(AString &res) const
375*f6dc9357SAndroid Build Coastguard Worker {
376*f6dc9357SAndroid Build Coastguard Worker   FOR_VECTOR (i, Types)
377*f6dc9357SAndroid Build Coastguard Worker   {
378*f6dc9357SAndroid Build Coastguard Worker     const UInt32 type = Types[i];
379*f6dc9357SAndroid Build Coastguard Worker     /*
380*f6dc9357SAndroid Build Coastguard Worker     if (type == METHOD_COMMENT || type == METHOD_END)
381*f6dc9357SAndroid Build Coastguard Worker       continue;
382*f6dc9357SAndroid Build Coastguard Worker     */
383*f6dc9357SAndroid Build Coastguard Worker     char buf[16];
384*f6dc9357SAndroid Build Coastguard Worker     const char *s;
385*f6dc9357SAndroid Build Coastguard Worker     switch (type)
386*f6dc9357SAndroid Build Coastguard Worker     {
387*f6dc9357SAndroid Build Coastguard Worker       // case METHOD_COMMENT: s = "Comment"; break;
388*f6dc9357SAndroid Build Coastguard Worker       case METHOD_ZERO_0: s = "Zero0"; break;
389*f6dc9357SAndroid Build Coastguard Worker       case METHOD_ZERO_2: s = "Zero2"; break;
390*f6dc9357SAndroid Build Coastguard Worker       case METHOD_COPY:   s = "Copy";  break;
391*f6dc9357SAndroid Build Coastguard Worker       case METHOD_ADC:    s = "ADC";   break;
392*f6dc9357SAndroid Build Coastguard Worker       case METHOD_ZLIB:   s = "ZLIB";  break;
393*f6dc9357SAndroid Build Coastguard Worker       case METHOD_BZIP2:  s = "BZip2"; break;
394*f6dc9357SAndroid Build Coastguard Worker       case METHOD_LZFSE:  s = "LZFSE"; break;
395*f6dc9357SAndroid Build Coastguard Worker       case METHOD_XZ:     s = "XZ";    break;
396*f6dc9357SAndroid Build Coastguard Worker       default: ConvertUInt32ToHex(type, buf); s = buf;
397*f6dc9357SAndroid Build Coastguard Worker     }
398*f6dc9357SAndroid Build Coastguard Worker     res.Add_OptSpaced(s);
399*f6dc9357SAndroid Build Coastguard Worker   }
400*f6dc9357SAndroid Build Coastguard Worker }
401*f6dc9357SAndroid Build Coastguard Worker 
402*f6dc9357SAndroid Build Coastguard Worker 
403*f6dc9357SAndroid Build Coastguard Worker 
404*f6dc9357SAndroid Build Coastguard Worker struct CAppleName
405*f6dc9357SAndroid Build Coastguard Worker {
406*f6dc9357SAndroid Build Coastguard Worker   bool IsFs;
407*f6dc9357SAndroid Build Coastguard Worker   const char *Ext;
408*f6dc9357SAndroid Build Coastguard Worker   const char *AppleName;
409*f6dc9357SAndroid Build Coastguard Worker };
410*f6dc9357SAndroid Build Coastguard Worker 
411*f6dc9357SAndroid Build Coastguard Worker static const CAppleName k_Names[] =
412*f6dc9357SAndroid Build Coastguard Worker {
413*f6dc9357SAndroid Build Coastguard Worker   { true,  "hfs",  "Apple_HFS" },
414*f6dc9357SAndroid Build Coastguard Worker   { true,  "hfsx", "Apple_HFSX" },
415*f6dc9357SAndroid Build Coastguard Worker   { true,  "ufs",  "Apple_UFS" },
416*f6dc9357SAndroid Build Coastguard Worker   { true,  "apfs", "Apple_APFS" },
417*f6dc9357SAndroid Build Coastguard Worker   { true,  "iso",  "Apple_ISO" },
418*f6dc9357SAndroid Build Coastguard Worker 
419*f6dc9357SAndroid Build Coastguard Worker   // efi_sys partition is FAT32, but it's not main file. So we use (IsFs = false)
420*f6dc9357SAndroid Build Coastguard Worker   { false,  "efi_sys", "C12A7328-F81F-11D2-BA4B-00A0C93EC93B" },
421*f6dc9357SAndroid Build Coastguard Worker 
422*f6dc9357SAndroid Build Coastguard Worker   { false, "free", "Apple_Free" },
423*f6dc9357SAndroid Build Coastguard Worker   { false, "ddm",  "DDM" },
424*f6dc9357SAndroid Build Coastguard Worker   { false, NULL,   "Apple_partition_map" },
425*f6dc9357SAndroid Build Coastguard Worker   { false, NULL,   " GPT " },
426*f6dc9357SAndroid Build Coastguard Worker     /* " GPT " is substring of full name entry in dmg that contains
427*f6dc9357SAndroid Build Coastguard Worker          some small metadata GPT entry. It's not real FS entry:
428*f6dc9357SAndroid Build Coastguard Worker       "Primary GPT Header",
429*f6dc9357SAndroid Build Coastguard Worker       "Primary GPT Table"
430*f6dc9357SAndroid Build Coastguard Worker       "Backup GPT Header",
431*f6dc9357SAndroid Build Coastguard Worker       "Backup GPT Table",
432*f6dc9357SAndroid Build Coastguard Worker     */
433*f6dc9357SAndroid Build Coastguard Worker   { false, NULL,   "MBR" },
434*f6dc9357SAndroid Build Coastguard Worker   { false, NULL,   "Driver" },
435*f6dc9357SAndroid Build Coastguard Worker   { false, NULL,   "Patches" }
436*f6dc9357SAndroid Build Coastguard Worker };
437*f6dc9357SAndroid Build Coastguard Worker 
438*f6dc9357SAndroid Build Coastguard Worker static const unsigned kNumAppleNames = Z7_ARRAY_SIZE(k_Names);
439*f6dc9357SAndroid Build Coastguard Worker 
440*f6dc9357SAndroid Build Coastguard Worker const char *Find_Apple_FS_Ext(const AString &name);
Find_Apple_FS_Ext(const AString & name)441*f6dc9357SAndroid Build Coastguard Worker const char *Find_Apple_FS_Ext(const AString &name)
442*f6dc9357SAndroid Build Coastguard Worker {
443*f6dc9357SAndroid Build Coastguard Worker   for (unsigned i = 0; i < kNumAppleNames; i++)
444*f6dc9357SAndroid Build Coastguard Worker   {
445*f6dc9357SAndroid Build Coastguard Worker     const CAppleName &a = k_Names[i];
446*f6dc9357SAndroid Build Coastguard Worker     if (a.Ext)
447*f6dc9357SAndroid Build Coastguard Worker       if (name == a.AppleName)
448*f6dc9357SAndroid Build Coastguard Worker         return a.Ext;
449*f6dc9357SAndroid Build Coastguard Worker   }
450*f6dc9357SAndroid Build Coastguard Worker   return NULL;
451*f6dc9357SAndroid Build Coastguard Worker }
452*f6dc9357SAndroid Build Coastguard Worker 
453*f6dc9357SAndroid Build Coastguard Worker 
454*f6dc9357SAndroid Build Coastguard Worker bool Is_Apple_FS_Or_Unknown(const AString &name);
Is_Apple_FS_Or_Unknown(const AString & name)455*f6dc9357SAndroid Build Coastguard Worker bool Is_Apple_FS_Or_Unknown(const AString &name)
456*f6dc9357SAndroid Build Coastguard Worker {
457*f6dc9357SAndroid Build Coastguard Worker   for (unsigned i = 0; i < kNumAppleNames; i++)
458*f6dc9357SAndroid Build Coastguard Worker   {
459*f6dc9357SAndroid Build Coastguard Worker     const CAppleName &a = k_Names[i];
460*f6dc9357SAndroid Build Coastguard Worker     // if (name.Find(a.AppleName) >= 0)
461*f6dc9357SAndroid Build Coastguard Worker     if (strstr(name, a.AppleName))
462*f6dc9357SAndroid Build Coastguard Worker       return a.IsFs;
463*f6dc9357SAndroid Build Coastguard Worker   }
464*f6dc9357SAndroid Build Coastguard Worker   return true;
465*f6dc9357SAndroid Build Coastguard Worker }
466*f6dc9357SAndroid Build Coastguard Worker 
467*f6dc9357SAndroid Build Coastguard Worker 
468*f6dc9357SAndroid Build Coastguard Worker 
469*f6dc9357SAndroid Build Coastguard Worker // define it for debug only:
470*f6dc9357SAndroid Build Coastguard Worker // #define Z7_DMG_SINGLE_FILE_MODE
471*f6dc9357SAndroid Build Coastguard Worker 
472*f6dc9357SAndroid Build Coastguard Worker static const Byte kProps[] =
473*f6dc9357SAndroid Build Coastguard Worker {
474*f6dc9357SAndroid Build Coastguard Worker   kpidPath,
475*f6dc9357SAndroid Build Coastguard Worker   kpidSize,
476*f6dc9357SAndroid Build Coastguard Worker   kpidPackSize,
477*f6dc9357SAndroid Build Coastguard Worker   kpidComment,
478*f6dc9357SAndroid Build Coastguard Worker   kpidMethod,
479*f6dc9357SAndroid Build Coastguard Worker   kpidNumBlocks,
480*f6dc9357SAndroid Build Coastguard Worker   kpidClusterSize,
481*f6dc9357SAndroid Build Coastguard Worker   kpidChecksum,
482*f6dc9357SAndroid Build Coastguard Worker   kpidCRC,
483*f6dc9357SAndroid Build Coastguard Worker   kpidId
484*f6dc9357SAndroid Build Coastguard Worker   // kpidOffset
485*f6dc9357SAndroid Build Coastguard Worker #ifdef Z7_DMG_SINGLE_FILE_MODE
486*f6dc9357SAndroid Build Coastguard Worker   , kpidPosition
487*f6dc9357SAndroid Build Coastguard Worker #endif
488*f6dc9357SAndroid Build Coastguard Worker };
489*f6dc9357SAndroid Build Coastguard Worker 
490*f6dc9357SAndroid Build Coastguard Worker IMP_IInArchive_Props
491*f6dc9357SAndroid Build Coastguard Worker 
492*f6dc9357SAndroid Build Coastguard Worker static const Byte kArcProps[] =
493*f6dc9357SAndroid Build Coastguard Worker {
494*f6dc9357SAndroid Build Coastguard Worker   kpidMethod,
495*f6dc9357SAndroid Build Coastguard Worker   kpidNumBlocks,
496*f6dc9357SAndroid Build Coastguard Worker   kpidClusterSize,
497*f6dc9357SAndroid Build Coastguard Worker   kpidComment
498*f6dc9357SAndroid Build Coastguard Worker };
499*f6dc9357SAndroid Build Coastguard Worker 
500*f6dc9357SAndroid Build Coastguard Worker 
Z7_COM7F_IMF(CHandler::GetArchiveProperty (PROPID propID,PROPVARIANT * value))501*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
502*f6dc9357SAndroid Build Coastguard Worker {
503*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_BEGIN
504*f6dc9357SAndroid Build Coastguard Worker   NWindows::NCOM::CPropVariant prop;
505*f6dc9357SAndroid Build Coastguard Worker   switch (propID)
506*f6dc9357SAndroid Build Coastguard Worker   {
507*f6dc9357SAndroid Build Coastguard Worker     case kpidMethod:
508*f6dc9357SAndroid Build Coastguard Worker     {
509*f6dc9357SAndroid Build Coastguard Worker       CMethods m;
510*f6dc9357SAndroid Build Coastguard Worker       CRecordVector<UInt32> ChecksumTypes;
511*f6dc9357SAndroid Build Coastguard Worker       {
512*f6dc9357SAndroid Build Coastguard Worker         FOR_VECTOR (i, _files)
513*f6dc9357SAndroid Build Coastguard Worker         {
514*f6dc9357SAndroid Build Coastguard Worker           const CFile &file = _files[i];
515*f6dc9357SAndroid Build Coastguard Worker           m.Update(file);
516*f6dc9357SAndroid Build Coastguard Worker           if (ChecksumTypes.Size() < (1 << 8))
517*f6dc9357SAndroid Build Coastguard Worker             ChecksumTypes.AddToUniqueSorted(file.Checksum.Type);
518*f6dc9357SAndroid Build Coastguard Worker         }
519*f6dc9357SAndroid Build Coastguard Worker       }
520*f6dc9357SAndroid Build Coastguard Worker       AString s;
521*f6dc9357SAndroid Build Coastguard Worker       m.AddToString(s);
522*f6dc9357SAndroid Build Coastguard Worker 
523*f6dc9357SAndroid Build Coastguard Worker       FOR_VECTOR (i, ChecksumTypes)
524*f6dc9357SAndroid Build Coastguard Worker       {
525*f6dc9357SAndroid Build Coastguard Worker         const UInt32 type = ChecksumTypes[i];
526*f6dc9357SAndroid Build Coastguard Worker         switch (type)
527*f6dc9357SAndroid Build Coastguard Worker         {
528*f6dc9357SAndroid Build Coastguard Worker           case kCheckSumType_CRC:
529*f6dc9357SAndroid Build Coastguard Worker             s.Add_OptSpaced("CRC");
530*f6dc9357SAndroid Build Coastguard Worker             break;
531*f6dc9357SAndroid Build Coastguard Worker           default:
532*f6dc9357SAndroid Build Coastguard Worker             s.Add_OptSpaced("Checksum");
533*f6dc9357SAndroid Build Coastguard Worker             s.Add_UInt32(type);
534*f6dc9357SAndroid Build Coastguard Worker         }
535*f6dc9357SAndroid Build Coastguard Worker       }
536*f6dc9357SAndroid Build Coastguard Worker 
537*f6dc9357SAndroid Build Coastguard Worker       if (!s.IsEmpty())
538*f6dc9357SAndroid Build Coastguard Worker         prop = s;
539*f6dc9357SAndroid Build Coastguard Worker       break;
540*f6dc9357SAndroid Build Coastguard Worker     }
541*f6dc9357SAndroid Build Coastguard Worker     case kpidNumBlocks:
542*f6dc9357SAndroid Build Coastguard Worker     {
543*f6dc9357SAndroid Build Coastguard Worker       UInt64 numBlocks = 0;
544*f6dc9357SAndroid Build Coastguard Worker       FOR_VECTOR (i, _files)
545*f6dc9357SAndroid Build Coastguard Worker         numBlocks += _files[i].Blocks.Size();
546*f6dc9357SAndroid Build Coastguard Worker       prop = numBlocks;
547*f6dc9357SAndroid Build Coastguard Worker       break;
548*f6dc9357SAndroid Build Coastguard Worker     }
549*f6dc9357SAndroid Build Coastguard Worker     case kpidClusterSize:
550*f6dc9357SAndroid Build Coastguard Worker     {
551*f6dc9357SAndroid Build Coastguard Worker       UInt64 blockSize_MAX = 0;
552*f6dc9357SAndroid Build Coastguard Worker       FOR_VECTOR (i, _files)
553*f6dc9357SAndroid Build Coastguard Worker       {
554*f6dc9357SAndroid Build Coastguard Worker         const UInt64 a = _files[i].BlockSize_MAX;
555*f6dc9357SAndroid Build Coastguard Worker         if (blockSize_MAX < a)
556*f6dc9357SAndroid Build Coastguard Worker             blockSize_MAX = a;
557*f6dc9357SAndroid Build Coastguard Worker       }
558*f6dc9357SAndroid Build Coastguard Worker       prop = blockSize_MAX;
559*f6dc9357SAndroid Build Coastguard Worker       break;
560*f6dc9357SAndroid Build Coastguard Worker     }
561*f6dc9357SAndroid Build Coastguard Worker     case kpidMainSubfile:
562*f6dc9357SAndroid Build Coastguard Worker     {
563*f6dc9357SAndroid Build Coastguard Worker       int mainIndex = -1;
564*f6dc9357SAndroid Build Coastguard Worker       FOR_VECTOR (i, _files)
565*f6dc9357SAndroid Build Coastguard Worker       {
566*f6dc9357SAndroid Build Coastguard Worker         if (Is_Apple_FS_Or_Unknown(_files[i].Name))
567*f6dc9357SAndroid Build Coastguard Worker         {
568*f6dc9357SAndroid Build Coastguard Worker           if (mainIndex != -1)
569*f6dc9357SAndroid Build Coastguard Worker           {
570*f6dc9357SAndroid Build Coastguard Worker             mainIndex = -1;
571*f6dc9357SAndroid Build Coastguard Worker             break;
572*f6dc9357SAndroid Build Coastguard Worker           }
573*f6dc9357SAndroid Build Coastguard Worker           mainIndex = (int)i;
574*f6dc9357SAndroid Build Coastguard Worker         }
575*f6dc9357SAndroid Build Coastguard Worker       }
576*f6dc9357SAndroid Build Coastguard Worker       if (mainIndex != -1)
577*f6dc9357SAndroid Build Coastguard Worker         prop = (UInt32)(Int32)mainIndex;
578*f6dc9357SAndroid Build Coastguard Worker       break;
579*f6dc9357SAndroid Build Coastguard Worker     }
580*f6dc9357SAndroid Build Coastguard Worker     case kpidWarning:
581*f6dc9357SAndroid Build Coastguard Worker       if (_masterCrcError)
582*f6dc9357SAndroid Build Coastguard Worker         prop = "Master CRC error";
583*f6dc9357SAndroid Build Coastguard Worker       break;
584*f6dc9357SAndroid Build Coastguard Worker 
585*f6dc9357SAndroid Build Coastguard Worker     case kpidWarningFlags:
586*f6dc9357SAndroid Build Coastguard Worker     {
587*f6dc9357SAndroid Build Coastguard Worker       UInt32 v = 0;
588*f6dc9357SAndroid Build Coastguard Worker       if (_headersError)  v |= kpv_ErrorFlags_HeadersError;
589*f6dc9357SAndroid Build Coastguard Worker       if (_dataForkError) v |= kpv_ErrorFlags_CrcError;
590*f6dc9357SAndroid Build Coastguard Worker       if (v != 0)
591*f6dc9357SAndroid Build Coastguard Worker         prop = v;
592*f6dc9357SAndroid Build Coastguard Worker       break;
593*f6dc9357SAndroid Build Coastguard Worker     }
594*f6dc9357SAndroid Build Coastguard Worker 
595*f6dc9357SAndroid Build Coastguard Worker     case kpidOffset: prop = _startPos; break;
596*f6dc9357SAndroid Build Coastguard Worker     case kpidPhySize: prop = _phySize; break;
597*f6dc9357SAndroid Build Coastguard Worker 
598*f6dc9357SAndroid Build Coastguard Worker     case kpidComment:
599*f6dc9357SAndroid Build Coastguard Worker     {
600*f6dc9357SAndroid Build Coastguard Worker       AString s;
601*f6dc9357SAndroid Build Coastguard Worker       if (!_name.IsEmpty())
602*f6dc9357SAndroid Build Coastguard Worker         AddToComment_Prop(s, "Name", _name);
603*f6dc9357SAndroid Build Coastguard Worker       AddToComment_UInt64(s, _numSectors << 9, "unpack-size");
604*f6dc9357SAndroid Build Coastguard Worker       {
605*f6dc9357SAndroid Build Coastguard Worker         char temp[sizeof(_segmentGUID) * 2 + 2];
606*f6dc9357SAndroid Build Coastguard Worker         ConvertDataToHex_Lower(temp, _segmentGUID, sizeof(_segmentGUID));
607*f6dc9357SAndroid Build Coastguard Worker         AddToComment_Prop(s, "ID", temp);
608*f6dc9357SAndroid Build Coastguard Worker       }
609*f6dc9357SAndroid Build Coastguard Worker       _masterChecksum.AddToComment(s, "master-checksum");
610*f6dc9357SAndroid Build Coastguard Worker       _dataForkChecksum.AddToComment(s, "pack-checksum");
611*f6dc9357SAndroid Build Coastguard Worker       {
612*f6dc9357SAndroid Build Coastguard Worker         /*
613*f6dc9357SAndroid Build Coastguard Worker         if (_dataStartOffset != 0)
614*f6dc9357SAndroid Build Coastguard Worker           AddToComment_UInt64(s, _dataStartOffset,    "payload-start-offset");
615*f6dc9357SAndroid Build Coastguard Worker         */
616*f6dc9357SAndroid Build Coastguard Worker         // if (_dataForkPair.Offset != 0)
617*f6dc9357SAndroid Build Coastguard Worker         _dataForkPair.Print(s, "pack");
618*f6dc9357SAndroid Build Coastguard Worker         rsrcPair.Print(s, "rsrc");
619*f6dc9357SAndroid Build Coastguard Worker         xmlPair.Print(s, "xml");
620*f6dc9357SAndroid Build Coastguard Worker         blobPair.Print(s, "blob");
621*f6dc9357SAndroid Build Coastguard Worker       }
622*f6dc9357SAndroid Build Coastguard Worker       if (_rsrcMode_wasUsed)
623*f6dc9357SAndroid Build Coastguard Worker         s += "RSRC_MODE\n";
624*f6dc9357SAndroid Build Coastguard Worker       if (!s.IsEmpty())
625*f6dc9357SAndroid Build Coastguard Worker         prop = s;
626*f6dc9357SAndroid Build Coastguard Worker     }
627*f6dc9357SAndroid Build Coastguard Worker     break;
628*f6dc9357SAndroid Build Coastguard Worker 
629*f6dc9357SAndroid Build Coastguard Worker     case kpidName:
630*f6dc9357SAndroid Build Coastguard Worker       if (!_name.IsEmpty())
631*f6dc9357SAndroid Build Coastguard Worker         prop = _name + ".dmg";
632*f6dc9357SAndroid Build Coastguard Worker       break;
633*f6dc9357SAndroid Build Coastguard Worker   }
634*f6dc9357SAndroid Build Coastguard Worker   prop.Detach(value);
635*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
636*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_END
637*f6dc9357SAndroid Build Coastguard Worker }
638*f6dc9357SAndroid Build Coastguard Worker 
639*f6dc9357SAndroid Build Coastguard Worker IMP_IInArchive_ArcProps
640*f6dc9357SAndroid Build Coastguard Worker 
641*f6dc9357SAndroid Build Coastguard Worker 
642*f6dc9357SAndroid Build Coastguard Worker 
643*f6dc9357SAndroid Build Coastguard Worker static const UInt64 kSectorNumber_LIMIT = (UInt64)1 << (63 - 9);
644*f6dc9357SAndroid Build Coastguard Worker 
Parse(const Byte * p,UInt32 size)645*f6dc9357SAndroid Build Coastguard Worker HRESULT CFile::Parse(const Byte *p, UInt32 size)
646*f6dc9357SAndroid Build Coastguard Worker {
647*f6dc9357SAndroid Build Coastguard Worker   // CFile was initialized to default values: 0 in size variables and (IsCorrect == false)
648*f6dc9357SAndroid Build Coastguard Worker   const unsigned kHeadSize = 0xCC;
649*f6dc9357SAndroid Build Coastguard Worker   if (size < kHeadSize)
650*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
651*f6dc9357SAndroid Build Coastguard Worker   if (Get32(p) != 0x6D697368) // "mish" signature
652*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
653*f6dc9357SAndroid Build Coastguard Worker   if (Get32(p + 4) != 1) // version
654*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
655*f6dc9357SAndroid Build Coastguard Worker 
656*f6dc9357SAndroid Build Coastguard Worker   StartUnpackSector = Get64(p + 8);
657*f6dc9357SAndroid Build Coastguard Worker   NumUnpackSectors = Get64(p + 0x10);
658*f6dc9357SAndroid Build Coastguard Worker   StartPackPos = Get64(p + 0x18);
659*f6dc9357SAndroid Build Coastguard Worker 
660*f6dc9357SAndroid Build Coastguard Worker #ifdef SHOW_DEBUG_INFO
661*f6dc9357SAndroid Build Coastguard Worker   /* the number of sectors that must be allocated.
662*f6dc9357SAndroid Build Coastguard Worker      ==  0x208 for 256KB clusters
663*f6dc9357SAndroid Build Coastguard Worker      ==  0x808 for   1MB clusters
664*f6dc9357SAndroid Build Coastguard Worker      == 0x1001 for   1MB clusters in some example
665*f6dc9357SAndroid Build Coastguard Worker   */
666*f6dc9357SAndroid Build Coastguard Worker   const UInt32 decompressedBufRequested = Get32(p + 0x20);
667*f6dc9357SAndroid Build Coastguard Worker #endif
668*f6dc9357SAndroid Build Coastguard Worker 
669*f6dc9357SAndroid Build Coastguard Worker   // Descriptor is file index. usually started from -1
670*f6dc9357SAndroid Build Coastguard Worker   // in one dmg it was started from 0
671*f6dc9357SAndroid Build Coastguard Worker   Descriptor = (Int32)Get32(p + 0x24);
672*f6dc9357SAndroid Build Coastguard Worker   // char Reserved1[24];
673*f6dc9357SAndroid Build Coastguard Worker 
674*f6dc9357SAndroid Build Coastguard Worker   Checksum.Parse(p + 0x40);
675*f6dc9357SAndroid Build Coastguard Worker   PRF(printf("\n" " Checksum Type = %2u"
676*f6dc9357SAndroid Build Coastguard Worker         "\n StartUnpackSector = %8x"
677*f6dc9357SAndroid Build Coastguard Worker         "\n NumUnpackSectors  = %8x"
678*f6dc9357SAndroid Build Coastguard Worker         "\n StartPos = %8x"
679*f6dc9357SAndroid Build Coastguard Worker         "\n decompressedBufRequested=%8x"
680*f6dc9357SAndroid Build Coastguard Worker         "\n blocksDescriptor=%8x"
681*f6dc9357SAndroid Build Coastguard Worker         , (unsigned)Checksum.Type
682*f6dc9357SAndroid Build Coastguard Worker         , (unsigned)StartUnpackSector
683*f6dc9357SAndroid Build Coastguard Worker         , (unsigned)NumUnpackSectors
684*f6dc9357SAndroid Build Coastguard Worker         , (unsigned)StartPackPos
685*f6dc9357SAndroid Build Coastguard Worker         , (unsigned)decompressedBufRequested
686*f6dc9357SAndroid Build Coastguard Worker         , (unsigned)Descriptor
687*f6dc9357SAndroid Build Coastguard Worker     );)
688*f6dc9357SAndroid Build Coastguard Worker 
689*f6dc9357SAndroid Build Coastguard Worker   const UInt32 numBlocks = Get32(p + 0xC8);
690*f6dc9357SAndroid Build Coastguard Worker   const unsigned kRecordSize = 40;
691*f6dc9357SAndroid Build Coastguard Worker   if ((UInt64)numBlocks * kRecordSize + kHeadSize != size)
692*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
693*f6dc9357SAndroid Build Coastguard Worker 
694*f6dc9357SAndroid Build Coastguard Worker   Blocks.ClearAndReserve(numBlocks);
695*f6dc9357SAndroid Build Coastguard Worker   FullFileChecksum = true;
696*f6dc9357SAndroid Build Coastguard Worker   /* IsCorrect = false; by default
697*f6dc9357SAndroid Build Coastguard Worker      So we return S_OK, if we can ignore some error in headers.
698*f6dc9357SAndroid Build Coastguard Worker   */
699*f6dc9357SAndroid Build Coastguard Worker 
700*f6dc9357SAndroid Build Coastguard Worker   p += kHeadSize;
701*f6dc9357SAndroid Build Coastguard Worker   UInt32 i;
702*f6dc9357SAndroid Build Coastguard Worker 
703*f6dc9357SAndroid Build Coastguard Worker   for (i = 0; i < numBlocks; i++, p += kRecordSize)
704*f6dc9357SAndroid Build Coastguard Worker   {
705*f6dc9357SAndroid Build Coastguard Worker     CBlock b;
706*f6dc9357SAndroid Build Coastguard Worker     b.Type = Get32(p);
707*f6dc9357SAndroid Build Coastguard Worker     {
708*f6dc9357SAndroid Build Coastguard Worker       const UInt64 a = Get64(p + 0x08);
709*f6dc9357SAndroid Build Coastguard Worker       if (a >= kSectorNumber_LIMIT)
710*f6dc9357SAndroid Build Coastguard Worker         return S_OK;
711*f6dc9357SAndroid Build Coastguard Worker       b.UnpPos = a << 9;
712*f6dc9357SAndroid Build Coastguard Worker     }
713*f6dc9357SAndroid Build Coastguard Worker     UInt64 unpSize;
714*f6dc9357SAndroid Build Coastguard Worker     {
715*f6dc9357SAndroid Build Coastguard Worker       const UInt64 a = Get64(p + 0x10);
716*f6dc9357SAndroid Build Coastguard Worker       if (a >= kSectorNumber_LIMIT)
717*f6dc9357SAndroid Build Coastguard Worker         return S_OK;
718*f6dc9357SAndroid Build Coastguard Worker       unpSize = a << 9;
719*f6dc9357SAndroid Build Coastguard Worker     }
720*f6dc9357SAndroid Build Coastguard Worker     const UInt64 newSize = b.UnpPos + unpSize;
721*f6dc9357SAndroid Build Coastguard Worker     if (newSize >= ((UInt64)1 << 63))
722*f6dc9357SAndroid Build Coastguard Worker       return S_OK;
723*f6dc9357SAndroid Build Coastguard Worker 
724*f6dc9357SAndroid Build Coastguard Worker     b.PackPos  = Get64(p + 0x18);
725*f6dc9357SAndroid Build Coastguard Worker     b.PackSize = Get64(p + 0x20);
726*f6dc9357SAndroid Build Coastguard Worker     // b.PackPos can be 0 for some types. So we don't check it
727*f6dc9357SAndroid Build Coastguard Worker     if (b.UnpPos != Size)
728*f6dc9357SAndroid Build Coastguard Worker       return S_OK;
729*f6dc9357SAndroid Build Coastguard Worker 
730*f6dc9357SAndroid Build Coastguard Worker     PRF(printf("\nType=%8x  comment=%8x  uPos=%8x  uSize=%7x  pPos=%8x  pSize=%7x",
731*f6dc9357SAndroid Build Coastguard Worker         (unsigned)b.Type, Get32(p + 4), (unsigned)b.UnpPos, (unsigned)unpSize, (unsigned)b.PackPos, (unsigned)b.PackSize));
732*f6dc9357SAndroid Build Coastguard Worker 
733*f6dc9357SAndroid Build Coastguard Worker     if (b.Type == METHOD_COMMENT)
734*f6dc9357SAndroid Build Coastguard Worker     {
735*f6dc9357SAndroid Build Coastguard Worker       // some files contain 2 comment block records:
736*f6dc9357SAndroid Build Coastguard Worker       // record[0]     : Type=METHOD_COMMENT, comment_field = "+beg"
737*f6dc9357SAndroid Build Coastguard Worker       // record[num-2] : Type=METHOD_COMMENT, comment_field = "+end"
738*f6dc9357SAndroid Build Coastguard Worker       // we skip these useless records.
739*f6dc9357SAndroid Build Coastguard Worker       continue;
740*f6dc9357SAndroid Build Coastguard Worker     }
741*f6dc9357SAndroid Build Coastguard Worker     if (b.Type == METHOD_END)
742*f6dc9357SAndroid Build Coastguard Worker       break;
743*f6dc9357SAndroid Build Coastguard Worker 
744*f6dc9357SAndroid Build Coastguard Worker     // we add only blocks that have non empty unpacked data:
745*f6dc9357SAndroid Build Coastguard Worker     if (unpSize != 0)
746*f6dc9357SAndroid Build Coastguard Worker     {
747*f6dc9357SAndroid Build Coastguard Worker       const UInt64 k_max_pos = (UInt64)1 << 63;
748*f6dc9357SAndroid Build Coastguard Worker       if (b.PackPos >= k_max_pos ||
749*f6dc9357SAndroid Build Coastguard Worker           b.PackSize >= k_max_pos - b.PackPos)
750*f6dc9357SAndroid Build Coastguard Worker         return S_OK;
751*f6dc9357SAndroid Build Coastguard Worker 
752*f6dc9357SAndroid Build Coastguard Worker       /* we don't count non-ZERO blocks here, because
753*f6dc9357SAndroid Build Coastguard Worker          ZERO blocks in dmg files are not limited by some cluster size.
754*f6dc9357SAndroid Build Coastguard Worker          note: COPY blocks also sometimes are fused to larger blocks.
755*f6dc9357SAndroid Build Coastguard Worker       */
756*f6dc9357SAndroid Build Coastguard Worker       if (b.IsClusteredMethod())
757*f6dc9357SAndroid Build Coastguard Worker       if (BlockSize_MAX < unpSize)
758*f6dc9357SAndroid Build Coastguard Worker           BlockSize_MAX = unpSize;
759*f6dc9357SAndroid Build Coastguard Worker 
760*f6dc9357SAndroid Build Coastguard Worker       PackSize += b.PackSize;
761*f6dc9357SAndroid Build Coastguard Worker       if (!b.NeedCrc())
762*f6dc9357SAndroid Build Coastguard Worker         FullFileChecksum = false;
763*f6dc9357SAndroid Build Coastguard Worker       Blocks.AddInReserved(b);
764*f6dc9357SAndroid Build Coastguard Worker       Size = newSize;
765*f6dc9357SAndroid Build Coastguard Worker     }
766*f6dc9357SAndroid Build Coastguard Worker   }
767*f6dc9357SAndroid Build Coastguard Worker 
768*f6dc9357SAndroid Build Coastguard Worker   PRF(printf("\n");)
769*f6dc9357SAndroid Build Coastguard Worker 
770*f6dc9357SAndroid Build Coastguard Worker   if (i != numBlocks - 1)
771*f6dc9357SAndroid Build Coastguard Worker   {
772*f6dc9357SAndroid Build Coastguard Worker     // return S_FALSE;
773*f6dc9357SAndroid Build Coastguard Worker     return S_OK;
774*f6dc9357SAndroid Build Coastguard Worker   }
775*f6dc9357SAndroid Build Coastguard Worker 
776*f6dc9357SAndroid Build Coastguard Worker   if ((Size >> 9) == NumUnpackSectors)
777*f6dc9357SAndroid Build Coastguard Worker     IsCorrect = true;
778*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
779*f6dc9357SAndroid Build Coastguard Worker }
780*f6dc9357SAndroid Build Coastguard Worker 
781*f6dc9357SAndroid Build Coastguard Worker 
FindKeyPair(const CXmlItem & item,const char * key,const char * nextTag)782*f6dc9357SAndroid Build Coastguard Worker static const CXmlItem *FindKeyPair(const CXmlItem &item, const char *key, const char *nextTag)
783*f6dc9357SAndroid Build Coastguard Worker {
784*f6dc9357SAndroid Build Coastguard Worker   for (unsigned i = 0; i + 1 < item.SubItems.Size(); i++)
785*f6dc9357SAndroid Build Coastguard Worker   {
786*f6dc9357SAndroid Build Coastguard Worker     const CXmlItem &si = item.SubItems[i];
787*f6dc9357SAndroid Build Coastguard Worker     if (si.IsTagged("key") && si.GetSubString() == key)
788*f6dc9357SAndroid Build Coastguard Worker     {
789*f6dc9357SAndroid Build Coastguard Worker       const CXmlItem *si_1 = &item.SubItems[i + 1];
790*f6dc9357SAndroid Build Coastguard Worker       if (si_1->IsTagged(nextTag))
791*f6dc9357SAndroid Build Coastguard Worker         return si_1;
792*f6dc9357SAndroid Build Coastguard Worker     }
793*f6dc9357SAndroid Build Coastguard Worker   }
794*f6dc9357SAndroid Build Coastguard Worker   return NULL;
795*f6dc9357SAndroid Build Coastguard Worker }
796*f6dc9357SAndroid Build Coastguard Worker 
GetStringFromKeyPair(const CXmlItem & item,const char * key,const char * nextTag)797*f6dc9357SAndroid Build Coastguard Worker static const AString *GetStringFromKeyPair(const CXmlItem &item, const char *key, const char *nextTag)
798*f6dc9357SAndroid Build Coastguard Worker {
799*f6dc9357SAndroid Build Coastguard Worker   const CXmlItem *si_1 = FindKeyPair(item, key, nextTag);
800*f6dc9357SAndroid Build Coastguard Worker   if (si_1)
801*f6dc9357SAndroid Build Coastguard Worker     return si_1->GetSubStringPtr();
802*f6dc9357SAndroid Build Coastguard Worker   return NULL;
803*f6dc9357SAndroid Build Coastguard Worker }
804*f6dc9357SAndroid Build Coastguard Worker 
805*f6dc9357SAndroid Build Coastguard Worker static const Byte k_Signature[] = { 'k','o','l','y', 0, 0, 0, 4, 0, 0, 2, 0 };
806*f6dc9357SAndroid Build Coastguard Worker 
IsKoly(const Byte * p)807*f6dc9357SAndroid Build Coastguard Worker static inline bool IsKoly(const Byte *p)
808*f6dc9357SAndroid Build Coastguard Worker {
809*f6dc9357SAndroid Build Coastguard Worker   return memcmp(p, k_Signature, Z7_ARRAY_SIZE(k_Signature)) == 0;
810*f6dc9357SAndroid Build Coastguard Worker   /*
811*f6dc9357SAndroid Build Coastguard Worker   if (Get32(p) != 0x6B6F6C79) // "koly" signature
812*f6dc9357SAndroid Build Coastguard Worker     return false;
813*f6dc9357SAndroid Build Coastguard Worker   if (Get32(p + 4) != 4) // version
814*f6dc9357SAndroid Build Coastguard Worker     return false;
815*f6dc9357SAndroid Build Coastguard Worker   if (Get32(p + 8) != HEADER_SIZE)
816*f6dc9357SAndroid Build Coastguard Worker     return false;
817*f6dc9357SAndroid Build Coastguard Worker   return true;
818*f6dc9357SAndroid Build Coastguard Worker   */
819*f6dc9357SAndroid Build Coastguard Worker }
820*f6dc9357SAndroid Build Coastguard Worker 
821*f6dc9357SAndroid Build Coastguard Worker 
ReadData(IInStream * stream,const CForkPair & pair,CByteBuffer & buf)822*f6dc9357SAndroid Build Coastguard Worker HRESULT CHandler::ReadData(IInStream *stream, const CForkPair &pair, CByteBuffer &buf)
823*f6dc9357SAndroid Build Coastguard Worker {
824*f6dc9357SAndroid Build Coastguard Worker   size_t size = (size_t)pair.Len;
825*f6dc9357SAndroid Build Coastguard Worker   if (size != pair.Len)
826*f6dc9357SAndroid Build Coastguard Worker     return E_OUTOFMEMORY;
827*f6dc9357SAndroid Build Coastguard Worker   buf.Alloc(size);
828*f6dc9357SAndroid Build Coastguard Worker   RINOK(InStream_SeekSet(stream, _startPos + pair.Offset))
829*f6dc9357SAndroid Build Coastguard Worker   return ReadStream_FALSE(stream, buf, size);
830*f6dc9357SAndroid Build Coastguard Worker }
831*f6dc9357SAndroid Build Coastguard Worker 
832*f6dc9357SAndroid Build Coastguard Worker 
833*f6dc9357SAndroid Build Coastguard Worker 
ParseBlob(const CByteBuffer & data)834*f6dc9357SAndroid Build Coastguard Worker bool CHandler::ParseBlob(const CByteBuffer &data)
835*f6dc9357SAndroid Build Coastguard Worker {
836*f6dc9357SAndroid Build Coastguard Worker   const unsigned kHeaderSize = 3 * 4;
837*f6dc9357SAndroid Build Coastguard Worker   if (data.Size() < kHeaderSize)
838*f6dc9357SAndroid Build Coastguard Worker     return false;
839*f6dc9357SAndroid Build Coastguard Worker   const Byte * const p = (const Byte *)data;
840*f6dc9357SAndroid Build Coastguard Worker   if (Get32a(p) != 0xfade0cc0) // CSMAGIC_EMBEDDED_SIGNATURE
841*f6dc9357SAndroid Build Coastguard Worker     return true;
842*f6dc9357SAndroid Build Coastguard Worker   const UInt32 size = Get32a(p + 4);
843*f6dc9357SAndroid Build Coastguard Worker   if (size != data.Size())
844*f6dc9357SAndroid Build Coastguard Worker     return false;
845*f6dc9357SAndroid Build Coastguard Worker   const UInt32 num = Get32a(p + 8);
846*f6dc9357SAndroid Build Coastguard Worker   if (num > (size - kHeaderSize) / 8)
847*f6dc9357SAndroid Build Coastguard Worker     return false;
848*f6dc9357SAndroid Build Coastguard Worker 
849*f6dc9357SAndroid Build Coastguard Worker   const UInt32 limit = num * 8 + kHeaderSize;
850*f6dc9357SAndroid Build Coastguard Worker   for (size_t i = kHeaderSize; i < limit; i += 8)
851*f6dc9357SAndroid Build Coastguard Worker   {
852*f6dc9357SAndroid Build Coastguard Worker     // type == 0 == CSSLOT_CODEDIRECTORY for CSMAGIC_CODEDIRECTORY item
853*f6dc9357SAndroid Build Coastguard Worker     // UInt32 type = Get32(p + i);
854*f6dc9357SAndroid Build Coastguard Worker     const UInt32 offset = Get32a(p + i + 4);
855*f6dc9357SAndroid Build Coastguard Worker     if (offset < limit || offset > size - 8)
856*f6dc9357SAndroid Build Coastguard Worker       return false;
857*f6dc9357SAndroid Build Coastguard Worker     // offset is not aligned for 4 here !!!
858*f6dc9357SAndroid Build Coastguard Worker     const Byte * const p2 = p + offset;
859*f6dc9357SAndroid Build Coastguard Worker     const UInt32 magic = Get32(p2);
860*f6dc9357SAndroid Build Coastguard Worker     const UInt32 len = Get32(p2 + 4);
861*f6dc9357SAndroid Build Coastguard Worker     if (size - offset < len || len < 8)
862*f6dc9357SAndroid Build Coastguard Worker       return false;
863*f6dc9357SAndroid Build Coastguard Worker 
864*f6dc9357SAndroid Build Coastguard Worker #ifdef DMG_SHOW_RAW
865*f6dc9357SAndroid Build Coastguard Worker     CExtraFile &extra = _extras.AddNew();
866*f6dc9357SAndroid Build Coastguard Worker     extra.Name = "_blob_";
867*f6dc9357SAndroid Build Coastguard Worker     extra.Data.CopyFrom(p2, len);
868*f6dc9357SAndroid Build Coastguard Worker #endif
869*f6dc9357SAndroid Build Coastguard Worker 
870*f6dc9357SAndroid Build Coastguard Worker     if (magic == 0xfade0c02) // CSMAGIC_CODEDIRECTORY
871*f6dc9357SAndroid Build Coastguard Worker     {
872*f6dc9357SAndroid Build Coastguard Worker #ifdef DMG_SHOW_RAW
873*f6dc9357SAndroid Build Coastguard Worker       extra.Name += "codedir";
874*f6dc9357SAndroid Build Coastguard Worker #endif
875*f6dc9357SAndroid Build Coastguard Worker 
876*f6dc9357SAndroid Build Coastguard Worker       if (len < 11 * 4)
877*f6dc9357SAndroid Build Coastguard Worker         return false;
878*f6dc9357SAndroid Build Coastguard Worker       const UInt32 idOffset = Get32(p2 + 5 * 4);
879*f6dc9357SAndroid Build Coastguard Worker       if (idOffset >= len)
880*f6dc9357SAndroid Build Coastguard Worker         return false;
881*f6dc9357SAndroid Build Coastguard Worker       UInt32 len2 = len - idOffset;
882*f6dc9357SAndroid Build Coastguard Worker       const UInt32 kNameLenMax = 1 << 8;
883*f6dc9357SAndroid Build Coastguard Worker       if (len2 > kNameLenMax)
884*f6dc9357SAndroid Build Coastguard Worker           len2 = kNameLenMax;
885*f6dc9357SAndroid Build Coastguard Worker       _name.SetFrom_CalcLen((const char *)(p2 + idOffset), len2);
886*f6dc9357SAndroid Build Coastguard Worker       /*
887*f6dc9357SAndroid Build Coastguard Worker       // #define kSecCodeSignatureHashSHA1     1
888*f6dc9357SAndroid Build Coastguard Worker       // #define kSecCodeSignatureHashSHA256   2
889*f6dc9357SAndroid Build Coastguard Worker       const UInt32 hashOffset    = Get32(p2 + 4 * 4);
890*f6dc9357SAndroid Build Coastguard Worker       const UInt32 nSpecialSlots = Get32(p2 + 6 * 4);
891*f6dc9357SAndroid Build Coastguard Worker       const UInt32 nCodeSlots    = Get32(p2 + 7 * 4);
892*f6dc9357SAndroid Build Coastguard Worker       const unsigned hashSize = p2[36];
893*f6dc9357SAndroid Build Coastguard Worker       const unsigned hashType = p2[37];
894*f6dc9357SAndroid Build Coastguard Worker       // const unsigned unused = p2[38];
895*f6dc9357SAndroid Build Coastguard Worker       const unsigned pageSize = p2[39];
896*f6dc9357SAndroid Build Coastguard Worker       */
897*f6dc9357SAndroid Build Coastguard Worker     }
898*f6dc9357SAndroid Build Coastguard Worker #ifdef DMG_SHOW_RAW
899*f6dc9357SAndroid Build Coastguard Worker     else if (magic == 0xfade0c01) extra.Name += "requirements";
900*f6dc9357SAndroid Build Coastguard Worker     else if (magic == 0xfade0b01) extra.Name += "signed";
901*f6dc9357SAndroid Build Coastguard Worker     else
902*f6dc9357SAndroid Build Coastguard Worker     {
903*f6dc9357SAndroid Build Coastguard Worker       char temp[16];
904*f6dc9357SAndroid Build Coastguard Worker       ConvertUInt32ToHex8Digits(magic, temp);
905*f6dc9357SAndroid Build Coastguard Worker       extra.Name += temp;
906*f6dc9357SAndroid Build Coastguard Worker     }
907*f6dc9357SAndroid Build Coastguard Worker #endif
908*f6dc9357SAndroid Build Coastguard Worker   }
909*f6dc9357SAndroid Build Coastguard Worker 
910*f6dc9357SAndroid Build Coastguard Worker   return true;
911*f6dc9357SAndroid Build Coastguard Worker }
912*f6dc9357SAndroid Build Coastguard Worker 
913*f6dc9357SAndroid Build Coastguard Worker 
914*f6dc9357SAndroid Build Coastguard Worker 
915*f6dc9357SAndroid Build Coastguard Worker 
Open2(IInStream * stream,IArchiveOpenCallback * openArchiveCallback)916*f6dc9357SAndroid Build Coastguard Worker HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *openArchiveCallback)
917*f6dc9357SAndroid Build Coastguard Worker {
918*f6dc9357SAndroid Build Coastguard Worker   /*
919*f6dc9357SAndroid Build Coastguard Worker   - usual dmg contains Koly Header at the end:
920*f6dc9357SAndroid Build Coastguard Worker   - rare case old dmg contains Koly Header at the begin.
921*f6dc9357SAndroid Build Coastguard Worker   */
922*f6dc9357SAndroid Build Coastguard Worker 
923*f6dc9357SAndroid Build Coastguard Worker   // _dataStartOffset = 0;
924*f6dc9357SAndroid Build Coastguard Worker   UInt64 fileSize;
925*f6dc9357SAndroid Build Coastguard Worker   RINOK(InStream_GetPos_GetSize(stream, _startPos, fileSize))
926*f6dc9357SAndroid Build Coastguard Worker 
927*f6dc9357SAndroid Build Coastguard Worker   const unsigned HEADER_SIZE = 0x200;
928*f6dc9357SAndroid Build Coastguard Worker   UInt64 buf[HEADER_SIZE / sizeof(UInt64)];
929*f6dc9357SAndroid Build Coastguard Worker   RINOK(ReadStream_FALSE(stream, buf, HEADER_SIZE))
930*f6dc9357SAndroid Build Coastguard Worker 
931*f6dc9357SAndroid Build Coastguard Worker   UInt64 headerPos;
932*f6dc9357SAndroid Build Coastguard Worker   bool front_Koly_Mode = false;
933*f6dc9357SAndroid Build Coastguard Worker 
934*f6dc9357SAndroid Build Coastguard Worker   /*
935*f6dc9357SAndroid Build Coastguard Worker   _dataForkChecksum.Offset ==   0 for koly-at-the-end
936*f6dc9357SAndroid Build Coastguard Worker   _dataForkChecksum.Offset == 512 for koly-at-the-start
937*f6dc9357SAndroid Build Coastguard Worker   so we can use (_dataForkChecksum.Offset) to detect "koly-at-the-start" mode
938*f6dc9357SAndroid Build Coastguard Worker   */
939*f6dc9357SAndroid Build Coastguard Worker 
940*f6dc9357SAndroid Build Coastguard Worker   if (IsKoly((const Byte *)(const void *)buf))
941*f6dc9357SAndroid Build Coastguard Worker   {
942*f6dc9357SAndroid Build Coastguard Worker     // it can be normal koly-at-the-end or koly-at-the-start
943*f6dc9357SAndroid Build Coastguard Worker     headerPos = _startPos;
944*f6dc9357SAndroid Build Coastguard Worker     /*
945*f6dc9357SAndroid Build Coastguard Worker     if (_startPos <= (1 << 8))
946*f6dc9357SAndroid Build Coastguard Worker     {
947*f6dc9357SAndroid Build Coastguard Worker       // we want to support front_Koly_Mode, even if there is
948*f6dc9357SAndroid Build Coastguard Worker       // some data before dmg file, like 128 bytes MacBin header
949*f6dc9357SAndroid Build Coastguard Worker       _dataStartOffset = HEADER_SIZE;
950*f6dc9357SAndroid Build Coastguard Worker       front_Koly_Mode = true;
951*f6dc9357SAndroid Build Coastguard Worker     }
952*f6dc9357SAndroid Build Coastguard Worker     */
953*f6dc9357SAndroid Build Coastguard Worker   }
954*f6dc9357SAndroid Build Coastguard Worker   else
955*f6dc9357SAndroid Build Coastguard Worker   {
956*f6dc9357SAndroid Build Coastguard Worker     /* we try to open in backward mode only for first attempt
957*f6dc9357SAndroid Build Coastguard Worker        when (_startPos == 0) */
958*f6dc9357SAndroid Build Coastguard Worker     if (_startPos != 0)
959*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
960*f6dc9357SAndroid Build Coastguard Worker     headerPos = fileSize;
961*f6dc9357SAndroid Build Coastguard Worker     if (headerPos < HEADER_SIZE)
962*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
963*f6dc9357SAndroid Build Coastguard Worker     headerPos -= HEADER_SIZE;
964*f6dc9357SAndroid Build Coastguard Worker     RINOK(InStream_SeekSet(stream, headerPos))
965*f6dc9357SAndroid Build Coastguard Worker     RINOK(ReadStream_FALSE(stream, buf, HEADER_SIZE))
966*f6dc9357SAndroid Build Coastguard Worker     if (!IsKoly((const Byte *)(const void *)buf))
967*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
968*f6dc9357SAndroid Build Coastguard Worker   }
969*f6dc9357SAndroid Build Coastguard Worker 
970*f6dc9357SAndroid Build Coastguard Worker   // UInt32 flags = Get32a((const Byte *)(const void *)buf + 12);
971*f6dc9357SAndroid Build Coastguard Worker   // _runningDataForkOffset = Get64a((const Byte *)(const void *)buf + 0x10);
972*f6dc9357SAndroid Build Coastguard Worker   _dataForkPair.Parse((const Byte *)(const void *)buf + 0x18);
973*f6dc9357SAndroid Build Coastguard Worker   rsrcPair.Parse((const Byte *)(const void *)buf + 0x28);
974*f6dc9357SAndroid Build Coastguard Worker   // _segmentNumber = Get32a(buf + 0x38); // 0 or 1
975*f6dc9357SAndroid Build Coastguard Worker   // _segmentCount = Get32a(buf + 0x3C);  // 0 (if not set) or 1
976*f6dc9357SAndroid Build Coastguard Worker   memcpy(_segmentGUID, (const Byte *)(const void *)buf + 0x40, 16);
977*f6dc9357SAndroid Build Coastguard Worker   _dataForkChecksum.Parse((const Byte *)(const void *)buf + 0x50);
978*f6dc9357SAndroid Build Coastguard Worker   xmlPair.Parse((const Byte *)(const void *)buf + 0xD8);
979*f6dc9357SAndroid Build Coastguard Worker   // Byte resereved[]
980*f6dc9357SAndroid Build Coastguard Worker   blobPair.Parse((const Byte *)(const void *)buf + 0x128);
981*f6dc9357SAndroid Build Coastguard Worker   _masterChecksum.Parse((const Byte *)(const void *)buf + 0x160);
982*f6dc9357SAndroid Build Coastguard Worker   // UInt32 imageVariant = Get32a((const Byte *)(const void *)buf + 0x1E8); imageVariant = imageVariant;
983*f6dc9357SAndroid Build Coastguard Worker   _numSectors = Get64((const Byte *)(const void *)buf + 0x1EC);  // it's not aligned for 8-bytes
984*f6dc9357SAndroid Build Coastguard Worker   // Byte resereved[12];
985*f6dc9357SAndroid Build Coastguard Worker 
986*f6dc9357SAndroid Build Coastguard Worker   if (_dataForkPair.Offset == HEADER_SIZE
987*f6dc9357SAndroid Build Coastguard Worker       && headerPos + HEADER_SIZE < fileSize)
988*f6dc9357SAndroid Build Coastguard Worker     front_Koly_Mode = true;
989*f6dc9357SAndroid Build Coastguard Worker 
990*f6dc9357SAndroid Build Coastguard Worker   const UInt64 limit = front_Koly_Mode ? fileSize : headerPos;
991*f6dc9357SAndroid Build Coastguard Worker   UInt64 top = 0;
992*f6dc9357SAndroid Build Coastguard Worker   if (!_dataForkPair.UpdateTop(limit, top)) return S_FALSE;
993*f6dc9357SAndroid Build Coastguard Worker   if (!xmlPair.UpdateTop(limit, top)) return S_FALSE;
994*f6dc9357SAndroid Build Coastguard Worker   if (!rsrcPair.UpdateTop(limit, top)) return S_FALSE;
995*f6dc9357SAndroid Build Coastguard Worker 
996*f6dc9357SAndroid Build Coastguard Worker   /* Some old dmg files contain garbage data in blobPair field.
997*f6dc9357SAndroid Build Coastguard Worker      So we need to ignore such garbage case;
998*f6dc9357SAndroid Build Coastguard Worker      And we still need to detect offset of start of archive for "parser" mode. */
999*f6dc9357SAndroid Build Coastguard Worker   const bool useBlob = blobPair.UpdateTop(limit, top);
1000*f6dc9357SAndroid Build Coastguard Worker 
1001*f6dc9357SAndroid Build Coastguard Worker   if (front_Koly_Mode)
1002*f6dc9357SAndroid Build Coastguard Worker     _phySize = top;
1003*f6dc9357SAndroid Build Coastguard Worker   else
1004*f6dc9357SAndroid Build Coastguard Worker   {
1005*f6dc9357SAndroid Build Coastguard Worker     _phySize = headerPos + HEADER_SIZE;
1006*f6dc9357SAndroid Build Coastguard Worker     _startPos = 0;
1007*f6dc9357SAndroid Build Coastguard Worker     if (top != headerPos)
1008*f6dc9357SAndroid Build Coastguard Worker     {
1009*f6dc9357SAndroid Build Coastguard Worker       /*
1010*f6dc9357SAndroid Build Coastguard Worker       if expected absolute offset is not equal to real header offset,
1011*f6dc9357SAndroid Build Coastguard Worker       2 cases are possible:
1012*f6dc9357SAndroid Build Coastguard Worker         - additional (unknown) headers
1013*f6dc9357SAndroid Build Coastguard Worker         - archive with offset.
1014*f6dc9357SAndroid Build Coastguard Worker        So we try to read XML with absolute offset to select from these two ways.
1015*f6dc9357SAndroid Build Coastguard Worker       */
1016*f6dc9357SAndroid Build Coastguard Worker       CForkPair xmlPair2 = xmlPair;
1017*f6dc9357SAndroid Build Coastguard Worker       const char *sz = "<?xml version";
1018*f6dc9357SAndroid Build Coastguard Worker       const unsigned len = (unsigned)strlen(sz);
1019*f6dc9357SAndroid Build Coastguard Worker       if (xmlPair2.Len > len)
1020*f6dc9357SAndroid Build Coastguard Worker         xmlPair2.Len = len;
1021*f6dc9357SAndroid Build Coastguard Worker       CByteBuffer buf2;
1022*f6dc9357SAndroid Build Coastguard Worker       if (xmlPair2.Len < len
1023*f6dc9357SAndroid Build Coastguard Worker         || ReadData(stream, xmlPair2, buf2) != S_OK
1024*f6dc9357SAndroid Build Coastguard Worker         || memcmp(buf2, sz, len) != 0)
1025*f6dc9357SAndroid Build Coastguard Worker       {
1026*f6dc9357SAndroid Build Coastguard Worker         // if absolute offset is not OK, probably it's archive with offset
1027*f6dc9357SAndroid Build Coastguard Worker         _startPos = headerPos - top;
1028*f6dc9357SAndroid Build Coastguard Worker         _phySize = top + HEADER_SIZE;
1029*f6dc9357SAndroid Build Coastguard Worker       }
1030*f6dc9357SAndroid Build Coastguard Worker     }
1031*f6dc9357SAndroid Build Coastguard Worker   }
1032*f6dc9357SAndroid Build Coastguard Worker 
1033*f6dc9357SAndroid Build Coastguard Worker   if (useBlob
1034*f6dc9357SAndroid Build Coastguard Worker       && blobPair.Len != 0
1035*f6dc9357SAndroid Build Coastguard Worker       && blobPair.Len <= (1u << 24)) // we don't want parsing of big blobs
1036*f6dc9357SAndroid Build Coastguard Worker   {
1037*f6dc9357SAndroid Build Coastguard Worker #ifdef DMG_SHOW_RAW
1038*f6dc9357SAndroid Build Coastguard Worker     CExtraFile &extra = _extras.AddNew();
1039*f6dc9357SAndroid Build Coastguard Worker     extra.Name = "_blob.bin";
1040*f6dc9357SAndroid Build Coastguard Worker     CByteBuffer &blobBuf = extra.Data;
1041*f6dc9357SAndroid Build Coastguard Worker #else
1042*f6dc9357SAndroid Build Coastguard Worker     CByteBuffer blobBuf;
1043*f6dc9357SAndroid Build Coastguard Worker #endif
1044*f6dc9357SAndroid Build Coastguard Worker     RINOK(ReadData(stream, blobPair, blobBuf))
1045*f6dc9357SAndroid Build Coastguard Worker     if (!ParseBlob(blobBuf))
1046*f6dc9357SAndroid Build Coastguard Worker       _headersError = true;
1047*f6dc9357SAndroid Build Coastguard Worker   }
1048*f6dc9357SAndroid Build Coastguard Worker 
1049*f6dc9357SAndroid Build Coastguard Worker 
1050*f6dc9357SAndroid Build Coastguard Worker   UInt64 openTotal = 0;
1051*f6dc9357SAndroid Build Coastguard Worker   UInt64 openCur = 0;
1052*f6dc9357SAndroid Build Coastguard Worker   if (_dataForkChecksum.IsCrc32())
1053*f6dc9357SAndroid Build Coastguard Worker     openTotal = _dataForkPair.Len;
1054*f6dc9357SAndroid Build Coastguard Worker 
1055*f6dc9357SAndroid Build Coastguard Worker   const UInt32 RSRC_HEAD_SIZE = 0x100;
1056*f6dc9357SAndroid Build Coastguard Worker 
1057*f6dc9357SAndroid Build Coastguard Worker   /* we have 2 ways to read files and blocks metadata:
1058*f6dc9357SAndroid Build Coastguard Worker      via Xml or via Rsrc.
1059*f6dc9357SAndroid Build Coastguard Worker      But some images have no Rsrc fork.
1060*f6dc9357SAndroid Build Coastguard Worker      Is it possible that there is no Xml?
1061*f6dc9357SAndroid Build Coastguard Worker      Rsrc method will not work for big files. */
1062*f6dc9357SAndroid Build Coastguard Worker   // v23.02: we use xml mode by default
1063*f6dc9357SAndroid Build Coastguard Worker   // if (rsrcPair.Len >= RSRC_HEAD_SIZE && rsrcPair.Len <= ((UInt32)1 << 24)) // for debug
1064*f6dc9357SAndroid Build Coastguard Worker   if (xmlPair.Len == 0)
1065*f6dc9357SAndroid Build Coastguard Worker   {
1066*f6dc9357SAndroid Build Coastguard Worker     // We don't know the size of the field "offset" in Rsrc.
1067*f6dc9357SAndroid Build Coastguard Worker     // We suppose that it uses 24 bits. So we use Rsrc, only if the rsrcPair.Len <= (1 << 24).
1068*f6dc9357SAndroid Build Coastguard Worker     const bool canUseRsrc = (rsrcPair.Len >= RSRC_HEAD_SIZE && rsrcPair.Len <= ((UInt32)1 << 24));
1069*f6dc9357SAndroid Build Coastguard Worker     if (!canUseRsrc)
1070*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
1071*f6dc9357SAndroid Build Coastguard Worker 
1072*f6dc9357SAndroid Build Coastguard Worker     _rsrcMode_wasUsed = true;
1073*f6dc9357SAndroid Build Coastguard Worker #ifdef DMG_SHOW_RAW
1074*f6dc9357SAndroid Build Coastguard Worker     CExtraFile &extra = _extras.AddNew();
1075*f6dc9357SAndroid Build Coastguard Worker     extra.Name = "rsrc.bin";
1076*f6dc9357SAndroid Build Coastguard Worker     CByteBuffer &rsrcBuf = extra.Data;
1077*f6dc9357SAndroid Build Coastguard Worker #else
1078*f6dc9357SAndroid Build Coastguard Worker     CByteBuffer rsrcBuf;
1079*f6dc9357SAndroid Build Coastguard Worker #endif
1080*f6dc9357SAndroid Build Coastguard Worker 
1081*f6dc9357SAndroid Build Coastguard Worker     RINOK(ReadData(stream, rsrcPair, rsrcBuf))
1082*f6dc9357SAndroid Build Coastguard Worker 
1083*f6dc9357SAndroid Build Coastguard Worker     const Byte *p = rsrcBuf;
1084*f6dc9357SAndroid Build Coastguard Worker     const UInt32 headSize     = Get32a(p + 0);
1085*f6dc9357SAndroid Build Coastguard Worker     const UInt32 footerOffset = Get32a(p + 4);
1086*f6dc9357SAndroid Build Coastguard Worker     const UInt32 mainDataSize = Get32a(p + 8);
1087*f6dc9357SAndroid Build Coastguard Worker     const UInt32 footerSize   = Get32a(p + 12);
1088*f6dc9357SAndroid Build Coastguard Worker     if (headSize != RSRC_HEAD_SIZE
1089*f6dc9357SAndroid Build Coastguard Worker         || footerOffset >= rsrcPair.Len
1090*f6dc9357SAndroid Build Coastguard Worker         || mainDataSize >= rsrcPair.Len
1091*f6dc9357SAndroid Build Coastguard Worker         || footerOffset < mainDataSize
1092*f6dc9357SAndroid Build Coastguard Worker         || footerOffset != headSize + mainDataSize)
1093*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
1094*f6dc9357SAndroid Build Coastguard Worker 
1095*f6dc9357SAndroid Build Coastguard Worker     {
1096*f6dc9357SAndroid Build Coastguard Worker       const UInt32 footerEnd = footerOffset + footerSize;
1097*f6dc9357SAndroid Build Coastguard Worker       if (footerEnd != rsrcPair.Len)
1098*f6dc9357SAndroid Build Coastguard Worker       {
1099*f6dc9357SAndroid Build Coastguard Worker         // there is rare case dmg example, where there are 4 additional bytes
1100*f6dc9357SAndroid Build Coastguard Worker         const UInt64 rem = rsrcPair.Len - footerOffset;
1101*f6dc9357SAndroid Build Coastguard Worker         if (rem < footerSize
1102*f6dc9357SAndroid Build Coastguard Worker           || rem - footerSize != 4
1103*f6dc9357SAndroid Build Coastguard Worker           || Get32(p + footerEnd) != 0)
1104*f6dc9357SAndroid Build Coastguard Worker           return S_FALSE;
1105*f6dc9357SAndroid Build Coastguard Worker       }
1106*f6dc9357SAndroid Build Coastguard Worker     }
1107*f6dc9357SAndroid Build Coastguard Worker 
1108*f6dc9357SAndroid Build Coastguard Worker     if (footerSize < 0x1e)
1109*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
1110*f6dc9357SAndroid Build Coastguard Worker     if (memcmp(p, p + footerOffset, 16) != 0)
1111*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
1112*f6dc9357SAndroid Build Coastguard Worker 
1113*f6dc9357SAndroid Build Coastguard Worker     p += footerOffset;
1114*f6dc9357SAndroid Build Coastguard Worker 
1115*f6dc9357SAndroid Build Coastguard Worker     if ((UInt32)Get16(p + 0x18) != 0x1c)
1116*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
1117*f6dc9357SAndroid Build Coastguard Worker     const UInt32 namesOffset = Get16(p + 0x1a);
1118*f6dc9357SAndroid Build Coastguard Worker     if (namesOffset > footerSize)
1119*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
1120*f6dc9357SAndroid Build Coastguard Worker 
1121*f6dc9357SAndroid Build Coastguard Worker     const UInt32 numItems = (UInt32)Get16(p + 0x1c) + 1;
1122*f6dc9357SAndroid Build Coastguard Worker     if (numItems * 8 + 0x1e > namesOffset)
1123*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
1124*f6dc9357SAndroid Build Coastguard Worker 
1125*f6dc9357SAndroid Build Coastguard Worker     for (UInt32 i = 0; i < numItems; i++)
1126*f6dc9357SAndroid Build Coastguard Worker     {
1127*f6dc9357SAndroid Build Coastguard Worker       const Byte *p2 = p + 0x1e + (size_t)i * 8;
1128*f6dc9357SAndroid Build Coastguard Worker       const UInt32 typeId = Get32(p2);
1129*f6dc9357SAndroid Build Coastguard Worker       const UInt32 k_typeId_blkx = 0x626c6b78; // blkx
1130*f6dc9357SAndroid Build Coastguard Worker #ifndef DMG_SHOW_RAW
1131*f6dc9357SAndroid Build Coastguard Worker       if (typeId != k_typeId_blkx)
1132*f6dc9357SAndroid Build Coastguard Worker         continue;
1133*f6dc9357SAndroid Build Coastguard Worker #endif
1134*f6dc9357SAndroid Build Coastguard Worker       const UInt32 numFiles = (UInt32)Get16(p2 + 4) + 1;
1135*f6dc9357SAndroid Build Coastguard Worker       const UInt32 offs = Get16(p2 + 6);
1136*f6dc9357SAndroid Build Coastguard Worker       if (0x1c + offs + 12 * numFiles > namesOffset)
1137*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
1138*f6dc9357SAndroid Build Coastguard Worker 
1139*f6dc9357SAndroid Build Coastguard Worker       for (UInt32 k = 0; k < numFiles; k++)
1140*f6dc9357SAndroid Build Coastguard Worker       {
1141*f6dc9357SAndroid Build Coastguard Worker         const Byte *p3 = p + 0x1c + offs + k * 12;
1142*f6dc9357SAndroid Build Coastguard Worker         // UInt32 id = Get16(p3);
1143*f6dc9357SAndroid Build Coastguard Worker         const UInt32 namePos = Get16(p3 + 2);
1144*f6dc9357SAndroid Build Coastguard Worker         // Byte attributes = p3[4]; // = 0x50 for blkx #define (ATTRIBUTE_HDIUTIL)
1145*f6dc9357SAndroid Build Coastguard Worker         // we don't know how many bits we can use. So we use 24 bits only
1146*f6dc9357SAndroid Build Coastguard Worker         UInt32 blockOffset = Get32(p3 + 4);
1147*f6dc9357SAndroid Build Coastguard Worker         blockOffset &= ((UInt32)1 << 24) - 1;
1148*f6dc9357SAndroid Build Coastguard Worker         // UInt32 unknown2 = Get32(p3 + 8); // ???
1149*f6dc9357SAndroid Build Coastguard Worker         if (blockOffset + 4 >= mainDataSize)
1150*f6dc9357SAndroid Build Coastguard Worker           return S_FALSE;
1151*f6dc9357SAndroid Build Coastguard Worker         const Byte *pBlock = rsrcBuf + headSize + blockOffset;
1152*f6dc9357SAndroid Build Coastguard Worker         const UInt32 blockSize = Get32(pBlock);
1153*f6dc9357SAndroid Build Coastguard Worker         if (mainDataSize - (blockOffset + 4) < blockSize)
1154*f6dc9357SAndroid Build Coastguard Worker           return S_FALSE;
1155*f6dc9357SAndroid Build Coastguard Worker 
1156*f6dc9357SAndroid Build Coastguard Worker         AString name;
1157*f6dc9357SAndroid Build Coastguard Worker 
1158*f6dc9357SAndroid Build Coastguard Worker         if (namePos != 0xffff)
1159*f6dc9357SAndroid Build Coastguard Worker         {
1160*f6dc9357SAndroid Build Coastguard Worker           const UInt32 namesBlockSize = footerSize - namesOffset;
1161*f6dc9357SAndroid Build Coastguard Worker           if (namePos >= namesBlockSize)
1162*f6dc9357SAndroid Build Coastguard Worker             return S_FALSE;
1163*f6dc9357SAndroid Build Coastguard Worker           const Byte *namePtr = p + namesOffset + namePos;
1164*f6dc9357SAndroid Build Coastguard Worker           const UInt32 nameLen = *namePtr;
1165*f6dc9357SAndroid Build Coastguard Worker           if (namesBlockSize - namePos <= nameLen)
1166*f6dc9357SAndroid Build Coastguard Worker             return S_FALSE;
1167*f6dc9357SAndroid Build Coastguard Worker           for (UInt32 r = 1; r <= nameLen; r++)
1168*f6dc9357SAndroid Build Coastguard Worker           {
1169*f6dc9357SAndroid Build Coastguard Worker             const Byte c = namePtr[r];
1170*f6dc9357SAndroid Build Coastguard Worker             if (c < 0x20 || c >= 0x80)
1171*f6dc9357SAndroid Build Coastguard Worker               break;
1172*f6dc9357SAndroid Build Coastguard Worker             name += (char)c;
1173*f6dc9357SAndroid Build Coastguard Worker           }
1174*f6dc9357SAndroid Build Coastguard Worker         }
1175*f6dc9357SAndroid Build Coastguard Worker 
1176*f6dc9357SAndroid Build Coastguard Worker         if (typeId == k_typeId_blkx)
1177*f6dc9357SAndroid Build Coastguard Worker         {
1178*f6dc9357SAndroid Build Coastguard Worker           CFile &file = _files.AddNew();
1179*f6dc9357SAndroid Build Coastguard Worker           file.Name = name;
1180*f6dc9357SAndroid Build Coastguard Worker           RINOK(file.Parse(pBlock + 4, blockSize))
1181*f6dc9357SAndroid Build Coastguard Worker           if (!file.IsCorrect)
1182*f6dc9357SAndroid Build Coastguard Worker             _headersError = true;
1183*f6dc9357SAndroid Build Coastguard Worker         }
1184*f6dc9357SAndroid Build Coastguard Worker 
1185*f6dc9357SAndroid Build Coastguard Worker #ifdef DMG_SHOW_RAW
1186*f6dc9357SAndroid Build Coastguard Worker         {
1187*f6dc9357SAndroid Build Coastguard Worker           AString name2;
1188*f6dc9357SAndroid Build Coastguard Worker           name2.Add_UInt32(i);
1189*f6dc9357SAndroid Build Coastguard Worker           name2 += '_';
1190*f6dc9357SAndroid Build Coastguard Worker           {
1191*f6dc9357SAndroid Build Coastguard Worker             char temp[4 + 1] = { 0 };
1192*f6dc9357SAndroid Build Coastguard Worker             memcpy(temp, p2, 4);
1193*f6dc9357SAndroid Build Coastguard Worker             name2 += temp;
1194*f6dc9357SAndroid Build Coastguard Worker           }
1195*f6dc9357SAndroid Build Coastguard Worker           name2.Trim();
1196*f6dc9357SAndroid Build Coastguard Worker           name2 += '_';
1197*f6dc9357SAndroid Build Coastguard Worker           name2.Add_UInt32(k);
1198*f6dc9357SAndroid Build Coastguard Worker           if (!name.IsEmpty())
1199*f6dc9357SAndroid Build Coastguard Worker           {
1200*f6dc9357SAndroid Build Coastguard Worker             name2 += '_';
1201*f6dc9357SAndroid Build Coastguard Worker             name2 += name;
1202*f6dc9357SAndroid Build Coastguard Worker           }
1203*f6dc9357SAndroid Build Coastguard Worker           CExtraFile &extra2 = _extras.AddNew();
1204*f6dc9357SAndroid Build Coastguard Worker           extra2.Name = name2;
1205*f6dc9357SAndroid Build Coastguard Worker           extra2.Data.CopyFrom(pBlock + 4, blockSize);
1206*f6dc9357SAndroid Build Coastguard Worker         }
1207*f6dc9357SAndroid Build Coastguard Worker #endif
1208*f6dc9357SAndroid Build Coastguard Worker       }
1209*f6dc9357SAndroid Build Coastguard Worker     }
1210*f6dc9357SAndroid Build Coastguard Worker   }
1211*f6dc9357SAndroid Build Coastguard Worker   else
1212*f6dc9357SAndroid Build Coastguard Worker   {
1213*f6dc9357SAndroid Build Coastguard Worker     if (xmlPair.Len > k_XmlSize_MAX)
1214*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
1215*f6dc9357SAndroid Build Coastguard Worker     // if (!canUseXml) return S_FALSE;
1216*f6dc9357SAndroid Build Coastguard Worker     const size_t size = (size_t)xmlPair.Len;
1217*f6dc9357SAndroid Build Coastguard Worker     // if (size + 1 <= xmlPair.Len) return S_FALSE; // optional check
1218*f6dc9357SAndroid Build Coastguard Worker     RINOK(InStream_SeekSet(stream, _startPos + xmlPair.Offset))
1219*f6dc9357SAndroid Build Coastguard Worker     CXml xml;
1220*f6dc9357SAndroid Build Coastguard Worker     {
1221*f6dc9357SAndroid Build Coastguard Worker       openTotal += size;
1222*f6dc9357SAndroid Build Coastguard Worker       if (openArchiveCallback)
1223*f6dc9357SAndroid Build Coastguard Worker       {
1224*f6dc9357SAndroid Build Coastguard Worker         RINOK(openArchiveCallback->SetTotal(NULL, &openTotal))
1225*f6dc9357SAndroid Build Coastguard Worker       }
1226*f6dc9357SAndroid Build Coastguard Worker       size_t pos = 0;
1227*f6dc9357SAndroid Build Coastguard Worker       CAlignedBuffer1 xmlStr(size + 1);
1228*f6dc9357SAndroid Build Coastguard Worker       for (;;)
1229*f6dc9357SAndroid Build Coastguard Worker       {
1230*f6dc9357SAndroid Build Coastguard Worker         const size_t k_OpenStep = 1 << 24;
1231*f6dc9357SAndroid Build Coastguard Worker         const size_t cur = MyMin(k_OpenStep, size - pos);
1232*f6dc9357SAndroid Build Coastguard Worker         RINOK(ReadStream_FALSE(stream, xmlStr + pos, cur))
1233*f6dc9357SAndroid Build Coastguard Worker         pos += cur;
1234*f6dc9357SAndroid Build Coastguard Worker         openCur += cur;
1235*f6dc9357SAndroid Build Coastguard Worker         if (pos == size)
1236*f6dc9357SAndroid Build Coastguard Worker           break;
1237*f6dc9357SAndroid Build Coastguard Worker         if (openArchiveCallback)
1238*f6dc9357SAndroid Build Coastguard Worker         {
1239*f6dc9357SAndroid Build Coastguard Worker           RINOK(openArchiveCallback->SetCompleted(NULL, &openCur))
1240*f6dc9357SAndroid Build Coastguard Worker         }
1241*f6dc9357SAndroid Build Coastguard Worker       }
1242*f6dc9357SAndroid Build Coastguard Worker       xmlStr[size] = 0;
1243*f6dc9357SAndroid Build Coastguard Worker       // if (strlen((const char *)(const void *)(const Byte *)xmlStr) != size) return S_FALSE;
1244*f6dc9357SAndroid Build Coastguard Worker       if (!xml.Parse((char *)(void *)(Byte *)xmlStr))
1245*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
1246*f6dc9357SAndroid Build Coastguard Worker 
1247*f6dc9357SAndroid Build Coastguard Worker #ifdef DMG_SHOW_RAW
1248*f6dc9357SAndroid Build Coastguard Worker       CExtraFile &extra = _extras.AddNew();
1249*f6dc9357SAndroid Build Coastguard Worker       extra.Name = "a.xml";
1250*f6dc9357SAndroid Build Coastguard Worker       extra.Data.CopyFrom(xmlStr, size);
1251*f6dc9357SAndroid Build Coastguard Worker #endif
1252*f6dc9357SAndroid Build Coastguard Worker     }
1253*f6dc9357SAndroid Build Coastguard Worker 
1254*f6dc9357SAndroid Build Coastguard Worker     if (xml.Root.Name != "plist")
1255*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
1256*f6dc9357SAndroid Build Coastguard Worker 
1257*f6dc9357SAndroid Build Coastguard Worker     const CXmlItem *dictItem = xml.Root.FindSubTag_GetPtr("dict");
1258*f6dc9357SAndroid Build Coastguard Worker     if (!dictItem)
1259*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
1260*f6dc9357SAndroid Build Coastguard Worker 
1261*f6dc9357SAndroid Build Coastguard Worker     const CXmlItem *rfDictItem = FindKeyPair(*dictItem, "resource-fork", "dict");
1262*f6dc9357SAndroid Build Coastguard Worker     if (!rfDictItem)
1263*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
1264*f6dc9357SAndroid Build Coastguard Worker 
1265*f6dc9357SAndroid Build Coastguard Worker     const CXmlItem *arrItem = FindKeyPair(*rfDictItem, "blkx", "array");
1266*f6dc9357SAndroid Build Coastguard Worker     if (!arrItem)
1267*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
1268*f6dc9357SAndroid Build Coastguard Worker 
1269*f6dc9357SAndroid Build Coastguard Worker     FOR_VECTOR (i, arrItem->SubItems)
1270*f6dc9357SAndroid Build Coastguard Worker     {
1271*f6dc9357SAndroid Build Coastguard Worker       const CXmlItem &item = arrItem->SubItems[i];
1272*f6dc9357SAndroid Build Coastguard Worker       if (!item.IsTagged("dict"))
1273*f6dc9357SAndroid Build Coastguard Worker         continue;
1274*f6dc9357SAndroid Build Coastguard Worker 
1275*f6dc9357SAndroid Build Coastguard Worker       CByteBuffer rawBuf;
1276*f6dc9357SAndroid Build Coastguard Worker       unsigned destLen = 0;
1277*f6dc9357SAndroid Build Coastguard Worker       {
1278*f6dc9357SAndroid Build Coastguard Worker         const AString *dataString = GetStringFromKeyPair(item, "Data", "data");
1279*f6dc9357SAndroid Build Coastguard Worker         if (!dataString)
1280*f6dc9357SAndroid Build Coastguard Worker           return S_FALSE;
1281*f6dc9357SAndroid Build Coastguard Worker         destLen = dataString->Len() / 4 * 3 + 4;
1282*f6dc9357SAndroid Build Coastguard Worker         rawBuf.Alloc(destLen);
1283*f6dc9357SAndroid Build Coastguard Worker         {
1284*f6dc9357SAndroid Build Coastguard Worker           const Byte *endPtr = Base64ToBin(rawBuf, *dataString);
1285*f6dc9357SAndroid Build Coastguard Worker           if (!endPtr)
1286*f6dc9357SAndroid Build Coastguard Worker             return S_FALSE;
1287*f6dc9357SAndroid Build Coastguard Worker           destLen = (unsigned)(endPtr - (const Byte *)rawBuf);
1288*f6dc9357SAndroid Build Coastguard Worker         }
1289*f6dc9357SAndroid Build Coastguard Worker 
1290*f6dc9357SAndroid Build Coastguard Worker #ifdef DMG_SHOW_RAW
1291*f6dc9357SAndroid Build Coastguard Worker         CExtraFile &extra = _extras.AddNew();
1292*f6dc9357SAndroid Build Coastguard Worker         extra.Name.Add_UInt32(_files.Size());
1293*f6dc9357SAndroid Build Coastguard Worker         extra.Data.CopyFrom(rawBuf, destLen);
1294*f6dc9357SAndroid Build Coastguard Worker #endif
1295*f6dc9357SAndroid Build Coastguard Worker       }
1296*f6dc9357SAndroid Build Coastguard Worker       CFile &file = _files.AddNew();
1297*f6dc9357SAndroid Build Coastguard Worker       {
1298*f6dc9357SAndroid Build Coastguard Worker         /* xml code removes front space for such string:
1299*f6dc9357SAndroid Build Coastguard Worker              <string> (Apple_Free : 3)</string>
1300*f6dc9357SAndroid Build Coastguard Worker            maybe we shoud fix xml code and return full string with space.
1301*f6dc9357SAndroid Build Coastguard Worker         */
1302*f6dc9357SAndroid Build Coastguard Worker         const AString *name = GetStringFromKeyPair(item, "Name", "string");
1303*f6dc9357SAndroid Build Coastguard Worker         if (!name || name->IsEmpty())
1304*f6dc9357SAndroid Build Coastguard Worker           name = GetStringFromKeyPair(item, "CFName", "string");
1305*f6dc9357SAndroid Build Coastguard Worker         if (name)
1306*f6dc9357SAndroid Build Coastguard Worker           file.Name = *name;
1307*f6dc9357SAndroid Build Coastguard Worker       }
1308*f6dc9357SAndroid Build Coastguard Worker       /*
1309*f6dc9357SAndroid Build Coastguard Worker       {
1310*f6dc9357SAndroid Build Coastguard Worker         const AString *s = GetStringFromKeyPair(item, "ID", "string");
1311*f6dc9357SAndroid Build Coastguard Worker         if (s)
1312*f6dc9357SAndroid Build Coastguard Worker           file.Id = *s;
1313*f6dc9357SAndroid Build Coastguard Worker       }
1314*f6dc9357SAndroid Build Coastguard Worker       */
1315*f6dc9357SAndroid Build Coastguard Worker       RINOK(file.Parse(rawBuf, destLen))
1316*f6dc9357SAndroid Build Coastguard Worker       if (!file.IsCorrect)
1317*f6dc9357SAndroid Build Coastguard Worker         _headersError = true;
1318*f6dc9357SAndroid Build Coastguard Worker     }
1319*f6dc9357SAndroid Build Coastguard Worker   }
1320*f6dc9357SAndroid Build Coastguard Worker 
1321*f6dc9357SAndroid Build Coastguard Worker   if (_masterChecksum.IsCrc32())
1322*f6dc9357SAndroid Build Coastguard Worker   {
1323*f6dc9357SAndroid Build Coastguard Worker     UInt32 crc = CRC_INIT_VAL;
1324*f6dc9357SAndroid Build Coastguard Worker     unsigned i;
1325*f6dc9357SAndroid Build Coastguard Worker     for (i = 0; i < _files.Size(); i++)
1326*f6dc9357SAndroid Build Coastguard Worker     {
1327*f6dc9357SAndroid Build Coastguard Worker       const CChecksum &cs = _files[i].Checksum;
1328*f6dc9357SAndroid Build Coastguard Worker       if ((cs.NumBits & 0x7) != 0)
1329*f6dc9357SAndroid Build Coastguard Worker         break;
1330*f6dc9357SAndroid Build Coastguard Worker       const UInt32 len = cs.NumBits >> 3;
1331*f6dc9357SAndroid Build Coastguard Worker       if (len > kChecksumSize_Max)
1332*f6dc9357SAndroid Build Coastguard Worker         break;
1333*f6dc9357SAndroid Build Coastguard Worker       crc = CrcUpdate(crc, cs.Data, (size_t)len);
1334*f6dc9357SAndroid Build Coastguard Worker     }
1335*f6dc9357SAndroid Build Coastguard Worker     if (i == _files.Size())
1336*f6dc9357SAndroid Build Coastguard Worker       _masterCrcError = (CRC_GET_DIGEST(crc) != _masterChecksum.GetCrc32());
1337*f6dc9357SAndroid Build Coastguard Worker   }
1338*f6dc9357SAndroid Build Coastguard Worker 
1339*f6dc9357SAndroid Build Coastguard Worker   {
1340*f6dc9357SAndroid Build Coastguard Worker     UInt64 sec = 0;
1341*f6dc9357SAndroid Build Coastguard Worker     FOR_VECTOR (i, _files)
1342*f6dc9357SAndroid Build Coastguard Worker     {
1343*f6dc9357SAndroid Build Coastguard Worker       const CFile &file = _files[i];
1344*f6dc9357SAndroid Build Coastguard Worker       /*
1345*f6dc9357SAndroid Build Coastguard Worker       if (file.Descriptor != (Int32)i - 1)
1346*f6dc9357SAndroid Build Coastguard Worker         _headersError = true;
1347*f6dc9357SAndroid Build Coastguard Worker       */
1348*f6dc9357SAndroid Build Coastguard Worker       if (file.StartUnpackSector != sec)
1349*f6dc9357SAndroid Build Coastguard Worker         _headersError = true;
1350*f6dc9357SAndroid Build Coastguard Worker       if (file.NumUnpackSectors >= kSectorNumber_LIMIT)
1351*f6dc9357SAndroid Build Coastguard Worker         _headersError = true;
1352*f6dc9357SAndroid Build Coastguard Worker       sec += file.NumUnpackSectors;
1353*f6dc9357SAndroid Build Coastguard Worker       if (sec >= kSectorNumber_LIMIT)
1354*f6dc9357SAndroid Build Coastguard Worker         _headersError = true;
1355*f6dc9357SAndroid Build Coastguard Worker     }
1356*f6dc9357SAndroid Build Coastguard Worker     if (sec != _numSectors)
1357*f6dc9357SAndroid Build Coastguard Worker       _headersError = true;
1358*f6dc9357SAndroid Build Coastguard Worker   }
1359*f6dc9357SAndroid Build Coastguard Worker 
1360*f6dc9357SAndroid Build Coastguard Worker   // data checksum calculation can be slow for big dmg file
1361*f6dc9357SAndroid Build Coastguard Worker   if (_dataForkChecksum.IsCrc32())
1362*f6dc9357SAndroid Build Coastguard Worker   {
1363*f6dc9357SAndroid Build Coastguard Worker     UInt64 endPos;
1364*f6dc9357SAndroid Build Coastguard Worker     if (!_dataForkPair.GetEndPos(endPos)
1365*f6dc9357SAndroid Build Coastguard Worker         || _dataForkPair.Offset >= ((UInt64)1 << 63))
1366*f6dc9357SAndroid Build Coastguard Worker       _headersError = true;
1367*f6dc9357SAndroid Build Coastguard Worker     else
1368*f6dc9357SAndroid Build Coastguard Worker     {
1369*f6dc9357SAndroid Build Coastguard Worker       const UInt64 seekPos = _startPos + _dataForkPair.Offset;
1370*f6dc9357SAndroid Build Coastguard Worker       if (seekPos > fileSize
1371*f6dc9357SAndroid Build Coastguard Worker         || endPos > fileSize - _startPos)
1372*f6dc9357SAndroid Build Coastguard Worker       {
1373*f6dc9357SAndroid Build Coastguard Worker         _headersError = true;
1374*f6dc9357SAndroid Build Coastguard Worker         // kpv_ErrorFlags_UnexpectedEnd
1375*f6dc9357SAndroid Build Coastguard Worker       }
1376*f6dc9357SAndroid Build Coastguard Worker       else
1377*f6dc9357SAndroid Build Coastguard Worker       {
1378*f6dc9357SAndroid Build Coastguard Worker         const size_t kBufSize = 1 << 15;
1379*f6dc9357SAndroid Build Coastguard Worker         CAlignedBuffer1 buf2(kBufSize);
1380*f6dc9357SAndroid Build Coastguard Worker         RINOK(InStream_SeekSet(stream, seekPos))
1381*f6dc9357SAndroid Build Coastguard Worker         if (openArchiveCallback)
1382*f6dc9357SAndroid Build Coastguard Worker         {
1383*f6dc9357SAndroid Build Coastguard Worker           RINOK(openArchiveCallback->SetTotal(NULL, &openTotal))
1384*f6dc9357SAndroid Build Coastguard Worker         }
1385*f6dc9357SAndroid Build Coastguard Worker         UInt32 crc = CRC_INIT_VAL;
1386*f6dc9357SAndroid Build Coastguard Worker         UInt64 pos = 0;
1387*f6dc9357SAndroid Build Coastguard Worker         for (;;)
1388*f6dc9357SAndroid Build Coastguard Worker         {
1389*f6dc9357SAndroid Build Coastguard Worker           const UInt64 rem = _dataForkPair.Len - pos;
1390*f6dc9357SAndroid Build Coastguard Worker           size_t cur = kBufSize;
1391*f6dc9357SAndroid Build Coastguard Worker           if (cur > rem)
1392*f6dc9357SAndroid Build Coastguard Worker             cur = (UInt32)rem;
1393*f6dc9357SAndroid Build Coastguard Worker           if (cur == 0)
1394*f6dc9357SAndroid Build Coastguard Worker             break;
1395*f6dc9357SAndroid Build Coastguard Worker           RINOK(ReadStream_FALSE(stream, buf2, cur))
1396*f6dc9357SAndroid Build Coastguard Worker           crc = CrcUpdate(crc, buf2, cur);
1397*f6dc9357SAndroid Build Coastguard Worker           pos += cur;
1398*f6dc9357SAndroid Build Coastguard Worker           openCur += cur;
1399*f6dc9357SAndroid Build Coastguard Worker           if ((pos & ((1 << 24) - 1)) == 0 && openArchiveCallback)
1400*f6dc9357SAndroid Build Coastguard Worker           {
1401*f6dc9357SAndroid Build Coastguard Worker             RINOK(openArchiveCallback->SetCompleted(NULL, &openCur))
1402*f6dc9357SAndroid Build Coastguard Worker           }
1403*f6dc9357SAndroid Build Coastguard Worker         }
1404*f6dc9357SAndroid Build Coastguard Worker         if (_dataForkChecksum.GetCrc32() != CRC_GET_DIGEST(crc))
1405*f6dc9357SAndroid Build Coastguard Worker           _dataForkError = true;
1406*f6dc9357SAndroid Build Coastguard Worker       }
1407*f6dc9357SAndroid Build Coastguard Worker     }
1408*f6dc9357SAndroid Build Coastguard Worker   }
1409*f6dc9357SAndroid Build Coastguard Worker 
1410*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
1411*f6dc9357SAndroid Build Coastguard Worker }
1412*f6dc9357SAndroid Build Coastguard Worker 
1413*f6dc9357SAndroid Build Coastguard Worker 
1414*f6dc9357SAndroid Build Coastguard Worker 
Z7_COM7F_IMF(CHandler::Open (IInStream * stream,const UInt64 *,IArchiveOpenCallback * openArchiveCallback))1415*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::Open(IInStream *stream,
1416*f6dc9357SAndroid Build Coastguard Worker     const UInt64 * /* maxCheckStartPosition */,
1417*f6dc9357SAndroid Build Coastguard Worker     IArchiveOpenCallback *openArchiveCallback))
1418*f6dc9357SAndroid Build Coastguard Worker {
1419*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_BEGIN
1420*f6dc9357SAndroid Build Coastguard Worker   Close();
1421*f6dc9357SAndroid Build Coastguard Worker   RINOK(Open2(stream, openArchiveCallback))
1422*f6dc9357SAndroid Build Coastguard Worker   _inStream = stream;
1423*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
1424*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_END
1425*f6dc9357SAndroid Build Coastguard Worker }
1426*f6dc9357SAndroid Build Coastguard Worker 
Z7_COM7F_IMF(CHandler::Close ())1427*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::Close())
1428*f6dc9357SAndroid Build Coastguard Worker {
1429*f6dc9357SAndroid Build Coastguard Worker   _masterCrcError = false;
1430*f6dc9357SAndroid Build Coastguard Worker   _headersError = false;
1431*f6dc9357SAndroid Build Coastguard Worker   _dataForkError = false;
1432*f6dc9357SAndroid Build Coastguard Worker   _rsrcMode_wasUsed = false;
1433*f6dc9357SAndroid Build Coastguard Worker   _phySize = 0;
1434*f6dc9357SAndroid Build Coastguard Worker   _startPos = 0;
1435*f6dc9357SAndroid Build Coastguard Worker   _name.Empty();
1436*f6dc9357SAndroid Build Coastguard Worker   _inStream.Release();
1437*f6dc9357SAndroid Build Coastguard Worker   _files.Clear();
1438*f6dc9357SAndroid Build Coastguard Worker #ifdef DMG_SHOW_RAW
1439*f6dc9357SAndroid Build Coastguard Worker   _extras.Clear();
1440*f6dc9357SAndroid Build Coastguard Worker #endif
1441*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
1442*f6dc9357SAndroid Build Coastguard Worker }
1443*f6dc9357SAndroid Build Coastguard Worker 
Z7_COM7F_IMF(CHandler::GetNumberOfItems (UInt32 * numItems))1444*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems))
1445*f6dc9357SAndroid Build Coastguard Worker {
1446*f6dc9357SAndroid Build Coastguard Worker   *numItems = _files.Size()
1447*f6dc9357SAndroid Build Coastguard Worker #ifdef DMG_SHOW_RAW
1448*f6dc9357SAndroid Build Coastguard Worker     + _extras.Size()
1449*f6dc9357SAndroid Build Coastguard Worker #endif
1450*f6dc9357SAndroid Build Coastguard Worker     ;
1451*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
1452*f6dc9357SAndroid Build Coastguard Worker }
1453*f6dc9357SAndroid Build Coastguard Worker 
1454*f6dc9357SAndroid Build Coastguard Worker #ifdef DMG_SHOW_RAW
1455*f6dc9357SAndroid Build Coastguard Worker #define RAW_PREFIX "raw" STRING_PATH_SEPARATOR
1456*f6dc9357SAndroid Build Coastguard Worker #endif
1457*f6dc9357SAndroid Build Coastguard Worker 
Z7_COM7F_IMF(CHandler::GetProperty (UInt32 index,PROPID propID,PROPVARIANT * value))1458*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value))
1459*f6dc9357SAndroid Build Coastguard Worker {
1460*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_BEGIN
1461*f6dc9357SAndroid Build Coastguard Worker   NWindows::NCOM::CPropVariant prop;
1462*f6dc9357SAndroid Build Coastguard Worker 
1463*f6dc9357SAndroid Build Coastguard Worker #ifdef DMG_SHOW_RAW
1464*f6dc9357SAndroid Build Coastguard Worker   if (index >= _files.Size())
1465*f6dc9357SAndroid Build Coastguard Worker   {
1466*f6dc9357SAndroid Build Coastguard Worker     const CExtraFile &extra = _extras[index - _files.Size()];
1467*f6dc9357SAndroid Build Coastguard Worker     switch (propID)
1468*f6dc9357SAndroid Build Coastguard Worker     {
1469*f6dc9357SAndroid Build Coastguard Worker       case kpidPath:
1470*f6dc9357SAndroid Build Coastguard Worker         prop = (AString)RAW_PREFIX + extra.Name;
1471*f6dc9357SAndroid Build Coastguard Worker         break;
1472*f6dc9357SAndroid Build Coastguard Worker       case kpidSize:
1473*f6dc9357SAndroid Build Coastguard Worker       case kpidPackSize:
1474*f6dc9357SAndroid Build Coastguard Worker         prop = (UInt64)extra.Data.Size();
1475*f6dc9357SAndroid Build Coastguard Worker         break;
1476*f6dc9357SAndroid Build Coastguard Worker     }
1477*f6dc9357SAndroid Build Coastguard Worker   }
1478*f6dc9357SAndroid Build Coastguard Worker   else
1479*f6dc9357SAndroid Build Coastguard Worker #endif
1480*f6dc9357SAndroid Build Coastguard Worker   {
1481*f6dc9357SAndroid Build Coastguard Worker     const CFile &item = _files[index];
1482*f6dc9357SAndroid Build Coastguard Worker     switch (propID)
1483*f6dc9357SAndroid Build Coastguard Worker     {
1484*f6dc9357SAndroid Build Coastguard Worker       case kpidSize:  prop = item.Size; break;
1485*f6dc9357SAndroid Build Coastguard Worker       case kpidPackSize:  prop = item.PackSize; break;
1486*f6dc9357SAndroid Build Coastguard Worker       case kpidCRC:
1487*f6dc9357SAndroid Build Coastguard Worker       {
1488*f6dc9357SAndroid Build Coastguard Worker         if (item.Checksum.IsCrc32() && item.FullFileChecksum)
1489*f6dc9357SAndroid Build Coastguard Worker           prop = item.Checksum.GetCrc32();
1490*f6dc9357SAndroid Build Coastguard Worker         break;
1491*f6dc9357SAndroid Build Coastguard Worker       }
1492*f6dc9357SAndroid Build Coastguard Worker       case kpidChecksum:
1493*f6dc9357SAndroid Build Coastguard Worker       {
1494*f6dc9357SAndroid Build Coastguard Worker         AString s;
1495*f6dc9357SAndroid Build Coastguard Worker         item.Checksum.Print(s);
1496*f6dc9357SAndroid Build Coastguard Worker         if (!s.IsEmpty())
1497*f6dc9357SAndroid Build Coastguard Worker           prop = s;
1498*f6dc9357SAndroid Build Coastguard Worker         break;
1499*f6dc9357SAndroid Build Coastguard Worker       }
1500*f6dc9357SAndroid Build Coastguard Worker 
1501*f6dc9357SAndroid Build Coastguard Worker       /*
1502*f6dc9357SAndroid Build Coastguard Worker       case kpidOffset:
1503*f6dc9357SAndroid Build Coastguard Worker       {
1504*f6dc9357SAndroid Build Coastguard Worker         prop = item.StartPackPos;
1505*f6dc9357SAndroid Build Coastguard Worker         break;
1506*f6dc9357SAndroid Build Coastguard Worker       }
1507*f6dc9357SAndroid Build Coastguard Worker       */
1508*f6dc9357SAndroid Build Coastguard Worker 
1509*f6dc9357SAndroid Build Coastguard Worker       case kpidNumBlocks:
1510*f6dc9357SAndroid Build Coastguard Worker           prop = (UInt32)item.Blocks.Size();
1511*f6dc9357SAndroid Build Coastguard Worker           break;
1512*f6dc9357SAndroid Build Coastguard Worker       case kpidClusterSize:
1513*f6dc9357SAndroid Build Coastguard Worker           prop = item.BlockSize_MAX;
1514*f6dc9357SAndroid Build Coastguard Worker           break;
1515*f6dc9357SAndroid Build Coastguard Worker 
1516*f6dc9357SAndroid Build Coastguard Worker       case kpidMethod:
1517*f6dc9357SAndroid Build Coastguard Worker       {
1518*f6dc9357SAndroid Build Coastguard Worker         AString s;
1519*f6dc9357SAndroid Build Coastguard Worker         if (!item.IsCorrect)
1520*f6dc9357SAndroid Build Coastguard Worker           s.Add_OptSpaced("CORRUPTED");
1521*f6dc9357SAndroid Build Coastguard Worker         CMethods m;
1522*f6dc9357SAndroid Build Coastguard Worker         m.Update(item);
1523*f6dc9357SAndroid Build Coastguard Worker         m.AddToString(s);
1524*f6dc9357SAndroid Build Coastguard Worker         {
1525*f6dc9357SAndroid Build Coastguard Worker           AString s2;
1526*f6dc9357SAndroid Build Coastguard Worker           item.Checksum.PrintType(s2);
1527*f6dc9357SAndroid Build Coastguard Worker           if (!s2.IsEmpty())
1528*f6dc9357SAndroid Build Coastguard Worker             s.Add_OptSpaced(s2);
1529*f6dc9357SAndroid Build Coastguard Worker         }
1530*f6dc9357SAndroid Build Coastguard Worker         if (!s.IsEmpty())
1531*f6dc9357SAndroid Build Coastguard Worker           prop = s;
1532*f6dc9357SAndroid Build Coastguard Worker         break;
1533*f6dc9357SAndroid Build Coastguard Worker       }
1534*f6dc9357SAndroid Build Coastguard Worker 
1535*f6dc9357SAndroid Build Coastguard Worker       case kpidPath:
1536*f6dc9357SAndroid Build Coastguard Worker       {
1537*f6dc9357SAndroid Build Coastguard Worker #ifdef Z7_DMG_SINGLE_FILE_MODE
1538*f6dc9357SAndroid Build Coastguard Worker         prop = "a.img";
1539*f6dc9357SAndroid Build Coastguard Worker #else
1540*f6dc9357SAndroid Build Coastguard Worker         UString name;
1541*f6dc9357SAndroid Build Coastguard Worker         name.Add_UInt32(index);
1542*f6dc9357SAndroid Build Coastguard Worker         unsigned num = 10;
1543*f6dc9357SAndroid Build Coastguard Worker         unsigned numDigits;
1544*f6dc9357SAndroid Build Coastguard Worker         for (numDigits = 1; num < _files.Size(); numDigits++)
1545*f6dc9357SAndroid Build Coastguard Worker           num *= 10;
1546*f6dc9357SAndroid Build Coastguard Worker         while (name.Len() < numDigits)
1547*f6dc9357SAndroid Build Coastguard Worker           name.InsertAtFront(L'0');
1548*f6dc9357SAndroid Build Coastguard Worker 
1549*f6dc9357SAndroid Build Coastguard Worker         AString subName;
1550*f6dc9357SAndroid Build Coastguard Worker         int pos1 = item.Name.Find('(');
1551*f6dc9357SAndroid Build Coastguard Worker         if (pos1 >= 0)
1552*f6dc9357SAndroid Build Coastguard Worker         {
1553*f6dc9357SAndroid Build Coastguard Worker           pos1++;
1554*f6dc9357SAndroid Build Coastguard Worker           const int pos2 = item.Name.Find(')', pos1);
1555*f6dc9357SAndroid Build Coastguard Worker           if (pos2 >= 0)
1556*f6dc9357SAndroid Build Coastguard Worker           {
1557*f6dc9357SAndroid Build Coastguard Worker             subName.SetFrom(item.Name.Ptr(pos1), pos2 - pos1);
1558*f6dc9357SAndroid Build Coastguard Worker             pos1 = subName.Find(':');
1559*f6dc9357SAndroid Build Coastguard Worker             if (pos1 >= 0)
1560*f6dc9357SAndroid Build Coastguard Worker               subName.DeleteFrom(pos1);
1561*f6dc9357SAndroid Build Coastguard Worker           }
1562*f6dc9357SAndroid Build Coastguard Worker         }
1563*f6dc9357SAndroid Build Coastguard Worker         else
1564*f6dc9357SAndroid Build Coastguard Worker           subName = item.Name; // new apfs dmg can be without braces
1565*f6dc9357SAndroid Build Coastguard Worker         subName.Trim();
1566*f6dc9357SAndroid Build Coastguard Worker         if (!subName.IsEmpty())
1567*f6dc9357SAndroid Build Coastguard Worker         {
1568*f6dc9357SAndroid Build Coastguard Worker           const char *ext = Find_Apple_FS_Ext(subName);
1569*f6dc9357SAndroid Build Coastguard Worker           if (ext)
1570*f6dc9357SAndroid Build Coastguard Worker             subName = ext;
1571*f6dc9357SAndroid Build Coastguard Worker           UString name2;
1572*f6dc9357SAndroid Build Coastguard Worker           ConvertUTF8ToUnicode(subName, name2);
1573*f6dc9357SAndroid Build Coastguard Worker           name.Add_Dot();
1574*f6dc9357SAndroid Build Coastguard Worker           name += name2;
1575*f6dc9357SAndroid Build Coastguard Worker         }
1576*f6dc9357SAndroid Build Coastguard Worker         else
1577*f6dc9357SAndroid Build Coastguard Worker         {
1578*f6dc9357SAndroid Build Coastguard Worker           UString name2;
1579*f6dc9357SAndroid Build Coastguard Worker           ConvertUTF8ToUnicode(item.Name, name2);
1580*f6dc9357SAndroid Build Coastguard Worker           if (!name2.IsEmpty())
1581*f6dc9357SAndroid Build Coastguard Worker             name += "_";
1582*f6dc9357SAndroid Build Coastguard Worker           name += name2;
1583*f6dc9357SAndroid Build Coastguard Worker         }
1584*f6dc9357SAndroid Build Coastguard Worker         prop = name;
1585*f6dc9357SAndroid Build Coastguard Worker #endif
1586*f6dc9357SAndroid Build Coastguard Worker 
1587*f6dc9357SAndroid Build Coastguard Worker         break;
1588*f6dc9357SAndroid Build Coastguard Worker       }
1589*f6dc9357SAndroid Build Coastguard Worker 
1590*f6dc9357SAndroid Build Coastguard Worker       case kpidComment:
1591*f6dc9357SAndroid Build Coastguard Worker       {
1592*f6dc9357SAndroid Build Coastguard Worker         UString name;
1593*f6dc9357SAndroid Build Coastguard Worker         ConvertUTF8ToUnicode(item.Name, name);
1594*f6dc9357SAndroid Build Coastguard Worker         prop = name;
1595*f6dc9357SAndroid Build Coastguard Worker         break;
1596*f6dc9357SAndroid Build Coastguard Worker       }
1597*f6dc9357SAndroid Build Coastguard Worker       case kpidId:
1598*f6dc9357SAndroid Build Coastguard Worker       {
1599*f6dc9357SAndroid Build Coastguard Worker         prop.Set_Int32((Int32)item.Descriptor);
1600*f6dc9357SAndroid Build Coastguard Worker         /*
1601*f6dc9357SAndroid Build Coastguard Worker         if (!item.Id.IsEmpty())
1602*f6dc9357SAndroid Build Coastguard Worker         {
1603*f6dc9357SAndroid Build Coastguard Worker           UString s;
1604*f6dc9357SAndroid Build Coastguard Worker           ConvertUTF8ToUnicode(item.Id, s);
1605*f6dc9357SAndroid Build Coastguard Worker           prop = s;
1606*f6dc9357SAndroid Build Coastguard Worker         }
1607*f6dc9357SAndroid Build Coastguard Worker         */
1608*f6dc9357SAndroid Build Coastguard Worker         break;
1609*f6dc9357SAndroid Build Coastguard Worker       }
1610*f6dc9357SAndroid Build Coastguard Worker #ifdef Z7_DMG_SINGLE_FILE_MODE
1611*f6dc9357SAndroid Build Coastguard Worker       case kpidPosition:
1612*f6dc9357SAndroid Build Coastguard Worker         prop = item.StartUnpackSector << 9;
1613*f6dc9357SAndroid Build Coastguard Worker         break;
1614*f6dc9357SAndroid Build Coastguard Worker #endif
1615*f6dc9357SAndroid Build Coastguard Worker     }
1616*f6dc9357SAndroid Build Coastguard Worker   }
1617*f6dc9357SAndroid Build Coastguard Worker   prop.Detach(value);
1618*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
1619*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_END
1620*f6dc9357SAndroid Build Coastguard Worker }
1621*f6dc9357SAndroid Build Coastguard Worker 
1622*f6dc9357SAndroid Build Coastguard Worker 
1623*f6dc9357SAndroid Build Coastguard Worker class CAdcDecoder
1624*f6dc9357SAndroid Build Coastguard Worker {
1625*f6dc9357SAndroid Build Coastguard Worker   CLzOutWindow m_OutWindowStream;
1626*f6dc9357SAndroid Build Coastguard Worker   CInBuffer m_InStream;
1627*f6dc9357SAndroid Build Coastguard Worker 
1628*f6dc9357SAndroid Build Coastguard Worker   class CCoderReleaser Z7_final
1629*f6dc9357SAndroid Build Coastguard Worker   {
1630*f6dc9357SAndroid Build Coastguard Worker     CAdcDecoder *m_Coder;
1631*f6dc9357SAndroid Build Coastguard Worker   public:
1632*f6dc9357SAndroid Build Coastguard Worker     bool NeedFlush;
CCoderReleaser(CAdcDecoder * coder)1633*f6dc9357SAndroid Build Coastguard Worker     CCoderReleaser(CAdcDecoder *coder): m_Coder(coder), NeedFlush(true) {}
~CCoderReleaser()1634*f6dc9357SAndroid Build Coastguard Worker     ~CCoderReleaser()
1635*f6dc9357SAndroid Build Coastguard Worker     {
1636*f6dc9357SAndroid Build Coastguard Worker       if (NeedFlush)
1637*f6dc9357SAndroid Build Coastguard Worker         m_Coder->m_OutWindowStream.Flush();
1638*f6dc9357SAndroid Build Coastguard Worker     }
1639*f6dc9357SAndroid Build Coastguard Worker   };
1640*f6dc9357SAndroid Build Coastguard Worker   friend class CCoderReleaser;
1641*f6dc9357SAndroid Build Coastguard Worker 
1642*f6dc9357SAndroid Build Coastguard Worker public:
1643*f6dc9357SAndroid Build Coastguard Worker   HRESULT Code(ISequentialInStream * const inStream,
1644*f6dc9357SAndroid Build Coastguard Worker     ISequentialOutStream *outStream,
1645*f6dc9357SAndroid Build Coastguard Worker     const UInt64 * const inSize,
1646*f6dc9357SAndroid Build Coastguard Worker     const UInt64 * const outSize,
1647*f6dc9357SAndroid Build Coastguard Worker     ICompressProgressInfo * const progress);
1648*f6dc9357SAndroid Build Coastguard Worker };
1649*f6dc9357SAndroid Build Coastguard Worker 
1650*f6dc9357SAndroid Build Coastguard Worker 
Code(ISequentialInStream * const inStream,ISequentialOutStream * outStream,const UInt64 * const inSize,const UInt64 * const outSizePtr,ICompressProgressInfo * const progress)1651*f6dc9357SAndroid Build Coastguard Worker HRESULT CAdcDecoder::Code(ISequentialInStream * const inStream,
1652*f6dc9357SAndroid Build Coastguard Worker     ISequentialOutStream *outStream,
1653*f6dc9357SAndroid Build Coastguard Worker     const UInt64 * const inSize,
1654*f6dc9357SAndroid Build Coastguard Worker     const UInt64 * const outSizePtr,
1655*f6dc9357SAndroid Build Coastguard Worker     ICompressProgressInfo * const progress)
1656*f6dc9357SAndroid Build Coastguard Worker {
1657*f6dc9357SAndroid Build Coastguard Worker   try {
1658*f6dc9357SAndroid Build Coastguard Worker 
1659*f6dc9357SAndroid Build Coastguard Worker   if (!m_OutWindowStream.Create(1 << 18)) // at least (1 << 16) is required here
1660*f6dc9357SAndroid Build Coastguard Worker     return E_OUTOFMEMORY;
1661*f6dc9357SAndroid Build Coastguard Worker   if (!m_InStream.Create(1 << 18))
1662*f6dc9357SAndroid Build Coastguard Worker     return E_OUTOFMEMORY;
1663*f6dc9357SAndroid Build Coastguard Worker 
1664*f6dc9357SAndroid Build Coastguard Worker   m_OutWindowStream.SetStream(outStream);
1665*f6dc9357SAndroid Build Coastguard Worker   m_OutWindowStream.Init(false);
1666*f6dc9357SAndroid Build Coastguard Worker   m_InStream.SetStream(inStream);
1667*f6dc9357SAndroid Build Coastguard Worker   m_InStream.Init();
1668*f6dc9357SAndroid Build Coastguard Worker 
1669*f6dc9357SAndroid Build Coastguard Worker   CCoderReleaser coderReleaser(this);
1670*f6dc9357SAndroid Build Coastguard Worker 
1671*f6dc9357SAndroid Build Coastguard Worker   const UInt32 kStep = 1 << 22;
1672*f6dc9357SAndroid Build Coastguard Worker   UInt64 nextLimit = kStep;
1673*f6dc9357SAndroid Build Coastguard Worker   const UInt64 outSize = *outSizePtr;
1674*f6dc9357SAndroid Build Coastguard Worker   UInt64 pos = 0;
1675*f6dc9357SAndroid Build Coastguard Worker   /* match sequences and literal sequences do not cross 64KB range
1676*f6dc9357SAndroid Build Coastguard Worker      in some dmg archive examples. But is it so for any Adc stream? */
1677*f6dc9357SAndroid Build Coastguard Worker 
1678*f6dc9357SAndroid Build Coastguard Worker   while (pos < outSize)
1679*f6dc9357SAndroid Build Coastguard Worker   {
1680*f6dc9357SAndroid Build Coastguard Worker     if (pos >= nextLimit && progress)
1681*f6dc9357SAndroid Build Coastguard Worker     {
1682*f6dc9357SAndroid Build Coastguard Worker       nextLimit += kStep;
1683*f6dc9357SAndroid Build Coastguard Worker       const UInt64 packSize = m_InStream.GetProcessedSize();
1684*f6dc9357SAndroid Build Coastguard Worker       RINOK(progress->SetRatioInfo(&packSize, &pos))
1685*f6dc9357SAndroid Build Coastguard Worker     }
1686*f6dc9357SAndroid Build Coastguard Worker     Byte b;
1687*f6dc9357SAndroid Build Coastguard Worker     if (!m_InStream.ReadByte(b))
1688*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
1689*f6dc9357SAndroid Build Coastguard Worker     const UInt64 rem = outSize - pos;
1690*f6dc9357SAndroid Build Coastguard Worker     if (b & 0x80)
1691*f6dc9357SAndroid Build Coastguard Worker     {
1692*f6dc9357SAndroid Build Coastguard Worker       unsigned num = (unsigned)b - 0x80 + 1;
1693*f6dc9357SAndroid Build Coastguard Worker       if (num > rem)
1694*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
1695*f6dc9357SAndroid Build Coastguard Worker       pos += num;
1696*f6dc9357SAndroid Build Coastguard Worker       do
1697*f6dc9357SAndroid Build Coastguard Worker       {
1698*f6dc9357SAndroid Build Coastguard Worker         if (!m_InStream.ReadByte(b))
1699*f6dc9357SAndroid Build Coastguard Worker           return S_FALSE;
1700*f6dc9357SAndroid Build Coastguard Worker         m_OutWindowStream.PutByte(b);
1701*f6dc9357SAndroid Build Coastguard Worker       }
1702*f6dc9357SAndroid Build Coastguard Worker       while (--num);
1703*f6dc9357SAndroid Build Coastguard Worker       continue;
1704*f6dc9357SAndroid Build Coastguard Worker     }
1705*f6dc9357SAndroid Build Coastguard Worker     Byte b1;
1706*f6dc9357SAndroid Build Coastguard Worker     if (!m_InStream.ReadByte(b1))
1707*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
1708*f6dc9357SAndroid Build Coastguard Worker 
1709*f6dc9357SAndroid Build Coastguard Worker     UInt32 len, dist;
1710*f6dc9357SAndroid Build Coastguard Worker 
1711*f6dc9357SAndroid Build Coastguard Worker     if (b & 0x40)
1712*f6dc9357SAndroid Build Coastguard Worker     {
1713*f6dc9357SAndroid Build Coastguard Worker       len = (UInt32)b - 0x40 + 4;
1714*f6dc9357SAndroid Build Coastguard Worker       Byte b2;
1715*f6dc9357SAndroid Build Coastguard Worker       if (!m_InStream.ReadByte(b2))
1716*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
1717*f6dc9357SAndroid Build Coastguard Worker       dist = ((UInt32)b1 << 8) + b2;
1718*f6dc9357SAndroid Build Coastguard Worker     }
1719*f6dc9357SAndroid Build Coastguard Worker     else
1720*f6dc9357SAndroid Build Coastguard Worker     {
1721*f6dc9357SAndroid Build Coastguard Worker       len = ((UInt32)b >> 2) + 3;
1722*f6dc9357SAndroid Build Coastguard Worker       dist = (((UInt32)b & 3) << 8) + b1;
1723*f6dc9357SAndroid Build Coastguard Worker     }
1724*f6dc9357SAndroid Build Coastguard Worker 
1725*f6dc9357SAndroid Build Coastguard Worker     if (/* dist >= pos || */ len > rem)
1726*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
1727*f6dc9357SAndroid Build Coastguard Worker     if (!m_OutWindowStream.CopyBlock(dist, len))
1728*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
1729*f6dc9357SAndroid Build Coastguard Worker     pos += len;
1730*f6dc9357SAndroid Build Coastguard Worker   }
1731*f6dc9357SAndroid Build Coastguard Worker   if (*inSize != m_InStream.GetProcessedSize())
1732*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
1733*f6dc9357SAndroid Build Coastguard Worker   coderReleaser.NeedFlush = false;
1734*f6dc9357SAndroid Build Coastguard Worker   return m_OutWindowStream.Flush();
1735*f6dc9357SAndroid Build Coastguard Worker 
1736*f6dc9357SAndroid Build Coastguard Worker   }
1737*f6dc9357SAndroid Build Coastguard Worker   catch(const CInBufferException &e) { return e.ErrorCode; }
1738*f6dc9357SAndroid Build Coastguard Worker   catch(const CLzOutWindowException &e) { return e.ErrorCode; }
1739*f6dc9357SAndroid Build Coastguard Worker   catch(...) { return S_FALSE; }
1740*f6dc9357SAndroid Build Coastguard Worker }
1741*f6dc9357SAndroid Build Coastguard Worker 
1742*f6dc9357SAndroid Build Coastguard Worker 
1743*f6dc9357SAndroid Build Coastguard Worker 
1744*f6dc9357SAndroid Build Coastguard Worker struct CDecoders
1745*f6dc9357SAndroid Build Coastguard Worker {
1746*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr2<ICompressCoder, NCompress::NZlib::CDecoder> zlib;
1747*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr2<ICompressCoder, NCompress::NBZip2::CDecoder> bzip2;
1748*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr2<ICompressCoder, NCompress::NLzfse::CDecoder> lzfse;
1749*f6dc9357SAndroid Build Coastguard Worker   CMyUniquePtr<NCompress::NXz::CDecoder> xz;
1750*f6dc9357SAndroid Build Coastguard Worker   CMyUniquePtr<CAdcDecoder> adc;
1751*f6dc9357SAndroid Build Coastguard Worker 
1752*f6dc9357SAndroid Build Coastguard Worker   HRESULT Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
1753*f6dc9357SAndroid Build Coastguard Worker     const CBlock &block, const UInt64 *unpSize, ICompressProgressInfo *progress);
1754*f6dc9357SAndroid Build Coastguard Worker };
1755*f6dc9357SAndroid Build Coastguard Worker 
Code(ISequentialInStream * inStream,ISequentialOutStream * outStream,const CBlock & block,const UInt64 * unpSize,ICompressProgressInfo * progress)1756*f6dc9357SAndroid Build Coastguard Worker HRESULT CDecoders::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
1757*f6dc9357SAndroid Build Coastguard Worker     const CBlock &block, const UInt64 *unpSize, ICompressProgressInfo *progress)
1758*f6dc9357SAndroid Build Coastguard Worker {
1759*f6dc9357SAndroid Build Coastguard Worker   HRESULT hres;
1760*f6dc9357SAndroid Build Coastguard Worker   UInt64 processed;
1761*f6dc9357SAndroid Build Coastguard Worker   switch (block.Type)
1762*f6dc9357SAndroid Build Coastguard Worker   {
1763*f6dc9357SAndroid Build Coastguard Worker     case METHOD_ADC:
1764*f6dc9357SAndroid Build Coastguard Worker       adc.Create_if_Empty();
1765*f6dc9357SAndroid Build Coastguard Worker       return adc->Code(inStream, outStream, &block.PackSize, unpSize, progress);
1766*f6dc9357SAndroid Build Coastguard Worker     case METHOD_LZFSE:
1767*f6dc9357SAndroid Build Coastguard Worker       lzfse.Create_if_Empty();
1768*f6dc9357SAndroid Build Coastguard Worker       return lzfse.Interface()->Code(inStream, outStream, &block.PackSize, unpSize, progress);
1769*f6dc9357SAndroid Build Coastguard Worker     case METHOD_ZLIB:
1770*f6dc9357SAndroid Build Coastguard Worker       zlib.Create_if_Empty();
1771*f6dc9357SAndroid Build Coastguard Worker       hres = zlib.Interface()->Code(inStream, outStream, NULL, unpSize, progress);
1772*f6dc9357SAndroid Build Coastguard Worker       processed = zlib->GetInputProcessedSize();
1773*f6dc9357SAndroid Build Coastguard Worker       break;
1774*f6dc9357SAndroid Build Coastguard Worker     case METHOD_BZIP2:
1775*f6dc9357SAndroid Build Coastguard Worker       bzip2.Create_if_Empty();
1776*f6dc9357SAndroid Build Coastguard Worker       hres = bzip2.Interface()->Code(inStream, outStream, NULL, unpSize, progress);
1777*f6dc9357SAndroid Build Coastguard Worker       processed = bzip2->GetInputProcessedSize();
1778*f6dc9357SAndroid Build Coastguard Worker       break;
1779*f6dc9357SAndroid Build Coastguard Worker     case METHOD_XZ:
1780*f6dc9357SAndroid Build Coastguard Worker       xz.Create_if_Empty();
1781*f6dc9357SAndroid Build Coastguard Worker       hres = xz->Decode(inStream, outStream, unpSize, true, progress);
1782*f6dc9357SAndroid Build Coastguard Worker       processed = xz->Stat.InSize;
1783*f6dc9357SAndroid Build Coastguard Worker       break;
1784*f6dc9357SAndroid Build Coastguard Worker     default:
1785*f6dc9357SAndroid Build Coastguard Worker       return E_NOTIMPL;
1786*f6dc9357SAndroid Build Coastguard Worker   }
1787*f6dc9357SAndroid Build Coastguard Worker   if (hres == S_OK && processed != block.PackSize)
1788*f6dc9357SAndroid Build Coastguard Worker     hres = S_FALSE;
1789*f6dc9357SAndroid Build Coastguard Worker   return hres;
1790*f6dc9357SAndroid Build Coastguard Worker }
1791*f6dc9357SAndroid Build Coastguard Worker 
1792*f6dc9357SAndroid Build Coastguard Worker 
Z7_COM7F_IMF(CHandler::Extract (const UInt32 * indices,UInt32 numItems,Int32 testMode,IArchiveExtractCallback * extractCallback))1793*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
1794*f6dc9357SAndroid Build Coastguard Worker     Int32 testMode, IArchiveExtractCallback *extractCallback))
1795*f6dc9357SAndroid Build Coastguard Worker {
1796*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_BEGIN
1797*f6dc9357SAndroid Build Coastguard Worker   const bool allFilesMode = (numItems == (UInt32)(Int32)-1);
1798*f6dc9357SAndroid Build Coastguard Worker   if (allFilesMode)
1799*f6dc9357SAndroid Build Coastguard Worker     numItems = _files.Size()
1800*f6dc9357SAndroid Build Coastguard Worker #ifdef DMG_SHOW_RAW
1801*f6dc9357SAndroid Build Coastguard Worker     + _extras.Size()
1802*f6dc9357SAndroid Build Coastguard Worker #endif
1803*f6dc9357SAndroid Build Coastguard Worker   ;
1804*f6dc9357SAndroid Build Coastguard Worker   if (numItems == 0)
1805*f6dc9357SAndroid Build Coastguard Worker     return S_OK;
1806*f6dc9357SAndroid Build Coastguard Worker   UInt64 totalSize = 0;
1807*f6dc9357SAndroid Build Coastguard Worker   UInt32 i;
1808*f6dc9357SAndroid Build Coastguard Worker 
1809*f6dc9357SAndroid Build Coastguard Worker   for (i = 0; i < numItems; i++)
1810*f6dc9357SAndroid Build Coastguard Worker   {
1811*f6dc9357SAndroid Build Coastguard Worker     const UInt32 index = allFilesMode ? i : indices[i];
1812*f6dc9357SAndroid Build Coastguard Worker #ifdef DMG_SHOW_RAW
1813*f6dc9357SAndroid Build Coastguard Worker     if (index >= _files.Size())
1814*f6dc9357SAndroid Build Coastguard Worker       totalSize += _extras[index - _files.Size()].Data.Size();
1815*f6dc9357SAndroid Build Coastguard Worker     else
1816*f6dc9357SAndroid Build Coastguard Worker #endif
1817*f6dc9357SAndroid Build Coastguard Worker       totalSize += _files[index].Size;
1818*f6dc9357SAndroid Build Coastguard Worker   }
1819*f6dc9357SAndroid Build Coastguard Worker   RINOK(extractCallback->SetTotal(totalSize))
1820*f6dc9357SAndroid Build Coastguard Worker 
1821*f6dc9357SAndroid Build Coastguard Worker   const size_t kZeroBufSize = 1 << 14;
1822*f6dc9357SAndroid Build Coastguard Worker   CAlignedBuffer1 zeroBuf(kZeroBufSize);
1823*f6dc9357SAndroid Build Coastguard Worker   memset(zeroBuf, 0, kZeroBufSize);
1824*f6dc9357SAndroid Build Coastguard Worker 
1825*f6dc9357SAndroid Build Coastguard Worker   CDecoders decoders;
1826*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr2_Create<ICompressCoder, NCompress::CCopyCoder> copyCoder;
1827*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr2_Create<ICompressProgressInfo, CLocalProgress> lps;
1828*f6dc9357SAndroid Build Coastguard Worker   lps->Init(extractCallback, false);
1829*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr2_Create<ISequentialInStream, CLimitedSequentialInStream> inStream;
1830*f6dc9357SAndroid Build Coastguard Worker   inStream->SetStream(_inStream);
1831*f6dc9357SAndroid Build Coastguard Worker 
1832*f6dc9357SAndroid Build Coastguard Worker   UInt64 total_PackSize = 0;
1833*f6dc9357SAndroid Build Coastguard Worker   UInt64 total_UnpackSize = 0;
1834*f6dc9357SAndroid Build Coastguard Worker   UInt64 cur_PackSize = 0;
1835*f6dc9357SAndroid Build Coastguard Worker   UInt64 cur_UnpackSize = 0;
1836*f6dc9357SAndroid Build Coastguard Worker 
1837*f6dc9357SAndroid Build Coastguard Worker   for (i = 0;; i++,
1838*f6dc9357SAndroid Build Coastguard Worker         total_PackSize   += cur_PackSize,
1839*f6dc9357SAndroid Build Coastguard Worker         total_UnpackSize += cur_UnpackSize)
1840*f6dc9357SAndroid Build Coastguard Worker   {
1841*f6dc9357SAndroid Build Coastguard Worker     lps->InSize = total_PackSize;
1842*f6dc9357SAndroid Build Coastguard Worker     lps->OutSize = total_UnpackSize;
1843*f6dc9357SAndroid Build Coastguard Worker     cur_PackSize = 0;
1844*f6dc9357SAndroid Build Coastguard Worker     cur_UnpackSize = 0;
1845*f6dc9357SAndroid Build Coastguard Worker     RINOK(lps->SetCur())
1846*f6dc9357SAndroid Build Coastguard Worker     if (i >= numItems)
1847*f6dc9357SAndroid Build Coastguard Worker       return S_OK;
1848*f6dc9357SAndroid Build Coastguard Worker 
1849*f6dc9357SAndroid Build Coastguard Worker     Int32 opRes = NExtract::NOperationResult::kOK;
1850*f6dc9357SAndroid Build Coastguard Worker    {
1851*f6dc9357SAndroid Build Coastguard Worker     CMyComPtr<ISequentialOutStream> realOutStream;
1852*f6dc9357SAndroid Build Coastguard Worker     const Int32 askMode = testMode ?
1853*f6dc9357SAndroid Build Coastguard Worker         NExtract::NAskMode::kTest :
1854*f6dc9357SAndroid Build Coastguard Worker         NExtract::NAskMode::kExtract;
1855*f6dc9357SAndroid Build Coastguard Worker     const UInt32 index = allFilesMode ? i : indices[i];
1856*f6dc9357SAndroid Build Coastguard Worker     RINOK(extractCallback->GetStream(index, &realOutStream, askMode))
1857*f6dc9357SAndroid Build Coastguard Worker 
1858*f6dc9357SAndroid Build Coastguard Worker     if (!testMode && !realOutStream)
1859*f6dc9357SAndroid Build Coastguard Worker       continue;
1860*f6dc9357SAndroid Build Coastguard Worker     RINOK(extractCallback->PrepareOperation(askMode))
1861*f6dc9357SAndroid Build Coastguard Worker 
1862*f6dc9357SAndroid Build Coastguard Worker #ifdef DMG_SHOW_RAW
1863*f6dc9357SAndroid Build Coastguard Worker     if (index >= _files.Size())
1864*f6dc9357SAndroid Build Coastguard Worker     {
1865*f6dc9357SAndroid Build Coastguard Worker       const CByteBuffer &buf = _extras[index - _files.Size()].Data;
1866*f6dc9357SAndroid Build Coastguard Worker       if (realOutStream)
1867*f6dc9357SAndroid Build Coastguard Worker         RINOK(WriteStream(realOutStream, buf, buf.Size()))
1868*f6dc9357SAndroid Build Coastguard Worker       cur_PackSize = cur_UnpackSize = buf.Size();
1869*f6dc9357SAndroid Build Coastguard Worker     }
1870*f6dc9357SAndroid Build Coastguard Worker     else
1871*f6dc9357SAndroid Build Coastguard Worker #endif
1872*f6dc9357SAndroid Build Coastguard Worker     {
1873*f6dc9357SAndroid Build Coastguard Worker       const CFile &item = _files[index];
1874*f6dc9357SAndroid Build Coastguard Worker       cur_PackSize = item.PackSize;
1875*f6dc9357SAndroid Build Coastguard Worker       cur_UnpackSize = item.Size;
1876*f6dc9357SAndroid Build Coastguard Worker 
1877*f6dc9357SAndroid Build Coastguard Worker       if (!item.IsCorrect)
1878*f6dc9357SAndroid Build Coastguard Worker         opRes = NExtract::NOperationResult::kHeadersError;
1879*f6dc9357SAndroid Build Coastguard Worker       else
1880*f6dc9357SAndroid Build Coastguard Worker       {
1881*f6dc9357SAndroid Build Coastguard Worker         CMyComPtr2_Create<ISequentialOutStream, COutStreamWithCRC> outCrcStream;
1882*f6dc9357SAndroid Build Coastguard Worker         outCrcStream->SetStream(realOutStream);
1883*f6dc9357SAndroid Build Coastguard Worker         // realOutStream.Release();
1884*f6dc9357SAndroid Build Coastguard Worker         const bool needCrc = item.Checksum.IsCrc32();
1885*f6dc9357SAndroid Build Coastguard Worker         outCrcStream->Init(needCrc);
1886*f6dc9357SAndroid Build Coastguard Worker 
1887*f6dc9357SAndroid Build Coastguard Worker         CMyComPtr2_Create<ISequentialOutStream, CLimitedSequentialOutStream> outStream;
1888*f6dc9357SAndroid Build Coastguard Worker         outStream->SetStream(outCrcStream);
1889*f6dc9357SAndroid Build Coastguard Worker 
1890*f6dc9357SAndroid Build Coastguard Worker         UInt64 unpPos = 0;
1891*f6dc9357SAndroid Build Coastguard Worker         UInt64 packPos = 0;
1892*f6dc9357SAndroid Build Coastguard Worker 
1893*f6dc9357SAndroid Build Coastguard Worker         FOR_VECTOR (blockIndex, item.Blocks)
1894*f6dc9357SAndroid Build Coastguard Worker         {
1895*f6dc9357SAndroid Build Coastguard Worker           lps->InSize = total_PackSize + packPos;
1896*f6dc9357SAndroid Build Coastguard Worker           lps->OutSize = total_UnpackSize + unpPos;
1897*f6dc9357SAndroid Build Coastguard Worker           RINOK(lps->SetCur())
1898*f6dc9357SAndroid Build Coastguard Worker 
1899*f6dc9357SAndroid Build Coastguard Worker           const CBlock &block = item.Blocks[blockIndex];
1900*f6dc9357SAndroid Build Coastguard Worker           // if (!block.ThereAreDataInBlock()) continue;
1901*f6dc9357SAndroid Build Coastguard Worker 
1902*f6dc9357SAndroid Build Coastguard Worker           packPos += block.PackSize;
1903*f6dc9357SAndroid Build Coastguard Worker           if (block.UnpPos != unpPos)
1904*f6dc9357SAndroid Build Coastguard Worker           {
1905*f6dc9357SAndroid Build Coastguard Worker             opRes = NExtract::NOperationResult::kHeadersError;
1906*f6dc9357SAndroid Build Coastguard Worker             break;
1907*f6dc9357SAndroid Build Coastguard Worker           }
1908*f6dc9357SAndroid Build Coastguard Worker 
1909*f6dc9357SAndroid Build Coastguard Worker           RINOK(InStream_SeekSet(_inStream, _startPos + _dataForkPair.Offset + item.StartPackPos + block.PackPos))
1910*f6dc9357SAndroid Build Coastguard Worker           inStream->Init(block.PackSize);
1911*f6dc9357SAndroid Build Coastguard Worker 
1912*f6dc9357SAndroid Build Coastguard Worker           const UInt64 unpSize = item.GetUnpackSize_of_Block(blockIndex);
1913*f6dc9357SAndroid Build Coastguard Worker 
1914*f6dc9357SAndroid Build Coastguard Worker           outStream->Init(unpSize);
1915*f6dc9357SAndroid Build Coastguard Worker           HRESULT res = S_OK;
1916*f6dc9357SAndroid Build Coastguard Worker 
1917*f6dc9357SAndroid Build Coastguard Worker           outCrcStream->EnableCalc(needCrc && block.NeedCrc());
1918*f6dc9357SAndroid Build Coastguard Worker 
1919*f6dc9357SAndroid Build Coastguard Worker           if (block.IsZeroMethod())
1920*f6dc9357SAndroid Build Coastguard Worker           {
1921*f6dc9357SAndroid Build Coastguard Worker             if (block.PackSize != 0)
1922*f6dc9357SAndroid Build Coastguard Worker               opRes = NExtract::NOperationResult::kUnsupportedMethod;
1923*f6dc9357SAndroid Build Coastguard Worker           }
1924*f6dc9357SAndroid Build Coastguard Worker           else if (block.Type == METHOD_COPY)
1925*f6dc9357SAndroid Build Coastguard Worker           {
1926*f6dc9357SAndroid Build Coastguard Worker             if (unpSize != block.PackSize)
1927*f6dc9357SAndroid Build Coastguard Worker               opRes = NExtract::NOperationResult::kUnsupportedMethod;
1928*f6dc9357SAndroid Build Coastguard Worker             else
1929*f6dc9357SAndroid Build Coastguard Worker               res = copyCoder.Interface()->Code(inStream, outStream, NULL, NULL, lps);
1930*f6dc9357SAndroid Build Coastguard Worker           }
1931*f6dc9357SAndroid Build Coastguard Worker           else
1932*f6dc9357SAndroid Build Coastguard Worker             res = decoders.Code(inStream, outStream, block, &unpSize, lps);
1933*f6dc9357SAndroid Build Coastguard Worker 
1934*f6dc9357SAndroid Build Coastguard Worker           if (res != S_OK)
1935*f6dc9357SAndroid Build Coastguard Worker           {
1936*f6dc9357SAndroid Build Coastguard Worker             if (res != S_FALSE)
1937*f6dc9357SAndroid Build Coastguard Worker             {
1938*f6dc9357SAndroid Build Coastguard Worker               if (res != E_NOTIMPL)
1939*f6dc9357SAndroid Build Coastguard Worker                 return res;
1940*f6dc9357SAndroid Build Coastguard Worker               opRes = NExtract::NOperationResult::kUnsupportedMethod;
1941*f6dc9357SAndroid Build Coastguard Worker             }
1942*f6dc9357SAndroid Build Coastguard Worker             if (opRes == NExtract::NOperationResult::kOK)
1943*f6dc9357SAndroid Build Coastguard Worker               opRes = NExtract::NOperationResult::kDataError;
1944*f6dc9357SAndroid Build Coastguard Worker           }
1945*f6dc9357SAndroid Build Coastguard Worker 
1946*f6dc9357SAndroid Build Coastguard Worker           unpPos += unpSize;
1947*f6dc9357SAndroid Build Coastguard Worker 
1948*f6dc9357SAndroid Build Coastguard Worker           if (!outStream->IsFinishedOK())
1949*f6dc9357SAndroid Build Coastguard Worker           {
1950*f6dc9357SAndroid Build Coastguard Worker             if (!block.IsZeroMethod() && opRes == NExtract::NOperationResult::kOK)
1951*f6dc9357SAndroid Build Coastguard Worker               opRes = NExtract::NOperationResult::kDataError;
1952*f6dc9357SAndroid Build Coastguard Worker 
1953*f6dc9357SAndroid Build Coastguard Worker             for (unsigned k = 0;;)
1954*f6dc9357SAndroid Build Coastguard Worker             {
1955*f6dc9357SAndroid Build Coastguard Worker               const UInt64 rem = outStream->GetRem();
1956*f6dc9357SAndroid Build Coastguard Worker               if (rem == 0)
1957*f6dc9357SAndroid Build Coastguard Worker                 break;
1958*f6dc9357SAndroid Build Coastguard Worker               size_t size = kZeroBufSize;
1959*f6dc9357SAndroid Build Coastguard Worker               if (size > rem)
1960*f6dc9357SAndroid Build Coastguard Worker                 size = (size_t)rem;
1961*f6dc9357SAndroid Build Coastguard Worker               RINOK(WriteStream(outStream, zeroBuf, size))
1962*f6dc9357SAndroid Build Coastguard Worker               k++;
1963*f6dc9357SAndroid Build Coastguard Worker               if ((k & 0xfff) == 0)
1964*f6dc9357SAndroid Build Coastguard Worker               {
1965*f6dc9357SAndroid Build Coastguard Worker                 lps->OutSize = total_UnpackSize + unpPos - outStream->GetRem();
1966*f6dc9357SAndroid Build Coastguard Worker                 RINOK(lps->SetCur())
1967*f6dc9357SAndroid Build Coastguard Worker               }
1968*f6dc9357SAndroid Build Coastguard Worker             }
1969*f6dc9357SAndroid Build Coastguard Worker           }
1970*f6dc9357SAndroid Build Coastguard Worker         }
1971*f6dc9357SAndroid Build Coastguard Worker         if (needCrc && opRes == NExtract::NOperationResult::kOK)
1972*f6dc9357SAndroid Build Coastguard Worker         {
1973*f6dc9357SAndroid Build Coastguard Worker           if (outCrcStream->GetCRC() != item.Checksum.GetCrc32())
1974*f6dc9357SAndroid Build Coastguard Worker             opRes = NExtract::NOperationResult::kCRCError;
1975*f6dc9357SAndroid Build Coastguard Worker         }
1976*f6dc9357SAndroid Build Coastguard Worker       }
1977*f6dc9357SAndroid Build Coastguard Worker     }
1978*f6dc9357SAndroid Build Coastguard Worker    }
1979*f6dc9357SAndroid Build Coastguard Worker     RINOK(extractCallback->SetOperationResult(opRes))
1980*f6dc9357SAndroid Build Coastguard Worker   }
1981*f6dc9357SAndroid Build Coastguard Worker 
1982*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_END
1983*f6dc9357SAndroid Build Coastguard Worker }
1984*f6dc9357SAndroid Build Coastguard Worker 
1985*f6dc9357SAndroid Build Coastguard Worker 
1986*f6dc9357SAndroid Build Coastguard Worker 
1987*f6dc9357SAndroid Build Coastguard Worker 
1988*f6dc9357SAndroid Build Coastguard Worker struct CChunk
1989*f6dc9357SAndroid Build Coastguard Worker {
1990*f6dc9357SAndroid Build Coastguard Worker   int BlockIndex;
1991*f6dc9357SAndroid Build Coastguard Worker   UInt64 AccessMark;
1992*f6dc9357SAndroid Build Coastguard Worker   Byte *Buf;
1993*f6dc9357SAndroid Build Coastguard Worker   size_t BufSize;
1994*f6dc9357SAndroid Build Coastguard Worker 
FreeNArchive::CChunk1995*f6dc9357SAndroid Build Coastguard Worker   void Free()
1996*f6dc9357SAndroid Build Coastguard Worker   {
1997*f6dc9357SAndroid Build Coastguard Worker     z7_AlignedFree(Buf);
1998*f6dc9357SAndroid Build Coastguard Worker     Buf = NULL;
1999*f6dc9357SAndroid Build Coastguard Worker     BufSize = 0;
2000*f6dc9357SAndroid Build Coastguard Worker   }
AllocNArchive::CChunk2001*f6dc9357SAndroid Build Coastguard Worker   void Alloc(size_t size)
2002*f6dc9357SAndroid Build Coastguard Worker   {
2003*f6dc9357SAndroid Build Coastguard Worker     Buf = (Byte *)z7_AlignedAlloc(size);
2004*f6dc9357SAndroid Build Coastguard Worker   }
2005*f6dc9357SAndroid Build Coastguard Worker };
2006*f6dc9357SAndroid Build Coastguard Worker 
2007*f6dc9357SAndroid Build Coastguard Worker 
2008*f6dc9357SAndroid Build Coastguard Worker Z7_CLASS_IMP_IInStream(
2009*f6dc9357SAndroid Build Coastguard Worker   CInStream
2010*f6dc9357SAndroid Build Coastguard Worker )
2011*f6dc9357SAndroid Build Coastguard Worker   bool _errorMode;
2012*f6dc9357SAndroid Build Coastguard Worker   UInt64 _virtPos;
2013*f6dc9357SAndroid Build Coastguard Worker   int _latestChunk;
2014*f6dc9357SAndroid Build Coastguard Worker   int _latestBlock;
2015*f6dc9357SAndroid Build Coastguard Worker   UInt64 _accessMark;
2016*f6dc9357SAndroid Build Coastguard Worker   UInt64 _chunks_TotalSize;
2017*f6dc9357SAndroid Build Coastguard Worker   CRecordVector<CChunk> _chunks;
2018*f6dc9357SAndroid Build Coastguard Worker 
2019*f6dc9357SAndroid Build Coastguard Worker public:
2020*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr<IInStream> Stream;
2021*f6dc9357SAndroid Build Coastguard Worker   const CFile *File;
2022*f6dc9357SAndroid Build Coastguard Worker   UInt64 Size;
2023*f6dc9357SAndroid Build Coastguard Worker private:
2024*f6dc9357SAndroid Build Coastguard Worker   UInt64 _startPos;
2025*f6dc9357SAndroid Build Coastguard Worker 
2026*f6dc9357SAndroid Build Coastguard Worker   ~CInStream();
2027*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr2<ISequentialOutStream, CBufPtrSeqOutStream> outStream;
2028*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr2<ISequentialInStream, CLimitedSequentialInStream> inStream;
2029*f6dc9357SAndroid Build Coastguard Worker   CDecoders decoders;
2030*f6dc9357SAndroid Build Coastguard Worker public:
2031*f6dc9357SAndroid Build Coastguard Worker 
2032*f6dc9357SAndroid Build Coastguard Worker   // HRESULT
2033*f6dc9357SAndroid Build Coastguard Worker   void Init(UInt64 startPos)
2034*f6dc9357SAndroid Build Coastguard Worker   {
2035*f6dc9357SAndroid Build Coastguard Worker     _errorMode = false;
2036*f6dc9357SAndroid Build Coastguard Worker     _startPos = startPos;
2037*f6dc9357SAndroid Build Coastguard Worker     _virtPos = 0;
2038*f6dc9357SAndroid Build Coastguard Worker     _latestChunk = -1;
2039*f6dc9357SAndroid Build Coastguard Worker     _latestBlock = -1;
2040*f6dc9357SAndroid Build Coastguard Worker     _accessMark = 0;
2041*f6dc9357SAndroid Build Coastguard Worker     _chunks_TotalSize = 0;
2042*f6dc9357SAndroid Build Coastguard Worker 
2043*f6dc9357SAndroid Build Coastguard Worker     inStream.Create_if_Empty();
2044*f6dc9357SAndroid Build Coastguard Worker     inStream->SetStream(Stream);
2045*f6dc9357SAndroid Build Coastguard Worker 
2046*f6dc9357SAndroid Build Coastguard Worker     outStream.Create_if_Empty();
2047*f6dc9357SAndroid Build Coastguard Worker     // return S_OK;
2048*f6dc9357SAndroid Build Coastguard Worker   }
2049*f6dc9357SAndroid Build Coastguard Worker };
2050*f6dc9357SAndroid Build Coastguard Worker 
2051*f6dc9357SAndroid Build Coastguard Worker 
2052*f6dc9357SAndroid Build Coastguard Worker CInStream::~CInStream()
2053*f6dc9357SAndroid Build Coastguard Worker {
2054*f6dc9357SAndroid Build Coastguard Worker   unsigned i = _chunks.Size();
2055*f6dc9357SAndroid Build Coastguard Worker   while (i)
2056*f6dc9357SAndroid Build Coastguard Worker     _chunks[--i].Free();
2057*f6dc9357SAndroid Build Coastguard Worker }
2058*f6dc9357SAndroid Build Coastguard Worker 
2059*f6dc9357SAndroid Build Coastguard Worker static unsigned FindBlock(const CRecordVector<CBlock> &blocks, UInt64 pos)
2060*f6dc9357SAndroid Build Coastguard Worker {
2061*f6dc9357SAndroid Build Coastguard Worker   unsigned left = 0, right = blocks.Size();
2062*f6dc9357SAndroid Build Coastguard Worker   for (;;)
2063*f6dc9357SAndroid Build Coastguard Worker   {
2064*f6dc9357SAndroid Build Coastguard Worker     const unsigned mid = (left + right) / 2;
2065*f6dc9357SAndroid Build Coastguard Worker     if (mid == left)
2066*f6dc9357SAndroid Build Coastguard Worker       return left;
2067*f6dc9357SAndroid Build Coastguard Worker     if (pos < blocks[mid].UnpPos)
2068*f6dc9357SAndroid Build Coastguard Worker       right = mid;
2069*f6dc9357SAndroid Build Coastguard Worker     else
2070*f6dc9357SAndroid Build Coastguard Worker       left = mid;
2071*f6dc9357SAndroid Build Coastguard Worker   }
2072*f6dc9357SAndroid Build Coastguard Worker }
2073*f6dc9357SAndroid Build Coastguard Worker 
2074*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CInStream::Read(void *data, UInt32 size, UInt32 *processedSize))
2075*f6dc9357SAndroid Build Coastguard Worker {
2076*f6dc9357SAndroid Build Coastguard Worker   // COM_TRY_BEGIN
2077*f6dc9357SAndroid Build Coastguard Worker   try {
2078*f6dc9357SAndroid Build Coastguard Worker 
2079*f6dc9357SAndroid Build Coastguard Worker   if (_errorMode)
2080*f6dc9357SAndroid Build Coastguard Worker     return E_OUTOFMEMORY;
2081*f6dc9357SAndroid Build Coastguard Worker 
2082*f6dc9357SAndroid Build Coastguard Worker   if (processedSize)
2083*f6dc9357SAndroid Build Coastguard Worker     *processedSize = 0;
2084*f6dc9357SAndroid Build Coastguard Worker   if (size == 0)
2085*f6dc9357SAndroid Build Coastguard Worker     return S_OK;
2086*f6dc9357SAndroid Build Coastguard Worker   if (_virtPos >= Size)
2087*f6dc9357SAndroid Build Coastguard Worker     return S_OK; // (Size == _virtPos) ? S_OK: E_FAIL;
2088*f6dc9357SAndroid Build Coastguard Worker   {
2089*f6dc9357SAndroid Build Coastguard Worker     const UInt64 rem = Size - _virtPos;
2090*f6dc9357SAndroid Build Coastguard Worker     if (size > rem)
2091*f6dc9357SAndroid Build Coastguard Worker       size = (UInt32)rem;
2092*f6dc9357SAndroid Build Coastguard Worker   }
2093*f6dc9357SAndroid Build Coastguard Worker 
2094*f6dc9357SAndroid Build Coastguard Worker   if (_latestBlock >= 0)
2095*f6dc9357SAndroid Build Coastguard Worker   {
2096*f6dc9357SAndroid Build Coastguard Worker     const CBlock &block = File->Blocks[(unsigned)_latestBlock];
2097*f6dc9357SAndroid Build Coastguard Worker     if (_virtPos < block.UnpPos ||
2098*f6dc9357SAndroid Build Coastguard Worker         _virtPos - block.UnpPos >= File->GetUnpackSize_of_Block((unsigned)_latestBlock))
2099*f6dc9357SAndroid Build Coastguard Worker       _latestBlock = -1;
2100*f6dc9357SAndroid Build Coastguard Worker   }
2101*f6dc9357SAndroid Build Coastguard Worker 
2102*f6dc9357SAndroid Build Coastguard Worker   if (_latestBlock < 0)
2103*f6dc9357SAndroid Build Coastguard Worker   {
2104*f6dc9357SAndroid Build Coastguard Worker     _latestChunk = -1;
2105*f6dc9357SAndroid Build Coastguard Worker     const unsigned blockIndex = FindBlock(File->Blocks, _virtPos);
2106*f6dc9357SAndroid Build Coastguard Worker     const CBlock &block = File->Blocks[blockIndex];
2107*f6dc9357SAndroid Build Coastguard Worker     const UInt64 unpSize = File->GetUnpackSize_of_Block(blockIndex);
2108*f6dc9357SAndroid Build Coastguard Worker 
2109*f6dc9357SAndroid Build Coastguard Worker     if (block.NeedAllocateBuffer()
2110*f6dc9357SAndroid Build Coastguard Worker         && unpSize <= k_Chunk_Size_MAX)
2111*f6dc9357SAndroid Build Coastguard Worker     {
2112*f6dc9357SAndroid Build Coastguard Worker       unsigned i = 0;
2113*f6dc9357SAndroid Build Coastguard Worker       {
2114*f6dc9357SAndroid Build Coastguard Worker         unsigned numChunks = _chunks.Size();
2115*f6dc9357SAndroid Build Coastguard Worker         if (numChunks)
2116*f6dc9357SAndroid Build Coastguard Worker         {
2117*f6dc9357SAndroid Build Coastguard Worker           const CChunk *chunk = _chunks.ConstData();
2118*f6dc9357SAndroid Build Coastguard Worker           do
2119*f6dc9357SAndroid Build Coastguard Worker           {
2120*f6dc9357SAndroid Build Coastguard Worker             if (chunk->BlockIndex == (int)blockIndex)
2121*f6dc9357SAndroid Build Coastguard Worker               break;
2122*f6dc9357SAndroid Build Coastguard Worker             chunk++;
2123*f6dc9357SAndroid Build Coastguard Worker           }
2124*f6dc9357SAndroid Build Coastguard Worker           while (--numChunks);
2125*f6dc9357SAndroid Build Coastguard Worker           i = _chunks.Size() - numChunks;
2126*f6dc9357SAndroid Build Coastguard Worker         }
2127*f6dc9357SAndroid Build Coastguard Worker       }
2128*f6dc9357SAndroid Build Coastguard Worker       if (i != _chunks.Size())
2129*f6dc9357SAndroid Build Coastguard Worker         _latestChunk = (int)i;
2130*f6dc9357SAndroid Build Coastguard Worker       else
2131*f6dc9357SAndroid Build Coastguard Worker       {
2132*f6dc9357SAndroid Build Coastguard Worker         unsigned chunkIndex;
2133*f6dc9357SAndroid Build Coastguard Worker         for (;;)
2134*f6dc9357SAndroid Build Coastguard Worker         {
2135*f6dc9357SAndroid Build Coastguard Worker           if (_chunks.IsEmpty() ||
2136*f6dc9357SAndroid Build Coastguard Worker               (_chunks.Size() < k_NumChunks_MAX
2137*f6dc9357SAndroid Build Coastguard Worker               && _chunks_TotalSize + unpSize <= k_Chunks_TotalSize_MAX))
2138*f6dc9357SAndroid Build Coastguard Worker           {
2139*f6dc9357SAndroid Build Coastguard Worker             CChunk chunk;
2140*f6dc9357SAndroid Build Coastguard Worker             chunk.Buf = NULL;
2141*f6dc9357SAndroid Build Coastguard Worker             chunk.BufSize = 0;
2142*f6dc9357SAndroid Build Coastguard Worker             chunk.BlockIndex = -1;
2143*f6dc9357SAndroid Build Coastguard Worker             chunk.AccessMark = 0;
2144*f6dc9357SAndroid Build Coastguard Worker             chunkIndex = _chunks.Add(chunk);
2145*f6dc9357SAndroid Build Coastguard Worker             break;
2146*f6dc9357SAndroid Build Coastguard Worker           }
2147*f6dc9357SAndroid Build Coastguard Worker           chunkIndex = 0;
2148*f6dc9357SAndroid Build Coastguard Worker           if (_chunks.Size() == 1)
2149*f6dc9357SAndroid Build Coastguard Worker             break;
2150*f6dc9357SAndroid Build Coastguard Worker           {
2151*f6dc9357SAndroid Build Coastguard Worker             const CChunk *chunks = _chunks.ConstData();
2152*f6dc9357SAndroid Build Coastguard Worker             UInt64 accessMark_min = chunks[chunkIndex].AccessMark;
2153*f6dc9357SAndroid Build Coastguard Worker             const unsigned numChunks = _chunks.Size();
2154*f6dc9357SAndroid Build Coastguard Worker             for (i = 1; i < numChunks; i++)
2155*f6dc9357SAndroid Build Coastguard Worker             {
2156*f6dc9357SAndroid Build Coastguard Worker               if (chunks[i].AccessMark < accessMark_min)
2157*f6dc9357SAndroid Build Coastguard Worker               {
2158*f6dc9357SAndroid Build Coastguard Worker                 chunkIndex = i;
2159*f6dc9357SAndroid Build Coastguard Worker                 accessMark_min = chunks[i].AccessMark;
2160*f6dc9357SAndroid Build Coastguard Worker               }
2161*f6dc9357SAndroid Build Coastguard Worker             }
2162*f6dc9357SAndroid Build Coastguard Worker           }
2163*f6dc9357SAndroid Build Coastguard Worker           {
2164*f6dc9357SAndroid Build Coastguard Worker             CChunk &chunk = _chunks[chunkIndex];
2165*f6dc9357SAndroid Build Coastguard Worker             const UInt64 newTotalSize = _chunks_TotalSize - chunk.BufSize;
2166*f6dc9357SAndroid Build Coastguard Worker             if (newTotalSize + unpSize <= k_Chunks_TotalSize_MAX)
2167*f6dc9357SAndroid Build Coastguard Worker               break;
2168*f6dc9357SAndroid Build Coastguard Worker             _chunks_TotalSize = newTotalSize;
2169*f6dc9357SAndroid Build Coastguard Worker             chunk.Free();
2170*f6dc9357SAndroid Build Coastguard Worker           }
2171*f6dc9357SAndroid Build Coastguard Worker           // we have called chunk.Free() before, because
2172*f6dc9357SAndroid Build Coastguard Worker           // _chunks.Delete() doesn't call chunk.Free().
2173*f6dc9357SAndroid Build Coastguard Worker           _chunks.Delete(chunkIndex);
2174*f6dc9357SAndroid Build Coastguard Worker           PRF(printf("\n++num_chunks=%u, _chunks_TotalSize = %u\n", (unsigned)_chunks.Size(), (unsigned)_chunks_TotalSize);)
2175*f6dc9357SAndroid Build Coastguard Worker         }
2176*f6dc9357SAndroid Build Coastguard Worker 
2177*f6dc9357SAndroid Build Coastguard Worker         CChunk &chunk = _chunks[chunkIndex];
2178*f6dc9357SAndroid Build Coastguard Worker         chunk.BlockIndex = -1;
2179*f6dc9357SAndroid Build Coastguard Worker         chunk.AccessMark = 0;
2180*f6dc9357SAndroid Build Coastguard Worker 
2181*f6dc9357SAndroid Build Coastguard Worker         if (chunk.BufSize < unpSize)
2182*f6dc9357SAndroid Build Coastguard Worker         {
2183*f6dc9357SAndroid Build Coastguard Worker           _chunks_TotalSize -= chunk.BufSize;
2184*f6dc9357SAndroid Build Coastguard Worker           chunk.Free();
2185*f6dc9357SAndroid Build Coastguard Worker           // if (unpSize > k_Chunk_Size_MAX) return E_FAIL;
2186*f6dc9357SAndroid Build Coastguard Worker           chunk.Alloc((size_t)unpSize);
2187*f6dc9357SAndroid Build Coastguard Worker           if (!chunk.Buf)
2188*f6dc9357SAndroid Build Coastguard Worker             return E_OUTOFMEMORY;
2189*f6dc9357SAndroid Build Coastguard Worker           chunk.BufSize = (size_t)unpSize;
2190*f6dc9357SAndroid Build Coastguard Worker           _chunks_TotalSize += chunk.BufSize;
2191*f6dc9357SAndroid Build Coastguard Worker         }
2192*f6dc9357SAndroid Build Coastguard Worker 
2193*f6dc9357SAndroid Build Coastguard Worker         RINOK(InStream_SeekSet(Stream, _startPos + File->StartPackPos + block.PackPos))
2194*f6dc9357SAndroid Build Coastguard Worker 
2195*f6dc9357SAndroid Build Coastguard Worker         inStream->Init(block.PackSize);
2196*f6dc9357SAndroid Build Coastguard Worker #ifdef Z7_DMG_USE_CACHE_FOR_COPY_BLOCKS
2197*f6dc9357SAndroid Build Coastguard Worker         if (block.Type == METHOD_COPY)
2198*f6dc9357SAndroid Build Coastguard Worker         {
2199*f6dc9357SAndroid Build Coastguard Worker           if (block.PackSize != unpSize)
2200*f6dc9357SAndroid Build Coastguard Worker             return E_FAIL;
2201*f6dc9357SAndroid Build Coastguard Worker           RINOK(ReadStream_FAIL(inStream, chunk.Buf, (size_t)unpSize))
2202*f6dc9357SAndroid Build Coastguard Worker         }
2203*f6dc9357SAndroid Build Coastguard Worker         else
2204*f6dc9357SAndroid Build Coastguard Worker #endif
2205*f6dc9357SAndroid Build Coastguard Worker         {
2206*f6dc9357SAndroid Build Coastguard Worker           outStream->Init(chunk.Buf, (size_t)unpSize);
2207*f6dc9357SAndroid Build Coastguard Worker           RINOK(decoders.Code(inStream, outStream, block, &unpSize, NULL))
2208*f6dc9357SAndroid Build Coastguard Worker           if (outStream->GetPos() != unpSize)
2209*f6dc9357SAndroid Build Coastguard Worker             return E_FAIL;
2210*f6dc9357SAndroid Build Coastguard Worker         }
2211*f6dc9357SAndroid Build Coastguard Worker         chunk.BlockIndex = (int)blockIndex;
2212*f6dc9357SAndroid Build Coastguard Worker         _latestChunk = (int)chunkIndex;
2213*f6dc9357SAndroid Build Coastguard Worker       }
2214*f6dc9357SAndroid Build Coastguard Worker 
2215*f6dc9357SAndroid Build Coastguard Worker       _chunks[_latestChunk].AccessMark = _accessMark++;
2216*f6dc9357SAndroid Build Coastguard Worker     }
2217*f6dc9357SAndroid Build Coastguard Worker 
2218*f6dc9357SAndroid Build Coastguard Worker     _latestBlock = (int)blockIndex;
2219*f6dc9357SAndroid Build Coastguard Worker   }
2220*f6dc9357SAndroid Build Coastguard Worker 
2221*f6dc9357SAndroid Build Coastguard Worker   const CBlock &block = File->Blocks[(unsigned)_latestBlock];
2222*f6dc9357SAndroid Build Coastguard Worker   const UInt64 offset = _virtPos - block.UnpPos;
2223*f6dc9357SAndroid Build Coastguard Worker   {
2224*f6dc9357SAndroid Build Coastguard Worker     const UInt64 rem = File->GetUnpackSize_of_Block((unsigned)_latestBlock) - offset;
2225*f6dc9357SAndroid Build Coastguard Worker     if (size > rem)
2226*f6dc9357SAndroid Build Coastguard Worker       size = (UInt32)rem;
2227*f6dc9357SAndroid Build Coastguard Worker     if (size == 0) // it's unexpected case. but we check it.
2228*f6dc9357SAndroid Build Coastguard Worker       return S_OK;
2229*f6dc9357SAndroid Build Coastguard Worker   }
2230*f6dc9357SAndroid Build Coastguard Worker   HRESULT res = S_OK;
2231*f6dc9357SAndroid Build Coastguard Worker 
2232*f6dc9357SAndroid Build Coastguard Worker   if (block.IsZeroMethod())
2233*f6dc9357SAndroid Build Coastguard Worker     memset(data, 0, size);
2234*f6dc9357SAndroid Build Coastguard Worker   else if (_latestChunk >= 0)
2235*f6dc9357SAndroid Build Coastguard Worker     memcpy(data, _chunks[_latestChunk].Buf + (size_t)offset, size);
2236*f6dc9357SAndroid Build Coastguard Worker   else
2237*f6dc9357SAndroid Build Coastguard Worker   {
2238*f6dc9357SAndroid Build Coastguard Worker     if (block.Type != METHOD_COPY)
2239*f6dc9357SAndroid Build Coastguard Worker       return E_FAIL;
2240*f6dc9357SAndroid Build Coastguard Worker     RINOK(InStream_SeekSet(Stream, _startPos + File->StartPackPos + block.PackPos + offset))
2241*f6dc9357SAndroid Build Coastguard Worker     res = Stream->Read(data, size, &size);
2242*f6dc9357SAndroid Build Coastguard Worker   }
2243*f6dc9357SAndroid Build Coastguard Worker 
2244*f6dc9357SAndroid Build Coastguard Worker   _virtPos += size;
2245*f6dc9357SAndroid Build Coastguard Worker   if (processedSize)
2246*f6dc9357SAndroid Build Coastguard Worker     *processedSize = size;
2247*f6dc9357SAndroid Build Coastguard Worker   return res;
2248*f6dc9357SAndroid Build Coastguard Worker   // COM_TRY_END
2249*f6dc9357SAndroid Build Coastguard Worker   }
2250*f6dc9357SAndroid Build Coastguard Worker   catch(...)
2251*f6dc9357SAndroid Build Coastguard Worker   {
2252*f6dc9357SAndroid Build Coastguard Worker     _errorMode = true;
2253*f6dc9357SAndroid Build Coastguard Worker     return E_OUTOFMEMORY;
2254*f6dc9357SAndroid Build Coastguard Worker   }
2255*f6dc9357SAndroid Build Coastguard Worker }
2256*f6dc9357SAndroid Build Coastguard Worker 
2257*f6dc9357SAndroid Build Coastguard Worker 
2258*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CInStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition))
2259*f6dc9357SAndroid Build Coastguard Worker {
2260*f6dc9357SAndroid Build Coastguard Worker   switch (seekOrigin)
2261*f6dc9357SAndroid Build Coastguard Worker   {
2262*f6dc9357SAndroid Build Coastguard Worker     case STREAM_SEEK_SET: break;
2263*f6dc9357SAndroid Build Coastguard Worker     case STREAM_SEEK_CUR: offset += _virtPos; break;
2264*f6dc9357SAndroid Build Coastguard Worker     case STREAM_SEEK_END: offset += Size; break;
2265*f6dc9357SAndroid Build Coastguard Worker     default: return STG_E_INVALIDFUNCTION;
2266*f6dc9357SAndroid Build Coastguard Worker   }
2267*f6dc9357SAndroid Build Coastguard Worker   if (offset < 0)
2268*f6dc9357SAndroid Build Coastguard Worker     return HRESULT_WIN32_ERROR_NEGATIVE_SEEK;
2269*f6dc9357SAndroid Build Coastguard Worker   _virtPos = (UInt64)offset;
2270*f6dc9357SAndroid Build Coastguard Worker   if (newPosition)
2271*f6dc9357SAndroid Build Coastguard Worker     *newPosition = (UInt64)offset;
2272*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
2273*f6dc9357SAndroid Build Coastguard Worker }
2274*f6dc9357SAndroid Build Coastguard Worker 
2275*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::GetStream(UInt32 index, ISequentialInStream **stream))
2276*f6dc9357SAndroid Build Coastguard Worker {
2277*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_BEGIN
2278*f6dc9357SAndroid Build Coastguard Worker 
2279*f6dc9357SAndroid Build Coastguard Worker #ifdef DMG_SHOW_RAW
2280*f6dc9357SAndroid Build Coastguard Worker   if (index >= _files.Size())
2281*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
2282*f6dc9357SAndroid Build Coastguard Worker #endif
2283*f6dc9357SAndroid Build Coastguard Worker 
2284*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr2<ISequentialInStream, CInStream> spec;
2285*f6dc9357SAndroid Build Coastguard Worker   spec.Create_if_Empty();
2286*f6dc9357SAndroid Build Coastguard Worker   spec->File = &_files[index];
2287*f6dc9357SAndroid Build Coastguard Worker   const CFile &file = *spec->File;
2288*f6dc9357SAndroid Build Coastguard Worker 
2289*f6dc9357SAndroid Build Coastguard Worker   if (!file.IsCorrect)
2290*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
2291*f6dc9357SAndroid Build Coastguard Worker 
2292*f6dc9357SAndroid Build Coastguard Worker   FOR_VECTOR (i, file.Blocks)
2293*f6dc9357SAndroid Build Coastguard Worker   {
2294*f6dc9357SAndroid Build Coastguard Worker     const CBlock &block = file.Blocks[i];
2295*f6dc9357SAndroid Build Coastguard Worker     if (!block.NeedAllocateBuffer())
2296*f6dc9357SAndroid Build Coastguard Worker       continue;
2297*f6dc9357SAndroid Build Coastguard Worker 
2298*f6dc9357SAndroid Build Coastguard Worker     switch (block.Type)
2299*f6dc9357SAndroid Build Coastguard Worker     {
2300*f6dc9357SAndroid Build Coastguard Worker #ifdef Z7_DMG_USE_CACHE_FOR_COPY_BLOCKS
2301*f6dc9357SAndroid Build Coastguard Worker       case METHOD_COPY:
2302*f6dc9357SAndroid Build Coastguard Worker         break;
2303*f6dc9357SAndroid Build Coastguard Worker #endif
2304*f6dc9357SAndroid Build Coastguard Worker       case METHOD_ADC:
2305*f6dc9357SAndroid Build Coastguard Worker       case METHOD_ZLIB:
2306*f6dc9357SAndroid Build Coastguard Worker       case METHOD_BZIP2:
2307*f6dc9357SAndroid Build Coastguard Worker       case METHOD_LZFSE:
2308*f6dc9357SAndroid Build Coastguard Worker       case METHOD_XZ:
2309*f6dc9357SAndroid Build Coastguard Worker       // case METHOD_END:
2310*f6dc9357SAndroid Build Coastguard Worker         if (file.GetUnpackSize_of_Block(i) > k_Chunk_Size_MAX)
2311*f6dc9357SAndroid Build Coastguard Worker           return S_FALSE;
2312*f6dc9357SAndroid Build Coastguard Worker         break;
2313*f6dc9357SAndroid Build Coastguard Worker       default:
2314*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
2315*f6dc9357SAndroid Build Coastguard Worker     }
2316*f6dc9357SAndroid Build Coastguard Worker   }
2317*f6dc9357SAndroid Build Coastguard Worker 
2318*f6dc9357SAndroid Build Coastguard Worker   spec->Stream = _inStream;
2319*f6dc9357SAndroid Build Coastguard Worker   spec->Size = spec->File->Size;
2320*f6dc9357SAndroid Build Coastguard Worker   // RINOK(
2321*f6dc9357SAndroid Build Coastguard Worker   spec->Init(_startPos + _dataForkPair.Offset);
2322*f6dc9357SAndroid Build Coastguard Worker   *stream = spec.Detach();
2323*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
2324*f6dc9357SAndroid Build Coastguard Worker 
2325*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_END
2326*f6dc9357SAndroid Build Coastguard Worker }
2327*f6dc9357SAndroid Build Coastguard Worker 
2328*f6dc9357SAndroid Build Coastguard Worker REGISTER_ARC_I(
2329*f6dc9357SAndroid Build Coastguard Worker   "Dmg", "dmg", NULL, 0xE4,
2330*f6dc9357SAndroid Build Coastguard Worker   k_Signature,
2331*f6dc9357SAndroid Build Coastguard Worker   0,
2332*f6dc9357SAndroid Build Coastguard Worker   NArcInfoFlags::kBackwardOpen |
2333*f6dc9357SAndroid Build Coastguard Worker   NArcInfoFlags::kUseGlobalOffset,
2334*f6dc9357SAndroid Build Coastguard Worker   NULL)
2335*f6dc9357SAndroid Build Coastguard Worker 
2336*f6dc9357SAndroid Build Coastguard Worker }}
2337