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