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