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