Ensure low-memory renderers retry failed loads correctly.
[chromium-blink-merge.git] / third_party / lzma_sdk / 7zIn.c
blobec93a43ffec78bd1d60408809f29947fbcd99437
1 /* 7zIn.c -- 7z Input functions
2 2010-10-29 : Igor Pavlov : Public domain */
4 #include <string.h>
6 #include "7z.h"
7 #include "7zCrc.h"
8 #include "CpuArch.h"
10 Byte k7zSignature[k7zSignatureSize] = {'7', 'z', 0xBC, 0xAF, 0x27, 0x1C};
12 #define RINOM(x) { if ((x) == 0) return SZ_ERROR_MEM; }
14 #define NUM_FOLDER_CODERS_MAX 32
15 #define NUM_CODER_STREAMS_MAX 32
17 void SzCoderInfo_Init(CSzCoderInfo *p)
19 Buf_Init(&p->Props);
22 void SzCoderInfo_Free(CSzCoderInfo *p, ISzAlloc *alloc)
24 Buf_Free(&p->Props, alloc);
25 SzCoderInfo_Init(p);
28 void SzFolder_Init(CSzFolder *p)
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;
42 void SzFolder_Free(CSzFolder *p, ISzAlloc *alloc)
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);
55 UInt32 SzFolder_GetNumOutStreams(CSzFolder *p)
57 UInt32 result = 0;
58 UInt32 i;
59 for (i = 0; i < p->NumCoders; i++)
60 result += p->Coders[i].NumOutStreams;
61 return result;
64 int SzFolder_FindBindPairForInStream(CSzFolder *p, UInt32 inStreamIndex)
66 UInt32 i;
67 for (i = 0; i < p->NumBindPairs; i++)
68 if (p->BindPairs[i].InIndex == inStreamIndex)
69 return i;
70 return -1;
74 int SzFolder_FindBindPairForOutStream(CSzFolder *p, UInt32 outStreamIndex)
76 UInt32 i;
77 for (i = 0; i < p->NumBindPairs; i++)
78 if (p->BindPairs[i].OutIndex == outStreamIndex)
79 return i;
80 return -1;
83 UInt64 SzFolder_GetUnpackSize(CSzFolder *p)
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;
95 void SzFile_Init(CSzFileItem *p)
97 p->HasStream = 1;
98 p->IsDir = 0;
99 p->IsAnti = 0;
100 p->CrcDefined = 0;
101 p->MTimeDefined = 0;
104 void SzAr_Init(CSzAr *p)
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;
116 void SzAr_Free(CSzAr *p, ISzAlloc *alloc)
118 UInt32 i;
119 if (p->Folders)
120 for (i = 0; i < p->NumFolders; i++)
121 SzFolder_Free(&p->Folders[i], alloc);
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);
132 void SzArEx_Init(CSzArEx *p)
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);
143 void SzArEx_Free(CSzArEx *p, ISzAlloc *alloc)
145 IAlloc_Free(alloc, p->FolderStartPackStreamIndex);
146 IAlloc_Free(alloc, p->PackStreamStartPositions);
147 IAlloc_Free(alloc, p->FolderStartFileIndex);
148 IAlloc_Free(alloc, p->FileIndexToFolderIndexMap);
150 IAlloc_Free(alloc, p->FileNameOffsets);
151 Buf_Free(&p->FileNames, alloc);
153 SzAr_Free(&p->db, alloc);
154 SzArEx_Init(p);
158 UInt64 GetFolderPackStreamSize(int folderIndex, int streamIndex) const
160 return PackSizes[FolderStartPackStreamIndex[folderIndex] + streamIndex];
163 UInt64 GetFilePackSize(int fileIndex) const
165 int folderIndex = FileIndexToFolderIndexMap[fileIndex];
166 if (folderIndex >= 0)
168 const CSzFolder &folderInfo = Folders[folderIndex];
169 if (FolderStartFileIndex[folderIndex] == fileIndex)
170 return GetFolderFullPackSize(folderIndex);
172 return 0;
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; }
179 static SRes SzArEx_Fill(CSzArEx *p, ISzAlloc *alloc)
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++)
189 p->FolderStartPackStreamIndex[i] = startPos;
190 startPos += p->db.Folders[i].NumPackStreams;
193 MY_ALLOC(UInt64, p->PackStreamStartPositions, p->db.NumPackStreams, alloc);
195 for (i = 0; i < p->db.NumPackStreams; i++)
197 p->PackStreamStartPositions[i] = startPosSize;
198 startPosSize += p->db.PackSizes[i];
201 MY_ALLOC(UInt32, p->FolderStartFileIndex, p->db.NumFolders, alloc);
202 MY_ALLOC(UInt32, p->FileIndexToFolderIndexMap, p->db.NumFiles, alloc);
204 for (i = 0; i < p->db.NumFiles; i++)
206 CSzFileItem *file = p->db.Files + i;
207 int emptyStream = !file->HasStream;
208 if (emptyStream && indexInFolder == 0)
210 p->FileIndexToFolderIndexMap[i] = (UInt32)-1;
211 continue;
213 if (indexInFolder == 0)
216 v3.13 incorrectly worked with empty folders
217 v4.07: Loop for skipping empty folders
219 for (;;)
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++;
229 p->FileIndexToFolderIndexMap[i] = folderIndex;
230 if (emptyStream)
231 continue;
232 indexInFolder++;
233 if (indexInFolder >= p->db.Folders[folderIndex].NumUnpackStreams)
235 folderIndex++;
236 indexInFolder = 0;
239 return SZ_OK;
243 UInt64 SzArEx_GetFolderStreamPos(const CSzArEx *p, UInt32 folderIndex, UInt32 indexInFolder)
245 return p->dataPos +
246 p->PackStreamStartPositions[p->FolderStartPackStreamIndex[folderIndex] + indexInFolder];
249 int SzArEx_GetFolderFullPackSize(const CSzArEx *p, UInt32 folderIndex, UInt64 *resSize)
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++)
257 UInt64 t = size + p->db.PackSizes[packStreamIndex + i];
258 if (t < size) /* check it */
259 return SZ_ERROR_FAIL;
260 size = t;
262 *resSize = size;
263 return SZ_OK;
268 SRes SzReadTime(const CObjectVector<CBuf> &dataVector,
269 CObjectVector<CSzFileItem> &files, UInt64 type)
271 CBoolVector boolVector;
272 RINOK(ReadBoolVector2(files.Size(), boolVector))
274 CStreamSwitch streamSwitch;
275 RINOK(streamSwitch.Set(this, &dataVector));
277 for (int i = 0; i < files.Size(); i++)
279 CSzFileItem &file = files[i];
280 CArchiveFileTime fileTime;
281 bool defined = boolVector[i];
282 if (defined)
284 UInt32 low, high;
285 RINOK(SzReadUInt32(low));
286 RINOK(SzReadUInt32(high));
287 fileTime.dwLowDateTime = low;
288 fileTime.dwHighDateTime = high;
290 switch(type)
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;
297 return SZ_OK;
301 static int TestSignatureCandidate(Byte *testBytes)
303 size_t i;
304 for (i = 0; i < k7zSignatureSize; i++)
305 if (testBytes[i] != k7zSignature[i])
306 return 0;
307 return 1;
310 typedef struct _CSzState
312 Byte *Data;
313 size_t Size;
314 }CSzData;
316 static SRes SzReadByte(CSzData *sd, Byte *b)
318 if (sd->Size == 0)
319 return SZ_ERROR_ARCHIVE;
320 sd->Size--;
321 *b = *sd->Data++;
322 return SZ_OK;
325 static SRes SzReadBytes(CSzData *sd, Byte *data, size_t size)
327 size_t i;
328 for (i = 0; i < size; i++)
330 RINOK(SzReadByte(sd, data + i));
332 return SZ_OK;
335 static SRes SzReadUInt32(CSzData *sd, UInt32 *value)
337 int i;
338 *value = 0;
339 for (i = 0; i < 4; i++)
341 Byte b;
342 RINOK(SzReadByte(sd, &b));
343 *value |= ((UInt32)(b) << (8 * i));
345 return SZ_OK;
348 static SRes SzReadNumber(CSzData *sd, UInt64 *value)
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++)
357 Byte b;
358 if ((firstByte & mask) == 0)
360 UInt64 highPart = firstByte & (mask - 1);
361 *value += (highPart << (8 * i));
362 return SZ_OK;
364 RINOK(SzReadByte(sd, &b));
365 *value |= ((UInt64)b << (8 * i));
366 mask >>= 1;
368 return SZ_OK;
371 static SRes SzReadNumber32(CSzData *sd, UInt32 *value)
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;
383 static SRes SzReadID(CSzData *sd, UInt64 *value)
385 return SzReadNumber(sd, value);
388 static SRes SzSkeepDataSize(CSzData *sd, UInt64 size)
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;
397 static SRes SzSkeepData(CSzData *sd)
399 UInt64 size;
400 RINOK(SzReadNumber(sd, &size));
401 return SzSkeepDataSize(sd, size);
404 static SRes SzReadArchiveProperties(CSzData *sd)
406 for (;;)
408 UInt64 type;
409 RINOK(SzReadID(sd, &type));
410 if (type == k7zIdEnd)
411 break;
412 SzSkeepData(sd);
414 return SZ_OK;
417 static SRes SzWaitAttribute(CSzData *sd, UInt64 attribute)
419 for (;;)
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));
431 static SRes SzReadBoolVector(CSzData *sd, size_t numItems, Byte **v, ISzAlloc *alloc)
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++)
439 if (mask == 0)
441 RINOK(SzReadByte(sd, &b));
442 mask = 0x80;
444 (*v)[i] = (Byte)(((b & mask) != 0) ? 1 : 0);
445 mask >>= 1;
447 return SZ_OK;
450 static SRes SzReadBoolVector2(CSzData *sd, size_t numItems, Byte **v, ISzAlloc *alloc)
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;
463 static SRes SzReadHashDigests(
464 CSzData *sd,
465 size_t numItems,
466 Byte **digestsDefined,
467 UInt32 **digests,
468 ISzAlloc *alloc)
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])
476 RINOK(SzReadUInt32(sd, (*digests) + i));
478 return SZ_OK;
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)
490 UInt32 i;
491 RINOK(SzReadNumber(sd, dataOffset));
492 RINOK(SzReadNumber32(sd, numPackStreams));
494 RINOK(SzWaitAttribute(sd, k7zIdSize));
496 MY_ALLOC(UInt64, *packSizes, (size_t)*numPackStreams, alloc);
498 for (i = 0; i < *numPackStreams; i++)
500 RINOK(SzReadNumber(sd, (*packSizes) + i));
503 for (;;)
505 UInt64 type;
506 RINOK(SzReadID(sd, &type));
507 if (type == k7zIdEnd)
508 break;
509 if (type == k7zIdCRC)
511 RINOK(SzReadHashDigests(sd, (size_t)*numPackStreams, packCRCsDefined, packCRCs, alloc));
512 continue;
514 RINOK(SzSkeepData(sd));
516 if (*packCRCsDefined == 0)
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++)
522 (*packCRCsDefined)[i] = 0;
523 (*packCRCs)[i] = 0;
526 return SZ_OK;
529 static SRes SzReadSwitch(CSzData *sd)
531 Byte external;
532 RINOK(SzReadByte(sd, &external));
533 return (external == 0) ? SZ_OK: SZ_ERROR_UNSUPPORTED;
536 static SRes SzGetNextFolderItem(CSzData *sd, CSzFolder *folder, ISzAlloc *alloc)
538 UInt32 numCoders, numBindPairs, numPackStreams, i;
539 UInt32 numInStreams = 0, numOutStreams = 0;
541 RINOK(SzReadNumber32(sd, &numCoders));
542 if (numCoders > NUM_FOLDER_CODERS_MAX)
543 return SZ_ERROR_UNSUPPORTED;
544 folder->NumCoders = numCoders;
546 MY_ALLOC(CSzCoderInfo, folder->Coders, (size_t)numCoders, alloc);
548 for (i = 0; i < numCoders; i++)
549 SzCoderInfo_Init(folder->Coders + i);
551 for (i = 0; i < numCoders; i++)
553 Byte mainByte;
554 CSzCoderInfo *coder = folder->Coders + i;
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);
567 if ((mainByte & 0x10) != 0)
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;
575 else
577 coder->NumInStreams = 1;
578 coder->NumOutStreams = 1;
580 if ((mainByte & 0x20) != 0)
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));
589 while ((mainByte & 0x80) != 0)
591 RINOK(SzReadByte(sd, &mainByte));
592 RINOK(SzSkeepDataSize(sd, (mainByte & 0xF)));
593 if ((mainByte & 0x10) != 0)
595 UInt32 n;
596 RINOK(SzReadNumber32(sd, &n));
597 RINOK(SzReadNumber32(sd, &n));
599 if ((mainByte & 0x20) != 0)
601 UInt64 propertiesSize = 0;
602 RINOK(SzReadNumber(sd, &propertiesSize));
603 RINOK(SzSkeepDataSize(sd, propertiesSize));
606 numInStreams += coder->NumInStreams;
607 numOutStreams += coder->NumOutStreams;
610 if (numOutStreams == 0)
611 return SZ_ERROR_UNSUPPORTED;
613 folder->NumBindPairs = numBindPairs = numOutStreams - 1;
614 MY_ALLOC(CSzBindPair, folder->BindPairs, (size_t)numBindPairs, alloc);
616 for (i = 0; i < numBindPairs; i++)
618 CSzBindPair *bp = folder->BindPairs + i;
619 RINOK(SzReadNumber32(sd, &bp->InIndex));
620 RINOK(SzReadNumber32(sd, &bp->OutIndex));
623 if (numInStreams < numBindPairs)
624 return SZ_ERROR_UNSUPPORTED;
626 folder->NumPackStreams = numPackStreams = numInStreams - numBindPairs;
627 MY_ALLOC(UInt32, folder->PackStreams, (size_t)numPackStreams, alloc);
629 if (numPackStreams == 1)
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;
638 else
639 for (i = 0; i < numPackStreams; i++)
641 RINOK(SzReadNumber32(sd, folder->PackStreams + i));
643 return SZ_OK;
646 static SRes SzReadUnpackInfo(
647 CSzData *sd,
648 UInt32 *numFolders,
649 CSzFolder **folders, /* for alloc */
650 ISzAlloc *alloc,
651 ISzAlloc *allocTemp)
653 UInt32 i;
654 RINOK(SzWaitAttribute(sd, k7zIdFolder));
655 RINOK(SzReadNumber32(sd, numFolders));
657 RINOK(SzReadSwitch(sd));
659 MY_ALLOC(CSzFolder, *folders, (size_t)*numFolders, alloc);
661 for (i = 0; i < *numFolders; i++)
662 SzFolder_Init((*folders) + i);
664 for (i = 0; i < *numFolders; i++)
666 RINOK(SzGetNextFolderItem(sd, (*folders) + i, alloc));
670 RINOK(SzWaitAttribute(sd, k7zIdCodersUnpackSize));
672 for (i = 0; i < *numFolders; i++)
674 UInt32 j;
675 CSzFolder *folder = (*folders) + i;
676 UInt32 numOutStreams = SzFolder_GetNumOutStreams(folder);
678 MY_ALLOC(UInt64, folder->UnpackSizes, (size_t)numOutStreams, alloc);
680 for (j = 0; j < numOutStreams; j++)
682 RINOK(SzReadNumber(sd, folder->UnpackSizes + j));
686 for (;;)
688 UInt64 type;
689 RINOK(SzReadID(sd, &type));
690 if (type == k7zIdEnd)
691 return SZ_OK;
692 if (type == k7zIdCRC)
694 SRes res;
695 Byte *crcsDefined = 0;
696 UInt32 *crcs = 0;
697 res = SzReadHashDigests(sd, *numFolders, &crcsDefined, &crcs, allocTemp);
698 if (res == SZ_OK)
700 for (i = 0; i < *numFolders; i++)
702 CSzFolder *folder = (*folders) + i;
703 folder->UnpackCRCDefined = crcsDefined[i];
704 folder->UnpackCRC = crcs[i];
707 IAlloc_Free(allocTemp, crcs);
708 IAlloc_Free(allocTemp, crcsDefined);
709 RINOK(res);
710 continue;
712 RINOK(SzSkeepData(sd));
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)
726 UInt64 type = 0;
727 UInt32 i;
728 UInt32 si = 0;
729 UInt32 numDigests = 0;
731 for (i = 0; i < numFolders; i++)
732 folders[i].NumUnpackStreams = 1;
733 *numUnpackStreams = numFolders;
735 for (;;)
737 RINOK(SzReadID(sd, &type));
738 if (type == k7zIdNumUnpackStream)
740 *numUnpackStreams = 0;
741 for (i = 0; i < numFolders; i++)
743 UInt32 numStreams;
744 RINOK(SzReadNumber32(sd, &numStreams));
745 folders[i].NumUnpackStreams = numStreams;
746 *numUnpackStreams += numStreams;
748 continue;
750 if (type == k7zIdCRC || type == k7zIdSize)
751 break;
752 if (type == k7zIdEnd)
753 break;
754 RINOK(SzSkeepData(sd));
757 if (*numUnpackStreams == 0)
759 *unpackSizes = 0;
760 *digestsDefined = 0;
761 *digests = 0;
763 else
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);
773 for (i = 0; i < numFolders; i++)
776 v3.13 incorrectly worked with empty folders
777 v4.07: we check that folder is empty
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++)
787 UInt64 size;
788 RINOK(SzReadNumber(sd, &size));
789 (*unpackSizes)[si++] = size;
790 sum += size;
792 (*unpackSizes)[si++] = SzFolder_GetUnpackSize(folders + i) - sum;
794 if (type == k7zIdSize)
796 RINOK(SzReadID(sd, &type));
799 for (i = 0; i < *numUnpackStreams; i++)
801 (*digestsDefined)[i] = 0;
802 (*digests)[i] = 0;
806 for (i = 0; i < numFolders; i++)
808 UInt32 numSubstreams = folders[i].NumUnpackStreams;
809 if (numSubstreams != 1 || !folders[i].UnpackCRCDefined)
810 numDigests += numSubstreams;
814 si = 0;
815 for (;;)
817 if (type == k7zIdCRC)
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)
825 for (i = 0; i < numFolders; i++)
827 CSzFolder *folder = folders + i;
828 UInt32 numSubstreams = folder->NumUnpackStreams;
829 if (numSubstreams == 1 && folder->UnpackCRCDefined)
831 (*digestsDefined)[si] = 1;
832 (*digests)[si] = folder->UnpackCRC;
833 si++;
835 else
837 UInt32 j;
838 for (j = 0; j < numSubstreams; j++, digestIndex++)
840 (*digestsDefined)[si] = digestsDefined2[digestIndex];
841 (*digests)[si] = digests2[digestIndex];
842 si++;
847 IAlloc_Free(allocTemp, digestsDefined2);
848 IAlloc_Free(allocTemp, digests2);
849 RINOK(res);
851 else if (type == k7zIdEnd)
852 return SZ_OK;
853 else
855 RINOK(SzSkeepData(sd));
857 RINOK(SzReadID(sd, &type));
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)
873 for (;;)
875 UInt64 type;
876 RINOK(SzReadID(sd, &type));
877 if ((UInt64)(int)type != type)
878 return SZ_ERROR_UNSUPPORTED;
879 switch((int)type)
881 case k7zIdEnd:
882 return SZ_OK;
883 case k7zIdPackInfo:
885 RINOK(SzReadPackInfo(sd, dataOffset, &p->NumPackStreams,
886 &p->PackSizes, &p->PackCRCsDefined, &p->PackCRCs, alloc));
887 break;
889 case k7zIdUnpackInfo:
891 RINOK(SzReadUnpackInfo(sd, &p->NumFolders, &p->Folders, alloc, allocTemp));
892 break;
894 case k7zIdSubStreamsInfo:
896 RINOK(SzReadSubStreamsInfo(sd, p->NumFolders, p->Folders,
897 numUnpackStreams, unpackSizes, digestsDefined, digests, allocTemp));
898 break;
900 default:
901 return SZ_ERROR_UNSUPPORTED;
906 size_t SzArEx_GetFileNameUtf16(const CSzArEx *p, size_t fileIndex, UInt16 *dest)
908 size_t len = p->FileNameOffsets[fileIndex + 1] - p->FileNameOffsets[fileIndex];
909 if (dest != 0)
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);
916 return len;
919 static SRes SzReadFileNames(const Byte *p, size_t size, UInt32 numFiles, size_t *sizes)
921 UInt32 i;
922 size_t pos = 0;
923 for (i = 0; i < numFiles; i++)
925 sizes[i] = pos;
926 for (;;)
928 if (pos >= size)
929 return SZ_ERROR_ARCHIVE;
930 if (p[pos * 2] == 0 && p[pos * 2 + 1] == 0)
931 break;
932 pos++;
934 pos++;
936 sizes[i] = pos;
937 return (pos == size) ? SZ_OK : SZ_ERROR_ARCHIVE;
940 static 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)
952 UInt64 type;
953 UInt32 numUnpackStreams = 0;
954 UInt32 numFiles = 0;
955 CSzFileItem *files = 0;
956 UInt32 numEmptyStreams = 0;
957 UInt32 i;
959 RINOK(SzReadID(sd, &type));
961 if (type == k7zIdArchiveProperties)
963 RINOK(SzReadArchiveProperties(sd));
964 RINOK(SzReadID(sd, &type));
968 if (type == k7zIdMainStreamsInfo)
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));
981 if (type == k7zIdEnd)
982 return SZ_OK;
983 if (type != k7zIdFilesInfo)
984 return SZ_ERROR_ARCHIVE;
986 RINOK(SzReadNumber32(sd, &numFiles));
987 p->db.NumFiles = numFiles;
989 MY_ALLOC(CSzFileItem, files, (size_t)numFiles, allocMain);
991 p->db.Files = files;
992 for (i = 0; i < numFiles; i++)
993 SzFile_Init(files + i);
995 for (;;)
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)
1007 RINOK(SzSkeepDataSize(sd, size));
1009 else
1010 switch((int)type)
1012 case k7zIdName:
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;
1027 case k7zIdEmptyStream:
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;
1036 case k7zIdEmptyFile:
1038 RINOK(SzReadBoolVector(sd, numEmptyStreams, emptyFileVector, allocTemp));
1039 break;
1041 case k7zIdWinAttributes:
1043 RINOK(SzReadBoolVector2(sd, numFiles, lwtVector, allocTemp));
1044 RINOK(SzReadSwitch(sd));
1045 for (i = 0; i < numFiles; i++)
1047 CSzFileItem *f = &files[i];
1048 Byte defined = (*lwtVector)[i];
1049 f->AttribDefined = defined;
1050 f->Attrib = 0;
1051 if (defined)
1053 RINOK(SzReadUInt32(sd, &f->Attrib));
1056 IAlloc_Free(allocTemp, *lwtVector);
1057 *lwtVector = NULL;
1058 break;
1060 case k7zIdMTime:
1062 RINOK(SzReadBoolVector2(sd, numFiles, lwtVector, allocTemp));
1063 RINOK(SzReadSwitch(sd));
1064 for (i = 0; i < numFiles; i++)
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)
1072 RINOK(SzReadUInt32(sd, &f->MTime.Low));
1073 RINOK(SzReadUInt32(sd, &f->MTime.High));
1076 IAlloc_Free(allocTemp, *lwtVector);
1077 *lwtVector = NULL;
1078 break;
1080 default:
1082 RINOK(SzSkeepDataSize(sd, size));
1088 UInt32 emptyFileIndex = 0;
1089 UInt32 sizeIndex = 0;
1090 for (i = 0; i < numFiles; i++)
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)
1100 file->IsDir = 0;
1101 file->Size = (*unpackSizes)[sizeIndex];
1102 file->Crc = (*digests)[sizeIndex];
1103 file->CrcDefined = (Byte)(*digestsDefined)[sizeIndex];
1104 sizeIndex++;
1106 else
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;
1119 return SzArEx_Fill(p, allocMain);
1122 static SRes SzReadHeader(
1123 CSzArEx *p,
1124 CSzData *sd,
1125 ISzAlloc *allocMain,
1126 ISzAlloc *allocTemp)
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;
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)
1159 UInt32 numUnpackStreams = 0;
1160 UInt64 dataStartPos;
1161 CSzFolder *folder;
1162 UInt64 unpackSize;
1163 SRes res;
1165 RINOK(SzReadStreamsInfo(sd, &dataStartPos, p,
1166 &numUnpackStreams, unpackSizes, digestsDefined, digests,
1167 allocTemp, allocTemp));
1169 dataStartPos += baseOffset;
1170 if (p->NumFolders != 1)
1171 return SZ_ERROR_ARCHIVE;
1173 folder = p->Folders;
1174 unpackSize = SzFolder_GetUnpackSize(folder);
1176 RINOK(LookInStream_SeekTo(inStream, dataStartPos));
1178 if (!Buf_Create(outBuffer, (size_t)unpackSize, allocTemp))
1179 return SZ_ERROR_MEM;
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;
1191 static SRes SzReadAndDecodePackedStreams(
1192 ILookInStream *inStream,
1193 CSzData *sd,
1194 CBuf *outBuffer,
1195 UInt64 baseOffset,
1196 ISzAlloc *allocTemp)
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;
1214 static SRes SzArEx_Open2(
1215 CSzArEx *p,
1216 ILookInStream *inStream,
1217 ISzAlloc *allocMain,
1218 ISzAlloc *allocTemp)
1220 Byte header[k7zStartHeaderSize];
1221 Int64 startArcPos;
1222 UInt64 nextHeaderOffset, nextHeaderSize;
1223 size_t nextHeaderSizeT;
1224 UInt32 nextHeaderCRC;
1225 CBuf buffer;
1226 SRes res;
1228 startArcPos = 0;
1229 RINOK(inStream->Seek(inStream, &startArcPos, SZ_SEEK_CUR));
1231 RINOK(LookInStream_Read2(inStream, header, k7zStartHeaderSize, SZ_ERROR_NO_ARCHIVE));
1233 if (!TestSignatureCandidate(header))
1234 return SZ_ERROR_NO_ARCHIVE;
1235 if (header[6] != k7zMajorVersion)
1236 return SZ_ERROR_UNSUPPORTED;
1238 nextHeaderOffset = GetUi64(header + 12);
1239 nextHeaderSize = GetUi64(header + 20);
1240 nextHeaderCRC = GetUi32(header + 28);
1242 p->startPosAfterHeader = startArcPos + k7zStartHeaderSize;
1244 if (CrcCalc(header + 12, 20) != GetUi32(header + 8))
1245 return SZ_ERROR_CRC;
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;
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;
1265 RINOK(LookInStream_SeekTo(inStream, startArcPos + k7zStartHeaderSize + nextHeaderOffset));
1267 if (!Buf_Create(&buffer, nextHeaderSizeT, allocTemp))
1268 return SZ_ERROR_MEM;
1270 res = LookInStream_Read(inStream, buffer.data, nextHeaderSizeT);
1271 if (res == SZ_OK)
1273 res = SZ_ERROR_ARCHIVE;
1274 if (CrcCalc(buffer.data, nextHeaderSizeT) == nextHeaderCRC)
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)
1283 if (type == k7zIdEncodedHeader)
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
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);
1301 if (res == SZ_OK)
1303 if (type == k7zIdHeader)
1304 res = SzReadHeader(p, &sd, allocMain, allocTemp);
1305 else
1306 res = SZ_ERROR_UNSUPPORTED;
1310 Buf_Free(&buffer, allocTemp);
1311 return res;
1314 SRes SzArEx_Open(CSzArEx *p, ILookInStream *inStream, ISzAlloc *allocMain, ISzAlloc *allocTemp)
1316 SRes res = SzArEx_Open2(p, inStream, allocMain, allocTemp);
1317 if (res != SZ_OK)
1318 SzArEx_Free(p, allocMain);
1319 return res;
1322 SRes 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)
1334 UInt32 folderIndex = p->FileIndexToFolderIndexMap[fileIndex];
1335 SRes res = SZ_OK;
1336 *offset = 0;
1337 *outSizeProcessed = 0;
1338 if (folderIndex == (UInt32)-1)
1340 IAlloc_Free(allocMain, *outBuffer);
1341 *blockIndex = folderIndex;
1342 *outBuffer = 0;
1343 *outBufferSize = 0;
1344 return SZ_OK;
1347 if (*outBuffer == 0 || *blockIndex != folderIndex)
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);
1354 if (unpackSize != unpackSizeSpec)
1355 return SZ_ERROR_MEM;
1356 *blockIndex = folderIndex;
1357 IAlloc_Free(allocMain, *outBuffer);
1358 *outBuffer = 0;
1360 RINOK(LookInStream_SeekTo(inStream, startOffset));
1362 if (res == SZ_OK)
1364 *outBufferSize = unpackSize;
1365 if (unpackSize != 0)
1367 *outBuffer = (Byte *)IAlloc_Alloc(allocMain, unpackSize);
1368 if (*outBuffer == 0)
1369 res = SZ_ERROR_MEM;
1371 if (res == SZ_OK)
1373 res = SzFolder_Decode(folder,
1374 p->db.PackSizes + p->FolderStartPackStreamIndex[folderIndex],
1375 inStream, startOffset,
1376 *outBuffer, unpackSize, allocTemp);
1377 if (res == SZ_OK)
1379 if (folder->UnpackCRCDefined)
1381 if (CrcCalc(*outBuffer, unpackSize) != folder->UnpackCRC)
1382 res = SZ_ERROR_CRC;
1388 if (res == SZ_OK)
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;
1401 return res;