• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
SzCoderInfo_Init(CSzCoderInfo * p)17 void SzCoderInfo_Init(CSzCoderInfo *p)
18 {
19   Buf_Init(&p->Props);
20 }
21 
SzCoderInfo_Free(CSzCoderInfo * p,ISzAlloc * alloc)22 void SzCoderInfo_Free(CSzCoderInfo *p, ISzAlloc *alloc)
23 {
24   Buf_Free(&p->Props, alloc);
25   SzCoderInfo_Init(p);
26 }
27 
SzFolder_Init(CSzFolder * p)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 
SzFolder_Free(CSzFolder * p,ISzAlloc * alloc)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 
SzFolder_GetNumOutStreams(CSzFolder * p)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 
SzFolder_FindBindPairForInStream(CSzFolder * p,UInt32 inStreamIndex)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 
SzFolder_FindBindPairForOutStream(CSzFolder * p,UInt32 outStreamIndex)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 
SzFolder_GetUnpackSize(CSzFolder * p)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 
SzFile_Init(CSzFileItem * p)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 
SzAr_Init(CSzAr * p)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 
SzAr_Free(CSzAr * p,ISzAlloc * alloc)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 
SzArEx_Init(CSzArEx * p)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 
SzArEx_Free(CSzArEx * p,ISzAlloc * alloc)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 
SzArEx_Fill(CSzArEx * p,ISzAlloc * alloc)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 
SzArEx_GetFolderStreamPos(const CSzArEx * p,UInt32 folderIndex,UInt32 indexInFolder)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 
SzArEx_GetFolderFullPackSize(const CSzArEx * p,UInt32 folderIndex,UInt64 * resSize)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 
TestSignatureCandidate(Byte * testBytes)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 
SzReadByte(CSzData * sd,Byte * b)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 
SzReadBytes(CSzData * sd,Byte * data,size_t size)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 
SzReadUInt32(CSzData * sd,UInt32 * value)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 
SzReadNumber(CSzData * sd,UInt64 * value)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 
SzReadNumber32(CSzData * sd,UInt32 * value)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 
SzReadID(CSzData * sd,UInt64 * value)383 static SRes SzReadID(CSzData *sd, UInt64 *value)
384 {
385   return SzReadNumber(sd, value);
386 }
387 
SzSkeepDataSize(CSzData * sd,UInt64 size)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 
SzSkeepData(CSzData * sd)397 static SRes SzSkeepData(CSzData *sd)
398 {
399   UInt64 size;
400   RINOK(SzReadNumber(sd, &size));
401   return SzSkeepDataSize(sd, size);
402 }
403 
SzReadArchiveProperties(CSzData * sd)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 
SzWaitAttribute(CSzData * sd,UInt64 attribute)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 
SzReadBoolVector(CSzData * sd,size_t numItems,Byte ** v,ISzAlloc * alloc)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 
SzReadBoolVector2(CSzData * sd,size_t numItems,Byte ** v,ISzAlloc * alloc)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 
SzReadHashDigests(CSzData * sd,size_t numItems,Byte ** digestsDefined,UInt32 ** digests,ISzAlloc * alloc)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 
SzReadPackInfo(CSzData * sd,UInt64 * dataOffset,UInt32 * numPackStreams,UInt64 ** packSizes,Byte ** packCRCsDefined,UInt32 ** packCRCs,ISzAlloc * alloc)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 
SzReadSwitch(CSzData * sd)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 
SzGetNextFolderItem(CSzData * sd,CSzFolder * folder,ISzAlloc * alloc)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 
SzReadUnpackInfo(CSzData * sd,UInt32 * numFolders,CSzFolder ** folders,ISzAlloc * alloc,ISzAlloc * allocTemp)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 
SzReadSubStreamsInfo(CSzData * sd,UInt32 numFolders,CSzFolder * folders,UInt32 * numUnpackStreams,UInt64 ** unpackSizes,Byte ** digestsDefined,UInt32 ** digests,ISzAlloc * allocTemp)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 
SzReadStreamsInfo(CSzData * sd,UInt64 * dataOffset,CSzAr * p,UInt32 * numUnpackStreams,UInt64 ** unpackSizes,Byte ** digestsDefined,UInt32 ** digests,ISzAlloc * alloc,ISzAlloc * allocTemp)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 
SzArEx_GetFileNameUtf16(const CSzArEx * p,size_t fileIndex,UInt16 * dest)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 
SzReadFileNames(const Byte * p,size_t size,UInt32 numFiles,size_t * sizes)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 
SzReadHeader2(CSzArEx * p,CSzData * sd,UInt64 ** unpackSizes,Byte ** digestsDefined,UInt32 ** digests,Byte ** emptyStreamVector,Byte ** emptyFileVector,Byte ** lwtVector,ISzAlloc * allocMain,ISzAlloc * allocTemp)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)
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 
SzReadHeader(CSzArEx * p,CSzData * sd,ISzAlloc * allocMain,ISzAlloc * allocTemp)1122 static 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 
SzReadAndDecodePackedStreams2(ILookInStream * inStream,CSzData * sd,CBuf * outBuffer,UInt64 baseOffset,CSzAr * p,UInt64 ** unpackSizes,Byte ** digestsDefined,UInt32 ** digests,ISzAlloc * allocTemp)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 
SzReadAndDecodePackedStreams(ILookInStream * inStream,CSzData * sd,CBuf * outBuffer,UInt64 baseOffset,ISzAlloc * allocTemp)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 
SzArEx_Open2(CSzArEx * p,ILookInStream * inStream,ISzAlloc * allocMain,ISzAlloc * allocTemp)1214 static 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 
SzArEx_Open(CSzArEx * p,ILookInStream * inStream,ISzAlloc * allocMain,ISzAlloc * allocTemp)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 
SzArEx_Extract(const CSzArEx * p,ILookInStream * inStream,UInt32 fileIndex,UInt32 * blockIndex,Byte ** outBuffer,size_t * outBufferSize,size_t * offset,size_t * outSizeProcessed,ISzAlloc * allocMain,ISzAlloc * allocTemp)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)
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