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