1 | /* 7zIn.c -- 7z Input functions |
2 | 2010-10-29 : Igor Pavlov : Public domain */ |
3 | |
4 | #include <string.h> |
5 | |
6 | #include "7z.h" |
7 | #include "7zCrc.h" |
8 | #include "CpuArch.h" |
9 | |
10 | Byte k7zSignature[k7zSignatureSize] = {'7', 'z', 0xBC, 0xAF, 0x27, 0x1C}; |
11 | |
12 | #define RINOM(x) { if ((x) == 0) return SZ_ERROR_MEM; } |
13 | |
14 | #define NUM_FOLDER_CODERS_MAX 32 |
15 | #define NUM_CODER_STREAMS_MAX 32 |
16 | |
17 | void SzCoderInfo_Init(CSzCoderInfo *p) |
18 | { |
19 | Buf_Init(&p->Props); |
20 | } |
21 | |
22 | void SzCoderInfo_Free(CSzCoderInfo *p, ISzAlloc *alloc) |
23 | { |
24 | Buf_Free(&p->Props, alloc); |
25 | SzCoderInfo_Init(p); |
26 | } |
27 | |
28 | void SzFolder_Init(CSzFolder *p) |
29 | { |
30 | p->Coders = 0; |
31 | p->BindPairs = 0; |
32 | p->PackStreams = 0; |
33 | p->UnpackSizes = 0; |
34 | p->NumCoders = 0; |
35 | p->NumBindPairs = 0; |
36 | p->NumPackStreams = 0; |
37 | p->UnpackCRCDefined = 0; |
38 | p->UnpackCRC = 0; |
39 | p->NumUnpackStreams = 0; |
40 | } |
41 | |
42 | void SzFolder_Free(CSzFolder *p, ISzAlloc *alloc) |
43 | { |
44 | UInt32 i; |
45 | if (p->Coders) |
46 | for (i = 0; i < p->NumCoders; i++) |
47 | SzCoderInfo_Free(&p->Coders[i], alloc); |
48 | IAlloc_Free(alloc, p->Coders); |
49 | IAlloc_Free(alloc, p->BindPairs); |
50 | IAlloc_Free(alloc, p->PackStreams); |
51 | IAlloc_Free(alloc, p->UnpackSizes); |
52 | SzFolder_Init(p); |
53 | } |
54 | |
55 | UInt32 SzFolder_GetNumOutStreams(CSzFolder *p) |
56 | { |
57 | UInt32 result = 0; |
58 | UInt32 i; |
59 | for (i = 0; i < p->NumCoders; i++) |
60 | result += p->Coders[i].NumOutStreams; |
61 | return result; |
62 | } |
63 | |
64 | int SzFolder_FindBindPairForInStream(CSzFolder *p, UInt32 inStreamIndex) |
65 | { |
66 | UInt32 i; |
67 | for (i = 0; i < p->NumBindPairs; i++) |
68 | if (p->BindPairs[i].InIndex == inStreamIndex) |
69 | return i; |
70 | return -1; |
71 | } |
72 | |
73 | |
74 | int SzFolder_FindBindPairForOutStream(CSzFolder *p, UInt32 outStreamIndex) |
75 | { |
76 | UInt32 i; |
77 | for (i = 0; i < p->NumBindPairs; i++) |
78 | if (p->BindPairs[i].OutIndex == outStreamIndex) |
79 | return i; |
80 | return -1; |
81 | } |
82 | |
83 | UInt64 SzFolder_GetUnpackSize(CSzFolder *p) |
84 | { |
85 | int i = (int)SzFolder_GetNumOutStreams(p); |
86 | if (i == 0) |
87 | return 0; |
88 | for (i--; i >= 0; i--) |
89 | if (SzFolder_FindBindPairForOutStream(p, i) < 0) |
90 | return p->UnpackSizes[i]; |
91 | /* throw 1; */ |
92 | return 0; |
93 | } |
94 | |
95 | void SzFile_Init(CSzFileItem *p) |
96 | { |
97 | p->HasStream = 1; |
98 | p->IsDir = 0; |
99 | p->IsAnti = 0; |
100 | p->CrcDefined = 0; |
101 | p->MTimeDefined = 0; |
102 | } |
103 | |
104 | void SzAr_Init(CSzAr *p) |
105 | { |
106 | p->PackSizes = 0; |
107 | p->PackCRCsDefined = 0; |
108 | p->PackCRCs = 0; |
109 | p->Folders = 0; |
110 | p->Files = 0; |
111 | p->NumPackStreams = 0; |
112 | p->NumFolders = 0; |
113 | p->NumFiles = 0; |
114 | } |
115 | |
116 | void SzAr_Free(CSzAr *p, ISzAlloc *alloc) |
117 | { |
118 | UInt32 i; |
119 | if (p->Folders) |
120 | for (i = 0; i < p->NumFolders; i++) |
121 | SzFolder_Free(&p->Folders[i], alloc); |
122 | |
123 | IAlloc_Free(alloc, p->PackSizes); |
124 | IAlloc_Free(alloc, p->PackCRCsDefined); |
125 | IAlloc_Free(alloc, p->PackCRCs); |
126 | IAlloc_Free(alloc, p->Folders); |
127 | IAlloc_Free(alloc, p->Files); |
128 | SzAr_Init(p); |
129 | } |
130 | |
131 | |
132 | void SzArEx_Init(CSzArEx *p) |
133 | { |
134 | SzAr_Init(&p->db); |
135 | p->FolderStartPackStreamIndex = 0; |
136 | p->PackStreamStartPositions = 0; |
137 | p->FolderStartFileIndex = 0; |
138 | p->FileIndexToFolderIndexMap = 0; |
139 | p->FileNameOffsets = 0; |
140 | Buf_Init(&p->FileNames); |
141 | } |
142 | |
143 | void SzArEx_Free(CSzArEx *p, ISzAlloc *alloc) |
144 | { |
145 | IAlloc_Free(alloc, p->FolderStartPackStreamIndex); |
146 | IAlloc_Free(alloc, p->PackStreamStartPositions); |
147 | IAlloc_Free(alloc, p->FolderStartFileIndex); |
148 | IAlloc_Free(alloc, p->FileIndexToFolderIndexMap); |
149 | |
150 | IAlloc_Free(alloc, p->FileNameOffsets); |
151 | Buf_Free(&p->FileNames, alloc); |
152 | |
153 | SzAr_Free(&p->db, alloc); |
154 | SzArEx_Init(p); |
155 | } |
156 | |
157 | /* |
158 | UInt64 GetFolderPackStreamSize(int folderIndex, int streamIndex) const |
159 | { |
160 | return PackSizes[FolderStartPackStreamIndex[folderIndex] + streamIndex]; |
161 | } |
162 | |
163 | UInt64 GetFilePackSize(int fileIndex) const |
164 | { |
165 | int folderIndex = FileIndexToFolderIndexMap[fileIndex]; |
166 | if (folderIndex >= 0) |
167 | { |
168 | const CSzFolder &folderInfo = Folders[folderIndex]; |
169 | if (FolderStartFileIndex[folderIndex] == fileIndex) |
170 | return GetFolderFullPackSize(folderIndex); |
171 | } |
172 | return 0; |
173 | } |
174 | */ |
175 | |
176 | #define MY_ALLOC(T, p, size, alloc) { if ((size) == 0) p = 0; else \ |
177 | if ((p = (T *)IAlloc_Alloc(alloc, (size) * sizeof(T))) == 0) return SZ_ERROR_MEM; } |
178 | |
179 | static SRes SzArEx_Fill(CSzArEx *p, ISzAlloc *alloc) |
180 | { |
181 | UInt32 startPos = 0; |
182 | UInt64 startPosSize = 0; |
183 | UInt32 i; |
184 | UInt32 folderIndex = 0; |
185 | UInt32 indexInFolder = 0; |
186 | MY_ALLOC(UInt32, p->FolderStartPackStreamIndex, p->db.NumFolders, alloc); |
187 | for (i = 0; i < p->db.NumFolders; i++) |
188 | { |
189 | p->FolderStartPackStreamIndex[i] = startPos; |
190 | startPos += p->db.Folders[i].NumPackStreams; |
191 | } |
192 | |
193 | MY_ALLOC(UInt64, p->PackStreamStartPositions, p->db.NumPackStreams, alloc); |
194 | |
195 | for (i = 0; i < p->db.NumPackStreams; i++) |
196 | { |
197 | p->PackStreamStartPositions[i] = startPosSize; |
198 | startPosSize += p->db.PackSizes[i]; |
199 | } |
200 | |
201 | MY_ALLOC(UInt32, p->FolderStartFileIndex, p->db.NumFolders, alloc); |
202 | MY_ALLOC(UInt32, p->FileIndexToFolderIndexMap, p->db.NumFiles, alloc); |
203 | |
204 | for (i = 0; i < p->db.NumFiles; i++) |
205 | { |
206 | CSzFileItem *file = p->db.Files + i; |
207 | int emptyStream = !file->HasStream; |
208 | if (emptyStream && indexInFolder == 0) |
209 | { |
210 | p->FileIndexToFolderIndexMap[i] = (UInt32)-1; |
211 | continue; |
212 | } |
213 | if (indexInFolder == 0) |
214 | { |
215 | /* |
216 | v3.13 incorrectly worked with empty folders |
217 | v4.07: Loop for skipping empty folders |
218 | */ |
219 | for (;;) |
220 | { |
221 | if (folderIndex >= p->db.NumFolders) |
222 | return SZ_ERROR_ARCHIVE; |
223 | p->FolderStartFileIndex[folderIndex] = i; |
224 | if (p->db.Folders[folderIndex].NumUnpackStreams != 0) |
225 | break; |
226 | folderIndex++; |
227 | } |
228 | } |
229 | p->FileIndexToFolderIndexMap[i] = folderIndex; |
230 | if (emptyStream) |
231 | continue; |
232 | indexInFolder++; |
233 | if (indexInFolder >= p->db.Folders[folderIndex].NumUnpackStreams) |
234 | { |
235 | folderIndex++; |
236 | indexInFolder = 0; |
237 | } |
238 | } |
239 | return SZ_OK; |
240 | } |
241 | |
242 | |
243 | UInt64 SzArEx_GetFolderStreamPos(const CSzArEx *p, UInt32 folderIndex, UInt32 indexInFolder) |
244 | { |
245 | return p->dataPos + |
246 | p->PackStreamStartPositions[p->FolderStartPackStreamIndex[folderIndex] + indexInFolder]; |
247 | } |
248 | |
249 | int SzArEx_GetFolderFullPackSize(const CSzArEx *p, UInt32 folderIndex, UInt64 *resSize) |
250 | { |
251 | UInt32 packStreamIndex = p->FolderStartPackStreamIndex[folderIndex]; |
252 | CSzFolder *folder = p->db.Folders + folderIndex; |
253 | UInt64 size = 0; |
254 | UInt32 i; |
255 | for (i = 0; i < folder->NumPackStreams; i++) |
256 | { |
257 | UInt64 t = size + p->db.PackSizes[packStreamIndex + i]; |
258 | if (t < size) /* check it */ |
259 | return SZ_ERROR_FAIL; |
260 | size = t; |
261 | } |
262 | *resSize = size; |
263 | return SZ_OK; |
264 | } |
265 | |
266 | |
267 | /* |
268 | SRes SzReadTime(const CObjectVector<CBuf> &dataVector, |
269 | CObjectVector<CSzFileItem> &files, UInt64 type) |
270 | { |
271 | CBoolVector boolVector; |
272 | RINOK(ReadBoolVector2(files.Size(), boolVector)) |
273 | |
274 | CStreamSwitch streamSwitch; |
275 | RINOK(streamSwitch.Set(this, &dataVector)); |
276 | |
277 | for (int i = 0; i < files.Size(); i++) |
278 | { |
279 | CSzFileItem &file = files[i]; |
280 | CArchiveFileTime fileTime; |
281 | bool defined = boolVector[i]; |
282 | if (defined) |
283 | { |
284 | UInt32 low, high; |
285 | RINOK(SzReadUInt32(low)); |
286 | RINOK(SzReadUInt32(high)); |
287 | fileTime.dwLowDateTime = low; |
288 | fileTime.dwHighDateTime = high; |
289 | } |
290 | switch(type) |
291 | { |
292 | case k7zIdCTime: file.IsCTimeDefined = defined; if (defined) file.CTime = fileTime; break; |
293 | case k7zIdATime: file.IsATimeDefined = defined; if (defined) file.ATime = fileTime; break; |
294 | case k7zIdMTime: file.IsMTimeDefined = defined; if (defined) file.MTime = fileTime; break; |
295 | } |
296 | } |
297 | return SZ_OK; |
298 | } |
299 | */ |
300 | |
301 | static int TestSignatureCandidate(Byte *testBytes) |
302 | { |
303 | size_t i; |
304 | for (i = 0; i < k7zSignatureSize; i++) |
305 | if (testBytes[i] != k7zSignature[i]) |
306 | return 0; |
307 | return 1; |
308 | } |
309 | |
310 | typedef struct _CSzState |
311 | { |
312 | Byte *Data; |
313 | size_t Size; |
314 | }CSzData; |
315 | |
316 | static SRes SzReadByte(CSzData *sd, Byte *b) |
317 | { |
318 | if (sd->Size == 0) |
319 | return SZ_ERROR_ARCHIVE; |
320 | sd->Size--; |
321 | *b = *sd->Data++; |
322 | return SZ_OK; |
323 | } |
324 | |
325 | static SRes SzReadBytes(CSzData *sd, Byte *data, size_t size) |
326 | { |
327 | size_t i; |
328 | for (i = 0; i < size; i++) |
329 | { |
330 | RINOK(SzReadByte(sd, data + i)); |
331 | } |
332 | return SZ_OK; |
333 | } |
334 | |
335 | static SRes SzReadUInt32(CSzData *sd, UInt32 *value) |
336 | { |
337 | int i; |
338 | *value = 0; |
339 | for (i = 0; i < 4; i++) |
340 | { |
341 | Byte b; |
342 | RINOK(SzReadByte(sd, &b)); |
343 | *value |= ((UInt32)(b) << (8 * i)); |
344 | } |
345 | return SZ_OK; |
346 | } |
347 | |
348 | static SRes SzReadNumber(CSzData *sd, UInt64 *value) |
349 | { |
350 | Byte firstByte; |
351 | Byte mask = 0x80; |
352 | int i; |
353 | RINOK(SzReadByte(sd, &firstByte)); |
354 | *value = 0; |
355 | for (i = 0; i < 8; i++) |
356 | { |
357 | Byte b; |
358 | if ((firstByte & mask) == 0) |
359 | { |
360 | UInt64 highPart = firstByte & (mask - 1); |
361 | *value += (highPart << (8 * i)); |
362 | return SZ_OK; |
363 | } |
364 | RINOK(SzReadByte(sd, &b)); |
365 | *value |= ((UInt64)b << (8 * i)); |
366 | mask >>= 1; |
367 | } |
368 | return SZ_OK; |
369 | } |
370 | |
371 | static SRes SzReadNumber32(CSzData *sd, UInt32 *value) |
372 | { |
373 | UInt64 value64; |
374 | RINOK(SzReadNumber(sd, &value64)); |
375 | if (value64 >= 0x80000000) |
376 | return SZ_ERROR_UNSUPPORTED; |
377 | if (value64 >= ((UInt64)(1) << ((sizeof(size_t) - 1) * 8 + 2))) |
378 | return SZ_ERROR_UNSUPPORTED; |
379 | *value = (UInt32)value64; |
380 | return SZ_OK; |
381 | } |
382 | |
383 | static SRes SzReadID(CSzData *sd, UInt64 *value) |
384 | { |
385 | return SzReadNumber(sd, value); |
386 | } |
387 | |
388 | static SRes SzSkeepDataSize(CSzData *sd, UInt64 size) |
389 | { |
390 | if (size > sd->Size) |
391 | return SZ_ERROR_ARCHIVE; |
392 | sd->Size -= (size_t)size; |
393 | sd->Data += (size_t)size; |
394 | return SZ_OK; |
395 | } |
396 | |
397 | static SRes SzSkeepData(CSzData *sd) |
398 | { |
399 | UInt64 size; |
400 | RINOK(SzReadNumber(sd, &size)); |
401 | return SzSkeepDataSize(sd, size); |
402 | } |
403 | |
404 | static SRes SzReadArchiveProperties(CSzData *sd) |
405 | { |
406 | for (;;) |
407 | { |
408 | UInt64 type; |
409 | RINOK(SzReadID(sd, &type)); |
410 | if (type == k7zIdEnd) |
411 | break; |
412 | SzSkeepData(sd); |
413 | } |
414 | return SZ_OK; |
415 | } |
416 | |
417 | static SRes SzWaitAttribute(CSzData *sd, UInt64 attribute) |
418 | { |
419 | for (;;) |
420 | { |
421 | UInt64 type; |
422 | RINOK(SzReadID(sd, &type)); |
423 | if (type == attribute) |
424 | return SZ_OK; |
425 | if (type == k7zIdEnd) |
426 | return SZ_ERROR_ARCHIVE; |
427 | RINOK(SzSkeepData(sd)); |
428 | } |
429 | } |
430 | |
431 | static SRes SzReadBoolVector(CSzData *sd, size_t numItems, Byte **v, ISzAlloc *alloc) |
432 | { |
433 | Byte b = 0; |
434 | Byte mask = 0; |
435 | size_t i; |
436 | MY_ALLOC(Byte, *v, numItems, alloc); |
437 | for (i = 0; i < numItems; i++) |
438 | { |
439 | if (mask == 0) |
440 | { |
441 | RINOK(SzReadByte(sd, &b)); |
442 | mask = 0x80; |
443 | } |
444 | (*v)[i] = (Byte)(((b & mask) != 0) ? 1 : 0); |
445 | mask >>= 1; |
446 | } |
447 | return SZ_OK; |
448 | } |
449 | |
450 | static SRes SzReadBoolVector2(CSzData *sd, size_t numItems, Byte **v, ISzAlloc *alloc) |
451 | { |
452 | Byte allAreDefined; |
453 | size_t i; |
454 | RINOK(SzReadByte(sd, &allAreDefined)); |
455 | if (allAreDefined == 0) |
456 | return SzReadBoolVector(sd, numItems, v, alloc); |
457 | MY_ALLOC(Byte, *v, numItems, alloc); |
458 | for (i = 0; i < numItems; i++) |
459 | (*v)[i] = 1; |
460 | return SZ_OK; |
461 | } |
462 | |
463 | static SRes SzReadHashDigests( |
464 | CSzData *sd, |
465 | size_t numItems, |
466 | Byte **digestsDefined, |
467 | UInt32 **digests, |
468 | ISzAlloc *alloc) |
469 | { |
470 | size_t i; |
471 | RINOK(SzReadBoolVector2(sd, numItems, digestsDefined, alloc)); |
472 | MY_ALLOC(UInt32, *digests, numItems, alloc); |
473 | for (i = 0; i < numItems; i++) |
474 | if ((*digestsDefined)[i]) |
475 | { |
476 | RINOK(SzReadUInt32(sd, (*digests) + i)); |
477 | } |
478 | return SZ_OK; |
479 | } |
480 | |
481 | static SRes SzReadPackInfo( |
482 | CSzData *sd, |
483 | UInt64 *dataOffset, |
484 | UInt32 *numPackStreams, |
485 | UInt64 **packSizes, |
486 | Byte **packCRCsDefined, |
487 | UInt32 **packCRCs, |
488 | ISzAlloc *alloc) |
489 | { |
490 | UInt32 i; |
491 | RINOK(SzReadNumber(sd, dataOffset)); |
492 | RINOK(SzReadNumber32(sd, numPackStreams)); |
493 | |
494 | RINOK(SzWaitAttribute(sd, k7zIdSize)); |
495 | |
496 | MY_ALLOC(UInt64, *packSizes, (size_t)*numPackStreams, alloc); |
497 | |
498 | for (i = 0; i < *numPackStreams; i++) |
499 | { |
500 | RINOK(SzReadNumber(sd, (*packSizes) + i)); |
501 | } |
502 | |
503 | for (;;) |
504 | { |
505 | UInt64 type; |
506 | RINOK(SzReadID(sd, &type)); |
507 | if (type == k7zIdEnd) |
508 | break; |
509 | if (type == k7zIdCRC) |
510 | { |
511 | RINOK(SzReadHashDigests(sd, (size_t)*numPackStreams, packCRCsDefined, packCRCs, alloc)); |
512 | continue; |
513 | } |
514 | RINOK(SzSkeepData(sd)); |
515 | } |
516 | if (*packCRCsDefined == 0) |
517 | { |
518 | MY_ALLOC(Byte, *packCRCsDefined, (size_t)*numPackStreams, alloc); |
519 | MY_ALLOC(UInt32, *packCRCs, (size_t)*numPackStreams, alloc); |
520 | for (i = 0; i < *numPackStreams; i++) |
521 | { |
522 | (*packCRCsDefined)[i] = 0; |
523 | (*packCRCs)[i] = 0; |
524 | } |
525 | } |
526 | return SZ_OK; |
527 | } |
528 | |
529 | static SRes SzReadSwitch(CSzData *sd) |
530 | { |
531 | Byte external; |
532 | RINOK(SzReadByte(sd, &external)); |
533 | return (external == 0) ? SZ_OK: SZ_ERROR_UNSUPPORTED; |
534 | } |
535 | |
536 | static SRes SzGetNextFolderItem(CSzData *sd, CSzFolder *folder, ISzAlloc *alloc) |
537 | { |
538 | UInt32 numCoders, numBindPairs, numPackStreams, i; |
539 | UInt32 numInStreams = 0, numOutStreams = 0; |
540 | |
541 | RINOK(SzReadNumber32(sd, &numCoders)); |
542 | if (numCoders > NUM_FOLDER_CODERS_MAX) |
543 | return SZ_ERROR_UNSUPPORTED; |
544 | folder->NumCoders = numCoders; |
545 | |
546 | MY_ALLOC(CSzCoderInfo, folder->Coders, (size_t)numCoders, alloc); |
547 | |
548 | for (i = 0; i < numCoders; i++) |
549 | SzCoderInfo_Init(folder->Coders + i); |
550 | |
551 | for (i = 0; i < numCoders; i++) |
552 | { |
553 | Byte mainByte; |
554 | CSzCoderInfo *coder = folder->Coders + i; |
555 | { |
556 | unsigned idSize, j; |
557 | Byte longID[15]; |
558 | RINOK(SzReadByte(sd, &mainByte)); |
559 | idSize = (unsigned)(mainByte & 0xF); |
560 | RINOK(SzReadBytes(sd, longID, idSize)); |
561 | if (idSize > sizeof(coder->MethodID)) |
562 | return SZ_ERROR_UNSUPPORTED; |
563 | coder->MethodID = 0; |
564 | for (j = 0; j < idSize; j++) |
565 | coder->MethodID |= (UInt64)longID[idSize - 1 - j] << (8 * j); |
566 | |
567 | if ((mainByte & 0x10) != 0) |
568 | { |
569 | RINOK(SzReadNumber32(sd, &coder->NumInStreams)); |
570 | RINOK(SzReadNumber32(sd, &coder->NumOutStreams)); |
571 | if (coder->NumInStreams > NUM_CODER_STREAMS_MAX || |
572 | coder->NumOutStreams > NUM_CODER_STREAMS_MAX) |
573 | return SZ_ERROR_UNSUPPORTED; |
574 | } |
575 | else |
576 | { |
577 | coder->NumInStreams = 1; |
578 | coder->NumOutStreams = 1; |
579 | } |
580 | if ((mainByte & 0x20) != 0) |
581 | { |
582 | UInt64 propertiesSize = 0; |
583 | RINOK(SzReadNumber(sd, &propertiesSize)); |
584 | if (!Buf_Create(&coder->Props, (size_t)propertiesSize, alloc)) |
585 | return SZ_ERROR_MEM; |
586 | RINOK(SzReadBytes(sd, coder->Props.data, (size_t)propertiesSize)); |
587 | } |
588 | } |
589 | while ((mainByte & 0x80) != 0) |
590 | { |
591 | RINOK(SzReadByte(sd, &mainByte)); |
592 | RINOK(SzSkeepDataSize(sd, (mainByte & 0xF))); |
593 | if ((mainByte & 0x10) != 0) |
594 | { |
595 | UInt32 n; |
596 | RINOK(SzReadNumber32(sd, &n)); |
597 | RINOK(SzReadNumber32(sd, &n)); |
598 | } |
599 | if ((mainByte & 0x20) != 0) |
600 | { |
601 | UInt64 propertiesSize = 0; |
602 | RINOK(SzReadNumber(sd, &propertiesSize)); |
603 | RINOK(SzSkeepDataSize(sd, propertiesSize)); |
604 | } |
605 | } |
606 | numInStreams += coder->NumInStreams; |
607 | numOutStreams += coder->NumOutStreams; |
608 | } |
609 | |
610 | if (numOutStreams == 0) |
611 | return SZ_ERROR_UNSUPPORTED; |
612 | |
613 | folder->NumBindPairs = numBindPairs = numOutStreams - 1; |
614 | MY_ALLOC(CSzBindPair, folder->BindPairs, (size_t)numBindPairs, alloc); |
615 | |
616 | for (i = 0; i < numBindPairs; i++) |
617 | { |
618 | CSzBindPair *bp = folder->BindPairs + i; |
619 | RINOK(SzReadNumber32(sd, &bp->InIndex)); |
620 | RINOK(SzReadNumber32(sd, &bp->OutIndex)); |
621 | } |
622 | |
623 | if (numInStreams < numBindPairs) |
624 | return SZ_ERROR_UNSUPPORTED; |
625 | |
626 | folder->NumPackStreams = numPackStreams = numInStreams - numBindPairs; |
627 | MY_ALLOC(UInt32, folder->PackStreams, (size_t)numPackStreams, alloc); |
628 | |
629 | if (numPackStreams == 1) |
630 | { |
631 | for (i = 0; i < numInStreams ; i++) |
632 | if (SzFolder_FindBindPairForInStream(folder, i) < 0) |
633 | break; |
634 | if (i == numInStreams) |
635 | return SZ_ERROR_UNSUPPORTED; |
636 | folder->PackStreams[0] = i; |
637 | } |
638 | else |
639 | for (i = 0; i < numPackStreams; i++) |
640 | { |
641 | RINOK(SzReadNumber32(sd, folder->PackStreams + i)); |
642 | } |
643 | return SZ_OK; |
644 | } |
645 | |
646 | static SRes SzReadUnpackInfo( |
647 | CSzData *sd, |
648 | UInt32 *numFolders, |
649 | CSzFolder **folders, /* for alloc */ |
650 | ISzAlloc *alloc, |
651 | ISzAlloc *allocTemp) |
652 | { |
653 | UInt32 i; |
654 | RINOK(SzWaitAttribute(sd, k7zIdFolder)); |
655 | RINOK(SzReadNumber32(sd, numFolders)); |
656 | { |
657 | RINOK(SzReadSwitch(sd)); |
658 | |
659 | MY_ALLOC(CSzFolder, *folders, (size_t)*numFolders, alloc); |
660 | |
661 | for (i = 0; i < *numFolders; i++) |
662 | SzFolder_Init((*folders) + i); |
663 | |
664 | for (i = 0; i < *numFolders; i++) |
665 | { |
666 | RINOK(SzGetNextFolderItem(sd, (*folders) + i, alloc)); |
667 | } |
668 | } |
669 | |
670 | RINOK(SzWaitAttribute(sd, k7zIdCodersUnpackSize)); |
671 | |
672 | for (i = 0; i < *numFolders; i++) |
673 | { |
674 | UInt32 j; |
675 | CSzFolder *folder = (*folders) + i; |
676 | UInt32 numOutStreams = SzFolder_GetNumOutStreams(folder); |
677 | |
678 | MY_ALLOC(UInt64, folder->UnpackSizes, (size_t)numOutStreams, alloc); |
679 | |
680 | for (j = 0; j < numOutStreams; j++) |
681 | { |
682 | RINOK(SzReadNumber(sd, folder->UnpackSizes + j)); |
683 | } |
684 | } |
685 | |
686 | for (;;) |
687 | { |
688 | UInt64 type; |
689 | RINOK(SzReadID(sd, &type)); |
690 | if (type == k7zIdEnd) |
691 | return SZ_OK; |
692 | if (type == k7zIdCRC) |
693 | { |
694 | SRes res; |
695 | Byte *crcsDefined = 0; |
696 | UInt32 *crcs = 0; |
697 | res = SzReadHashDigests(sd, *numFolders, &crcsDefined, &crcs, allocTemp); |
698 | if (res == SZ_OK) |
699 | { |
700 | for (i = 0; i < *numFolders; i++) |
701 | { |
702 | CSzFolder *folder = (*folders) + i; |
703 | folder->UnpackCRCDefined = crcsDefined[i]; |
704 | folder->UnpackCRC = crcs[i]; |
705 | } |
706 | } |
707 | IAlloc_Free(allocTemp, crcs); |
708 | IAlloc_Free(allocTemp, crcsDefined); |
709 | RINOK(res); |
710 | continue; |
711 | } |
712 | RINOK(SzSkeepData(sd)); |
713 | } |
714 | } |
715 | |
716 | static SRes SzReadSubStreamsInfo( |
717 | CSzData *sd, |
718 | UInt32 numFolders, |
719 | CSzFolder *folders, |
720 | UInt32 *numUnpackStreams, |
721 | UInt64 **unpackSizes, |
722 | Byte **digestsDefined, |
723 | UInt32 **digests, |
724 | ISzAlloc *allocTemp) |
725 | { |
726 | UInt64 type = 0; |
727 | UInt32 i; |
728 | UInt32 si = 0; |
729 | UInt32 numDigests = 0; |
730 | |
731 | for (i = 0; i < numFolders; i++) |
732 | folders[i].NumUnpackStreams = 1; |
733 | *numUnpackStreams = numFolders; |
734 | |
735 | for (;;) |
736 | { |
737 | RINOK(SzReadID(sd, &type)); |
738 | if (type == k7zIdNumUnpackStream) |
739 | { |
740 | *numUnpackStreams = 0; |
741 | for (i = 0; i < numFolders; i++) |
742 | { |
743 | UInt32 numStreams; |
744 | RINOK(SzReadNumber32(sd, &numStreams)); |
745 | folders[i].NumUnpackStreams = numStreams; |
746 | *numUnpackStreams += numStreams; |
747 | } |
748 | continue; |
749 | } |
750 | if (type == k7zIdCRC || type == k7zIdSize) |
751 | break; |
752 | if (type == k7zIdEnd) |
753 | break; |
754 | RINOK(SzSkeepData(sd)); |
755 | } |
756 | |
757 | if (*numUnpackStreams == 0) |
758 | { |
759 | *unpackSizes = 0; |
760 | *digestsDefined = 0; |
761 | *digests = 0; |
762 | } |
763 | else |
764 | { |
765 | *unpackSizes = (UInt64 *)IAlloc_Alloc(allocTemp, (size_t)*numUnpackStreams * sizeof(UInt64)); |
766 | RINOM(*unpackSizes); |
767 | *digestsDefined = (Byte *)IAlloc_Alloc(allocTemp, (size_t)*numUnpackStreams * sizeof(Byte)); |
768 | RINOM(*digestsDefined); |
769 | *digests = (UInt32 *)IAlloc_Alloc(allocTemp, (size_t)*numUnpackStreams * sizeof(UInt32)); |
770 | RINOM(*digests); |
771 | } |
772 | |
773 | for (i = 0; i < numFolders; i++) |
774 | { |
775 | /* |
776 | v3.13 incorrectly worked with empty folders |
777 | v4.07: we check that folder is empty |
778 | */ |
779 | UInt64 sum = 0; |
780 | UInt32 j; |
781 | UInt32 numSubstreams = folders[i].NumUnpackStreams; |
782 | if (numSubstreams == 0) |
783 | continue; |
784 | if (type == k7zIdSize) |
785 | for (j = 1; j < numSubstreams; j++) |
786 | { |
787 | UInt64 size; |
788 | RINOK(SzReadNumber(sd, &size)); |
789 | (*unpackSizes)[si++] = size; |
790 | sum += size; |
791 | } |
792 | (*unpackSizes)[si++] = SzFolder_GetUnpackSize(folders + i) - sum; |
793 | } |
794 | if (type == k7zIdSize) |
795 | { |
796 | RINOK(SzReadID(sd, &type)); |
797 | } |
798 | |
799 | for (i = 0; i < *numUnpackStreams; i++) |
800 | { |
801 | (*digestsDefined)[i] = 0; |
802 | (*digests)[i] = 0; |
803 | } |
804 | |
805 | |
806 | for (i = 0; i < numFolders; i++) |
807 | { |
808 | UInt32 numSubstreams = folders[i].NumUnpackStreams; |
809 | if (numSubstreams != 1 || !folders[i].UnpackCRCDefined) |
810 | numDigests += numSubstreams; |
811 | } |
812 | |
813 | |
814 | si = 0; |
815 | for (;;) |
816 | { |
817 | if (type == k7zIdCRC) |
818 | { |
819 | int digestIndex = 0; |
820 | Byte *digestsDefined2 = 0; |
821 | UInt32 *digests2 = 0; |
822 | SRes res = SzReadHashDigests(sd, numDigests, &digestsDefined2, &digests2, allocTemp); |
823 | if (res == SZ_OK) |
824 | { |
825 | for (i = 0; i < numFolders; i++) |
826 | { |
827 | CSzFolder *folder = folders + i; |
828 | UInt32 numSubstreams = folder->NumUnpackStreams; |
829 | if (numSubstreams == 1 && folder->UnpackCRCDefined) |
830 | { |
831 | (*digestsDefined)[si] = 1; |
832 | (*digests)[si] = folder->UnpackCRC; |
833 | si++; |
834 | } |
835 | else |
836 | { |
837 | UInt32 j; |
838 | for (j = 0; j < numSubstreams; j++, digestIndex++) |
839 | { |
840 | (*digestsDefined)[si] = digestsDefined2[digestIndex]; |
841 | (*digests)[si] = digests2[digestIndex]; |
842 | si++; |
843 | } |
844 | } |
845 | } |
846 | } |
847 | IAlloc_Free(allocTemp, digestsDefined2); |
848 | IAlloc_Free(allocTemp, digests2); |
849 | RINOK(res); |
850 | } |
851 | else if (type == k7zIdEnd) |
852 | return SZ_OK; |
853 | else |
854 | { |
855 | RINOK(SzSkeepData(sd)); |
856 | } |
857 | RINOK(SzReadID(sd, &type)); |
858 | } |
859 | } |
860 | |
861 | |
862 | static SRes SzReadStreamsInfo( |
863 | CSzData *sd, |
864 | UInt64 *dataOffset, |
865 | CSzAr *p, |
866 | UInt32 *numUnpackStreams, |
867 | UInt64 **unpackSizes, /* allocTemp */ |
868 | Byte **digestsDefined, /* allocTemp */ |
869 | UInt32 **digests, /* allocTemp */ |
870 | ISzAlloc *alloc, |
871 | ISzAlloc *allocTemp) |
872 | { |
873 | for (;;) |
874 | { |
875 | UInt64 type; |
876 | RINOK(SzReadID(sd, &type)); |
877 | if ((UInt64)(int)type != type) |
878 | return SZ_ERROR_UNSUPPORTED; |
879 | switch((int)type) |
880 | { |
881 | case k7zIdEnd: |
882 | return SZ_OK; |
883 | case k7zIdPackInfo: |
884 | { |
885 | RINOK(SzReadPackInfo(sd, dataOffset, &p->NumPackStreams, |
886 | &p->PackSizes, &p->PackCRCsDefined, &p->PackCRCs, alloc)); |
887 | break; |
888 | } |
889 | case k7zIdUnpackInfo: |
890 | { |
891 | RINOK(SzReadUnpackInfo(sd, &p->NumFolders, &p->Folders, alloc, allocTemp)); |
892 | break; |
893 | } |
894 | case k7zIdSubStreamsInfo: |
895 | { |
896 | RINOK(SzReadSubStreamsInfo(sd, p->NumFolders, p->Folders, |
897 | numUnpackStreams, unpackSizes, digestsDefined, digests, allocTemp)); |
898 | break; |
899 | } |
900 | default: |
901 | return SZ_ERROR_UNSUPPORTED; |
902 | } |
903 | } |
904 | } |
905 | |
906 | size_t SzArEx_GetFileNameUtf16(const CSzArEx *p, size_t fileIndex, UInt16 *dest) |
907 | { |
908 | size_t len = p->FileNameOffsets[fileIndex + 1] - p->FileNameOffsets[fileIndex]; |
909 | if (dest != 0) |
910 | { |
911 | size_t i; |
912 | const Byte *src = p->FileNames.data + (p->FileNameOffsets[fileIndex] * 2); |
913 | for (i = 0; i < len; i++) |
914 | dest[i] = GetUi16(src + i * 2); |
915 | } |
916 | return len; |
917 | } |
918 | |
919 | static SRes SzReadFileNames(const Byte *p, size_t size, UInt32 numFiles, size_t *sizes) |
920 | { |
921 | UInt32 i; |
922 | size_t pos = 0; |
923 | for (i = 0; i < numFiles; i++) |
924 | { |
925 | sizes[i] = pos; |
926 | for (;;) |
927 | { |
928 | if (pos >= size) |
929 | return SZ_ERROR_ARCHIVE; |
930 | if (p[pos * 2] == 0 && p[pos * 2 + 1] == 0) |
931 | break; |
932 | pos++; |
933 | } |
934 | pos++; |
935 | } |
936 | sizes[i] = pos; |
937 | return (pos == size) ? SZ_OK : SZ_ERROR_ARCHIVE; |
938 | } |
939 | |
940 | static SRes ( |
941 | CSzArEx *p, /* allocMain */ |
942 | CSzData *sd, |
943 | UInt64 **unpackSizes, /* allocTemp */ |
944 | Byte **digestsDefined, /* allocTemp */ |
945 | UInt32 **digests, /* allocTemp */ |
946 | Byte **emptyStreamVector, /* allocTemp */ |
947 | Byte **emptyFileVector, /* allocTemp */ |
948 | Byte **lwtVector, /* allocTemp */ |
949 | ISzAlloc *allocMain, |
950 | ISzAlloc *allocTemp) |
951 | { |
952 | UInt64 type; |
953 | UInt32 numUnpackStreams = 0; |
954 | UInt32 numFiles = 0; |
955 | CSzFileItem *files = 0; |
956 | UInt32 numEmptyStreams = 0; |
957 | UInt32 i; |
958 | |
959 | RINOK(SzReadID(sd, &type)); |
960 | |
961 | if (type == k7zIdArchiveProperties) |
962 | { |
963 | RINOK(SzReadArchiveProperties(sd)); |
964 | RINOK(SzReadID(sd, &type)); |
965 | } |
966 | |
967 | |
968 | if (type == k7zIdMainStreamsInfo) |
969 | { |
970 | RINOK(SzReadStreamsInfo(sd, |
971 | &p->dataPos, |
972 | &p->db, |
973 | &numUnpackStreams, |
974 | unpackSizes, |
975 | digestsDefined, |
976 | digests, allocMain, allocTemp)); |
977 | p->dataPos += p->startPosAfterHeader; |
978 | RINOK(SzReadID(sd, &type)); |
979 | } |
980 | |
981 | if (type == k7zIdEnd) |
982 | return SZ_OK; |
983 | if (type != k7zIdFilesInfo) |
984 | return SZ_ERROR_ARCHIVE; |
985 | |
986 | RINOK(SzReadNumber32(sd, &numFiles)); |
987 | p->db.NumFiles = numFiles; |
988 | |
989 | MY_ALLOC(CSzFileItem, files, (size_t)numFiles, allocMain); |
990 | |
991 | p->db.Files = files; |
992 | for (i = 0; i < numFiles; i++) |
993 | SzFile_Init(files + i); |
994 | |
995 | for (;;) |
996 | { |
997 | UInt64 type2; |
998 | UInt64 size; |
999 | RINOK(SzReadID(sd, &type2)); |
1000 | if (type2 == k7zIdEnd) |
1001 | break; |
1002 | RINOK(SzReadNumber(sd, &size)); |
1003 | if (size > sd->Size) |
1004 | return SZ_ERROR_ARCHIVE; |
1005 | if ((UInt64)(int)type2 != type2) |
1006 | { |
1007 | RINOK(SzSkeepDataSize(sd, size)); |
1008 | } |
1009 | else |
1010 | switch((int)type2) |
1011 | { |
1012 | case k7zIdName: |
1013 | { |
1014 | size_t namesSize; |
1015 | RINOK(SzReadSwitch(sd)); |
1016 | namesSize = (size_t)size - 1; |
1017 | if ((namesSize & 1) != 0) |
1018 | return SZ_ERROR_ARCHIVE; |
1019 | if (!Buf_Create(&p->FileNames, namesSize, allocMain)) |
1020 | return SZ_ERROR_MEM; |
1021 | MY_ALLOC(size_t, p->FileNameOffsets, numFiles + 1, allocMain); |
1022 | memcpy(p->FileNames.data, sd->Data, namesSize); |
1023 | RINOK(SzReadFileNames(sd->Data, namesSize >> 1, numFiles, p->FileNameOffsets)) |
1024 | RINOK(SzSkeepDataSize(sd, namesSize)); |
1025 | break; |
1026 | } |
1027 | case k7zIdEmptyStream: |
1028 | { |
1029 | RINOK(SzReadBoolVector(sd, numFiles, emptyStreamVector, allocTemp)); |
1030 | numEmptyStreams = 0; |
1031 | for (i = 0; i < numFiles; i++) |
1032 | if ((*emptyStreamVector)[i]) |
1033 | numEmptyStreams++; |
1034 | break; |
1035 | } |
1036 | case k7zIdEmptyFile: |
1037 | { |
1038 | RINOK(SzReadBoolVector(sd, numEmptyStreams, emptyFileVector, allocTemp)); |
1039 | break; |
1040 | } |
1041 | case k7zIdWinAttributes: |
1042 | { |
1043 | RINOK(SzReadBoolVector2(sd, numFiles, lwtVector, allocTemp)); |
1044 | RINOK(SzReadSwitch(sd)); |
1045 | for (i = 0; i < numFiles; i++) |
1046 | { |
1047 | CSzFileItem *f = &files[i]; |
1048 | Byte defined = (*lwtVector)[i]; |
1049 | f->AttribDefined = defined; |
1050 | f->Attrib = 0; |
1051 | if (defined) |
1052 | { |
1053 | RINOK(SzReadUInt32(sd, &f->Attrib)); |
1054 | } |
1055 | } |
1056 | IAlloc_Free(allocTemp, *lwtVector); |
1057 | *lwtVector = NULL; |
1058 | break; |
1059 | } |
1060 | case k7zIdMTime: |
1061 | { |
1062 | RINOK(SzReadBoolVector2(sd, numFiles, lwtVector, allocTemp)); |
1063 | RINOK(SzReadSwitch(sd)); |
1064 | for (i = 0; i < numFiles; i++) |
1065 | { |
1066 | CSzFileItem *f = &files[i]; |
1067 | Byte defined = (*lwtVector)[i]; |
1068 | f->MTimeDefined = defined; |
1069 | f->MTime.Low = f->MTime.High = 0; |
1070 | if (defined) |
1071 | { |
1072 | RINOK(SzReadUInt32(sd, &f->MTime.Low)); |
1073 | RINOK(SzReadUInt32(sd, &f->MTime.High)); |
1074 | } |
1075 | } |
1076 | IAlloc_Free(allocTemp, *lwtVector); |
1077 | *lwtVector = NULL; |
1078 | break; |
1079 | } |
1080 | default: |
1081 | { |
1082 | RINOK(SzSkeepDataSize(sd, size)); |
1083 | } |
1084 | } |
1085 | } |
1086 | |
1087 | { |
1088 | UInt32 emptyFileIndex = 0; |
1089 | UInt32 sizeIndex = 0; |
1090 | for (i = 0; i < numFiles; i++) |
1091 | { |
1092 | CSzFileItem *file = files + i; |
1093 | file->IsAnti = 0; |
1094 | if (*emptyStreamVector == 0) |
1095 | file->HasStream = 1; |
1096 | else |
1097 | file->HasStream = (Byte)((*emptyStreamVector)[i] ? 0 : 1); |
1098 | if (file->HasStream) |
1099 | { |
1100 | file->IsDir = 0; |
1101 | file->Size = (*unpackSizes)[sizeIndex]; |
1102 | file->Crc = (*digests)[sizeIndex]; |
1103 | file->CrcDefined = (Byte)(*digestsDefined)[sizeIndex]; |
1104 | sizeIndex++; |
1105 | } |
1106 | else |
1107 | { |
1108 | if (*emptyFileVector == 0) |
1109 | file->IsDir = 1; |
1110 | else |
1111 | file->IsDir = (Byte)((*emptyFileVector)[emptyFileIndex] ? 0 : 1); |
1112 | emptyFileIndex++; |
1113 | file->Size = 0; |
1114 | file->Crc = 0; |
1115 | file->CrcDefined = 0; |
1116 | } |
1117 | } |
1118 | } |
1119 | return SzArEx_Fill(p, allocMain); |
1120 | } |
1121 | |
1122 | static SRes ( |
1123 | CSzArEx *p, |
1124 | CSzData *sd, |
1125 | ISzAlloc *allocMain, |
1126 | ISzAlloc *allocTemp) |
1127 | { |
1128 | UInt64 *unpackSizes = 0; |
1129 | Byte *digestsDefined = 0; |
1130 | UInt32 *digests = 0; |
1131 | Byte *emptyStreamVector = 0; |
1132 | Byte *emptyFileVector = 0; |
1133 | Byte *lwtVector = 0; |
1134 | SRes res = SzReadHeader2(p, sd, |
1135 | &unpackSizes, &digestsDefined, &digests, |
1136 | &emptyStreamVector, &emptyFileVector, &lwtVector, |
1137 | allocMain, allocTemp); |
1138 | IAlloc_Free(allocTemp, unpackSizes); |
1139 | IAlloc_Free(allocTemp, digestsDefined); |
1140 | IAlloc_Free(allocTemp, digests); |
1141 | IAlloc_Free(allocTemp, emptyStreamVector); |
1142 | IAlloc_Free(allocTemp, emptyFileVector); |
1143 | IAlloc_Free(allocTemp, lwtVector); |
1144 | return res; |
1145 | } |
1146 | |
1147 | static SRes SzReadAndDecodePackedStreams2( |
1148 | ILookInStream *inStream, |
1149 | CSzData *sd, |
1150 | CBuf *outBuffer, |
1151 | UInt64 baseOffset, |
1152 | CSzAr *p, |
1153 | UInt64 **unpackSizes, |
1154 | Byte **digestsDefined, |
1155 | UInt32 **digests, |
1156 | ISzAlloc *allocTemp) |
1157 | { |
1158 | |
1159 | UInt32 numUnpackStreams = 0; |
1160 | UInt64 dataStartPos; |
1161 | CSzFolder *folder; |
1162 | UInt64 unpackSize; |
1163 | SRes res; |
1164 | |
1165 | RINOK(SzReadStreamsInfo(sd, &dataStartPos, p, |
1166 | &numUnpackStreams, unpackSizes, digestsDefined, digests, |
1167 | allocTemp, allocTemp)); |
1168 | |
1169 | dataStartPos += baseOffset; |
1170 | if (p->NumFolders != 1) |
1171 | return SZ_ERROR_ARCHIVE; |
1172 | |
1173 | folder = p->Folders; |
1174 | unpackSize = SzFolder_GetUnpackSize(folder); |
1175 | |
1176 | RINOK(LookInStream_SeekTo(inStream, dataStartPos)); |
1177 | |
1178 | if (!Buf_Create(outBuffer, (size_t)unpackSize, allocTemp)) |
1179 | return SZ_ERROR_MEM; |
1180 | |
1181 | res = SzFolder_Decode(folder, p->PackSizes, |
1182 | inStream, dataStartPos, |
1183 | outBuffer->data, (size_t)unpackSize, allocTemp); |
1184 | RINOK(res); |
1185 | if (folder->UnpackCRCDefined) |
1186 | if (CrcCalc(outBuffer->data, (size_t)unpackSize) != folder->UnpackCRC) |
1187 | return SZ_ERROR_CRC; |
1188 | return SZ_OK; |
1189 | } |
1190 | |
1191 | static SRes SzReadAndDecodePackedStreams( |
1192 | ILookInStream *inStream, |
1193 | CSzData *sd, |
1194 | CBuf *outBuffer, |
1195 | UInt64 baseOffset, |
1196 | ISzAlloc *allocTemp) |
1197 | { |
1198 | CSzAr p; |
1199 | UInt64 *unpackSizes = 0; |
1200 | Byte *digestsDefined = 0; |
1201 | UInt32 *digests = 0; |
1202 | SRes res; |
1203 | SzAr_Init(&p); |
1204 | res = SzReadAndDecodePackedStreams2(inStream, sd, outBuffer, baseOffset, |
1205 | &p, &unpackSizes, &digestsDefined, &digests, |
1206 | allocTemp); |
1207 | SzAr_Free(&p, allocTemp); |
1208 | IAlloc_Free(allocTemp, unpackSizes); |
1209 | IAlloc_Free(allocTemp, digestsDefined); |
1210 | IAlloc_Free(allocTemp, digests); |
1211 | return res; |
1212 | } |
1213 | |
1214 | static SRes SzArEx_Open2( |
1215 | CSzArEx *p, |
1216 | ILookInStream *inStream, |
1217 | ISzAlloc *allocMain, |
1218 | ISzAlloc *allocTemp) |
1219 | { |
1220 | Byte [k7zStartHeaderSize]; |
1221 | Int64 startArcPos; |
1222 | UInt64 , ; |
1223 | size_t ; |
1224 | UInt32 ; |
1225 | CBuf buffer; |
1226 | SRes res; |
1227 | |
1228 | startArcPos = 0; |
1229 | RINOK(inStream->Seek(inStream, &startArcPos, SZ_SEEK_CUR)); |
1230 | |
1231 | RINOK(LookInStream_Read2(inStream, header, k7zStartHeaderSize, SZ_ERROR_NO_ARCHIVE)); |
1232 | |
1233 | if (!TestSignatureCandidate(header)) |
1234 | return SZ_ERROR_NO_ARCHIVE; |
1235 | if (header[6] != k7zMajorVersion) |
1236 | return SZ_ERROR_UNSUPPORTED; |
1237 | |
1238 | nextHeaderOffset = GetUi64(header + 12); |
1239 | nextHeaderSize = GetUi64(header + 20); |
1240 | nextHeaderCRC = GetUi32(header + 28); |
1241 | |
1242 | p->startPosAfterHeader = startArcPos + k7zStartHeaderSize; |
1243 | |
1244 | if (CrcCalc(header + 12, 20) != GetUi32(header + 8)) |
1245 | return SZ_ERROR_CRC; |
1246 | |
1247 | nextHeaderSizeT = (size_t)nextHeaderSize; |
1248 | if (nextHeaderSizeT != nextHeaderSize) |
1249 | return SZ_ERROR_MEM; |
1250 | if (nextHeaderSizeT == 0) |
1251 | return SZ_OK; |
1252 | if (nextHeaderOffset > nextHeaderOffset + nextHeaderSize || |
1253 | nextHeaderOffset > nextHeaderOffset + nextHeaderSize + k7zStartHeaderSize) |
1254 | return SZ_ERROR_NO_ARCHIVE; |
1255 | |
1256 | { |
1257 | Int64 pos = 0; |
1258 | RINOK(inStream->Seek(inStream, &pos, SZ_SEEK_END)); |
1259 | if ((UInt64)pos < startArcPos + nextHeaderOffset || |
1260 | (UInt64)pos < startArcPos + k7zStartHeaderSize + nextHeaderOffset || |
1261 | (UInt64)pos < startArcPos + k7zStartHeaderSize + nextHeaderOffset + nextHeaderSize) |
1262 | return SZ_ERROR_INPUT_EOF; |
1263 | } |
1264 | |
1265 | RINOK(LookInStream_SeekTo(inStream, startArcPos + k7zStartHeaderSize + nextHeaderOffset)); |
1266 | |
1267 | if (!Buf_Create(&buffer, nextHeaderSizeT, allocTemp)) |
1268 | return SZ_ERROR_MEM; |
1269 | |
1270 | res = LookInStream_Read(inStream, buffer.data, nextHeaderSizeT); |
1271 | if (res == SZ_OK) |
1272 | { |
1273 | res = SZ_ERROR_ARCHIVE; |
1274 | if (CrcCalc(buffer.data, nextHeaderSizeT) == nextHeaderCRC) |
1275 | { |
1276 | CSzData sd; |
1277 | UInt64 type; |
1278 | sd.Data = buffer.data; |
1279 | sd.Size = buffer.size; |
1280 | res = SzReadID(&sd, &type); |
1281 | if (res == SZ_OK) |
1282 | { |
1283 | if (type == k7zIdEncodedHeader) |
1284 | { |
1285 | CBuf outBuffer; |
1286 | Buf_Init(&outBuffer); |
1287 | res = SzReadAndDecodePackedStreams(inStream, &sd, &outBuffer, p->startPosAfterHeader, allocTemp); |
1288 | if (res != SZ_OK) |
1289 | Buf_Free(&outBuffer, allocTemp); |
1290 | else |
1291 | { |
1292 | Buf_Free(&buffer, allocTemp); |
1293 | buffer.data = outBuffer.data; |
1294 | buffer.size = outBuffer.size; |
1295 | sd.Data = buffer.data; |
1296 | sd.Size = buffer.size; |
1297 | res = SzReadID(&sd, &type); |
1298 | } |
1299 | } |
1300 | } |
1301 | if (res == SZ_OK) |
1302 | { |
1303 | if (type == k7zIdHeader) |
1304 | res = SzReadHeader(p, &sd, allocMain, allocTemp); |
1305 | else |
1306 | res = SZ_ERROR_UNSUPPORTED; |
1307 | } |
1308 | } |
1309 | } |
1310 | Buf_Free(&buffer, allocTemp); |
1311 | return res; |
1312 | } |
1313 | |
1314 | SRes SzArEx_Open(CSzArEx *p, ILookInStream *inStream, ISzAlloc *allocMain, ISzAlloc *allocTemp) |
1315 | { |
1316 | SRes res = SzArEx_Open2(p, inStream, allocMain, allocTemp); |
1317 | if (res != SZ_OK) |
1318 | SzArEx_Free(p, allocMain); |
1319 | return res; |
1320 | } |
1321 | |
1322 | SRes ( |
1323 | const CSzArEx *p, |
1324 | ILookInStream *inStream, |
1325 | UInt32 fileIndex, |
1326 | UInt32 *blockIndex, |
1327 | Byte **outBuffer, |
1328 | size_t *outBufferSize, |
1329 | size_t *offset, |
1330 | size_t *outSizeProcessed, |
1331 | ISzAlloc *allocMain, |
1332 | ISzAlloc *allocTemp) |
1333 | { |
1334 | UInt32 folderIndex = p->FileIndexToFolderIndexMap[fileIndex]; |
1335 | SRes res = SZ_OK; |
1336 | *offset = 0; |
1337 | *outSizeProcessed = 0; |
1338 | if (folderIndex == (UInt32)-1) |
1339 | { |
1340 | IAlloc_Free(allocMain, *outBuffer); |
1341 | *blockIndex = folderIndex; |
1342 | *outBuffer = 0; |
1343 | *outBufferSize = 0; |
1344 | return SZ_OK; |
1345 | } |
1346 | |
1347 | if (*outBuffer == 0 || *blockIndex != folderIndex) |
1348 | { |
1349 | CSzFolder *folder = p->db.Folders + folderIndex; |
1350 | UInt64 unpackSizeSpec = SzFolder_GetUnpackSize(folder); |
1351 | size_t unpackSize = (size_t)unpackSizeSpec; |
1352 | UInt64 startOffset = SzArEx_GetFolderStreamPos(p, folderIndex, 0); |
1353 | |
1354 | if (unpackSize != unpackSizeSpec) |
1355 | return SZ_ERROR_MEM; |
1356 | *blockIndex = folderIndex; |
1357 | IAlloc_Free(allocMain, *outBuffer); |
1358 | *outBuffer = 0; |
1359 | |
1360 | RINOK(LookInStream_SeekTo(inStream, startOffset)); |
1361 | |
1362 | if (res == SZ_OK) |
1363 | { |
1364 | *outBufferSize = unpackSize; |
1365 | if (unpackSize != 0) |
1366 | { |
1367 | *outBuffer = (Byte *)IAlloc_Alloc(allocMain, unpackSize); |
1368 | if (*outBuffer == 0) |
1369 | res = SZ_ERROR_MEM; |
1370 | } |
1371 | if (res == SZ_OK) |
1372 | { |
1373 | res = SzFolder_Decode(folder, |
1374 | p->db.PackSizes + p->FolderStartPackStreamIndex[folderIndex], |
1375 | inStream, startOffset, |
1376 | *outBuffer, unpackSize, allocTemp); |
1377 | if (res == SZ_OK) |
1378 | { |
1379 | if (folder->UnpackCRCDefined) |
1380 | { |
1381 | if (CrcCalc(*outBuffer, unpackSize) != folder->UnpackCRC) |
1382 | res = SZ_ERROR_CRC; |
1383 | } |
1384 | } |
1385 | } |
1386 | } |
1387 | } |
1388 | if (res == SZ_OK) |
1389 | { |
1390 | UInt32 i; |
1391 | CSzFileItem *fileItem = p->db.Files + fileIndex; |
1392 | *offset = 0; |
1393 | for (i = p->FolderStartFileIndex[folderIndex]; i < fileIndex; i++) |
1394 | *offset += (UInt32)p->db.Files[i].Size; |
1395 | *outSizeProcessed = (size_t)fileItem->Size; |
1396 | if (*offset + *outSizeProcessed > *outBufferSize) |
1397 | return SZ_ERROR_FAIL; |
1398 | if (fileItem->CrcDefined && CrcCalc(*outBuffer + *offset, *outSizeProcessed) != fileItem->Crc) |
1399 | res = SZ_ERROR_CRC; |
1400 | } |
1401 | return res; |
1402 | } |
1403 | |