diff options
Diffstat (limited to '')
-rw-r--r-- | CPP/7zip/Archive/DmgHandler.cpp | 1841 |
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 | |||
36 | Byte *Base64ToBin(Byte *dest, const char *src); | 61 | Byte *Base64ToBin(Byte *dest, const char *src); |
37 | 62 | ||
38 | namespace NArchive { | 63 | namespace NArchive { |
39 | namespace NDmg { | 64 | namespace NDmg { |
40 | 65 | ||
66 | // allocation limits for compressed blocks for GetStream() interface: | ||
67 | static const unsigned k_NumChunks_MAX = 128; | ||
68 | static 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: | ||
71 | static const size_t k_Chunks_TotalSize_MAX = (size_t)1 << (sizeof(size_t) + 24); | ||
41 | 72 | ||
42 | static 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 | ||
76 | static const size_t k_XmlSize_MAX = | ||
77 | ((size_t)1 << (sizeof(size_t) / 4 + 30)) - 256; | ||
78 | |||
79 | static const UInt32 METHOD_ZERO_0 = 0; // sparse | ||
43 | static const UInt32 METHOD_COPY = 1; | 80 | static const UInt32 METHOD_COPY = 1; |
44 | static const UInt32 METHOD_ZERO_2 = 2; // without file CRC calculation | 81 | static const UInt32 METHOD_ZERO_2 = 2; // sparse : without file CRC calculation |
45 | static const UInt32 METHOD_ADC = 0x80000004; | 82 | static const UInt32 METHOD_ADC = 0x80000004; |
46 | static const UInt32 METHOD_ZLIB = 0x80000005; | 83 | static const UInt32 METHOD_ZLIB = 0x80000005; |
47 | static const UInt32 METHOD_BZIP2 = 0x80000006; | 84 | static const UInt32 METHOD_BZIP2 = 0x80000006; |
48 | static const UInt32 METHOD_LZFSE = 0x80000007; | 85 | static const UInt32 METHOD_LZFSE = 0x80000007; |
86 | static const UInt32 METHOD_XZ = 0x80000008; | ||
49 | static const UInt32 METHOD_COMMENT = 0x7FFFFFFE; // is used to comment "+beg" and "+end" in extra field. | 87 | static const UInt32 METHOD_COMMENT = 0x7FFFFFFE; // is used to comment "+beg" and "+end" in extra field. |
50 | static const UInt32 METHOD_END = 0xFFFFFFFF; | 88 | static 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 | ||
68 | static const UInt32 kCheckSumType_CRC = 2; | 128 | static const UInt32 kCheckSumType_CRC = 2; |
69 | 129 | static const unsigned kChecksumSize_Max = 0x80; | |
70 | static const size_t kChecksumSize_Max = 0x80; | ||
71 | 130 | ||
72 | struct CChecksum | 131 | struct 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 | ||
83 | void CChecksum::Parse(const Byte *p) | 147 | void 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 | |||
155 | void 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 | |||
170 | void 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 | |||
193 | void CChecksum::Print_with_Name(AString &s) const | ||
194 | { | ||
195 | if (NumBits == 0) | ||
196 | return; | ||
197 | PrintType(s); | ||
198 | s += ": "; | ||
199 | Print(s); | ||
200 | } | ||
201 | |||
202 | static 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 | |||
210 | void 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 | |||
90 | struct CFile | 219 | struct 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 | ||
267 | static 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 | |||
112 | struct CForkPair | 275 | struct 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 | ||
306 | void 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 | ||
135 | Z7_CLASS_IMP_CHandler_IInArchive_1( | 316 | Z7_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 | ||
160 | static const size_t kXmlSizeMax = 0xFFFF0000; // 4 GB - 64 KB; | ||
161 | 355 | ||
162 | struct CMethods | 356 | struct 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 | ||
171 | void CMethods::Update(const CFile &file) | 364 | void 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 | ||
178 | void CMethods::GetString(AString &res) const | 374 | void 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 | |||
219 | struct CAppleName | 404 | struct 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 | ||
245 | static const unsigned kNumAppleNames = Z7_ARRAY_SIZE(k_Names); | 438 | static const unsigned kNumAppleNames = Z7_ARRAY_SIZE(k_Names); |
246 | 439 | ||
440 | const char *Find_Apple_FS_Ext(const AString &name); | ||
441 | const 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 | |||
454 | bool Is_Apple_FS_Or_Unknown(const AString &name); | ||
455 | bool 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 | |||
247 | static const Byte kProps[] = | 472 | static 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 | ||
258 | IMP_IInArchive_Props | 490 | IMP_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 | |||
267 | Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) | 501 | Z7_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 | ||
359 | IMP_IInArchive_ArcProps | 639 | IMP_IInArchive_ArcProps |
360 | 640 | ||
641 | |||
642 | |||
643 | static const UInt64 kSectorNumber_LIMIT = (UInt64)1 << (63 - 9); | ||
644 | |||
361 | HRESULT CFile::Parse(const Byte *p, UInt32 size) | 645 | HRESULT 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 | ||
439 | static int FindKeyPair(const CXmlItem &item, const char *key, const char *nextTag) | 781 | |
782 | static 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 | ||
450 | static const AString *GetStringFromKeyPair(const CXmlItem &item, const char *key, const char *nextTag) | 797 | static 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 | ||
458 | static const unsigned HEADER_SIZE = 0x200; | ||
459 | |||
460 | static const Byte k_Signature[] = { 'k','o','l','y', 0, 0, 0, 4, 0, 0, 2, 0 }; | 805 | static const Byte k_Signature[] = { 'k','o','l','y', 0, 0, 0, 4, 0, 0, 2, 0 }; |
461 | 806 | ||
462 | static inline bool IsKoly(const Byte *p) | 807 | static 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 | |||
488 | bool CHandler::ParseBlob(const CByteBuffer &data) | 834 | bool 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 | ||
553 | HRESULT CHandler::Open2(IInStream *stream) | 914 | |
915 | |||
916 | HRESULT 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 | |||
935 | Z7_COM7F_IMF(CHandler::Open(IInStream *stream, | 1415 | Z7_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 | ||
950 | Z7_COM7F_IMF(CHandler::Close()) | 1427 | Z7_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 | ||
964 | Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems)) | 1444 | Z7_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 | ||
1106 | Z7_CLASS_IMP_NOQIB_1( | 1623 | class 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 | ||
1136 | public: | 1642 | public: |
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 | ||
1142 | HRESULT CAdcDecoder::CodeReal(ISequentialInStream *inStream, | 1650 | |
1143 | ISequentialOutStream *outStream, const UInt64 *inSize, const UInt64 *outSize, | 1651 | HRESULT 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 | ||
1220 | Z7_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 | ||
1744 | struct 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 | 1756 | HRESULT 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 | ||
1236 | Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, | 1793 | Z7_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 | |||
1462 | struct CChunk | 1988 | struct 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 | ||
1470 | Z7_CLASS_IMP_COM_1( | 2008 | Z7_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 | ||
1500 | public: | 2019 | public: |
1501 | CMyComPtr<IInStream> Stream; | 2020 | CMyComPtr<IInStream> Stream; |
1502 | UInt64 Size; | ||
1503 | const CFile *File; | 2021 | const CFile *File; |
2022 | UInt64 Size; | ||
2023 | private: | ||
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; | ||
2030 | public: | ||
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 | ||
2052 | CInStream::~CInStream() | ||
2053 | { | ||
2054 | unsigned i = _chunks.Size(); | ||
2055 | while (i) | ||
2056 | _chunks[--i].Free(); | ||
2057 | } | ||
2058 | |||
1525 | static unsigned FindBlock(const CRecordVector<CBlock> &blocks, UInt64 pos) | 2059 | static 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 | ||
1540 | Z7_COM7F_IMF(CInStream::Read(void *data, UInt32 size, UInt32 *processedSize)) | 2074 | Z7_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 | ||
1704 | Z7_COM7F_IMF(CInStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)) | 2258 | Z7_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 |