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