blob: f1a44928e2ac5903677bce23cab584679264ca55 [file] [log] [blame]
repo syncbaa38582013-07-26 17:53:31 -07001/* 7zIn.c -- 7z Input functions
22010-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
10Byte 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
17void SzCoderInfo_Init(CSzCoderInfo *p)
18{
19 Buf_Init(&p->Props);
20}
21
22void SzCoderInfo_Free(CSzCoderInfo *p, ISzAlloc *alloc)
23{
24 Buf_Free(&p->Props, alloc);
25 SzCoderInfo_Init(p);
26}
27
28void 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
42void 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
55UInt32 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
64int 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
74int 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
83UInt64 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
95void 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
104void 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
116void 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
132void 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
143void 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/*
158UInt64 GetFolderPackStreamSize(int folderIndex, int streamIndex) const
159{
160 return PackSizes[FolderStartPackStreamIndex[folderIndex] + streamIndex];
161}
162
163UInt64 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
179static 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
243UInt64 SzArEx_GetFolderStreamPos(const CSzArEx *p, UInt32 folderIndex, UInt32 indexInFolder)
244{
245 return p->dataPos +
246 p->PackStreamStartPositions[p->FolderStartPackStreamIndex[folderIndex] + indexInFolder];
247}
248
249int 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/*
268SRes 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
301static 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
310typedef struct _CSzState
311{
312 Byte *Data;
313 size_t Size;
314}CSzData;
315
316static 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
325static 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
335static 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
348static 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
371static 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
383static SRes SzReadID(CSzData *sd, UInt64 *value)
384{
385 return SzReadNumber(sd, value);
386}
387
388static 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
397static SRes SzSkeepData(CSzData *sd)
398{
399 UInt64 size;
400 RINOK(SzReadNumber(sd, &size));
401 return SzSkeepDataSize(sd, size);
402}
403
404static 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
417static 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
431static 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
450static 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
463static 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
481static 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
529static SRes SzReadSwitch(CSzData *sd)
530{
531 Byte external;
532 RINOK(SzReadByte(sd, &external));
533 return (external == 0) ? SZ_OK: SZ_ERROR_UNSUPPORTED;
534}
535
536static 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
646static 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
716static 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
862static 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
906size_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
919static 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
940static SRes SzReadHeader2(
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 type;
998 UInt64 size;
999 RINOK(SzReadID(sd, &type));
1000 if (type == k7zIdEnd)
1001 break;
1002 RINOK(SzReadNumber(sd, &size));
1003 if (size > sd->Size)
1004 return SZ_ERROR_ARCHIVE;
1005 if ((UInt64)(int)type != type)
1006 {
1007 RINOK(SzSkeepDataSize(sd, size));
1008 }
1009 else
1010 switch((int)type)
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
1122static SRes SzReadHeader(
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
1147static 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
1191static 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
1214static SRes SzArEx_Open2(
1215 CSzArEx *p,
1216 ILookInStream *inStream,
1217 ISzAlloc *allocMain,
1218 ISzAlloc *allocTemp)
1219{
1220 Byte header[k7zStartHeaderSize];
1221 Int64 startArcPos;
1222 UInt64 nextHeaderOffset, nextHeaderSize;
1223 size_t nextHeaderSizeT;
1224 UInt32 nextHeaderCRC;
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
1314SRes 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
1322SRes SzArEx_Extract(
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}