1/* 7zArcIn.c -- 7z Input functions
22014-06-16 : Igor Pavlov : Public domain */
3
4#include "Precomp.h"
5
6#include <string.h>
7
8#include "7z.h"
9#include "7zBuf.h"
10#include "7zCrc.h"
11#include "CpuArch.h"
12
13#define MY_ALLOC(T, p, size, alloc) { if ((size) == 0) p = 0; else \
14  if ((p = (T *)IAlloc_Alloc(alloc, (size) * sizeof(T))) == 0) return SZ_ERROR_MEM; }
15
16#define k7zMajorVersion 0
17
18enum EIdEnum
19{
20  k7zIdEnd,
21  k7zIdHeader,
22  k7zIdArchiveProperties,
23  k7zIdAdditionalStreamsInfo,
24  k7zIdMainStreamsInfo,
25  k7zIdFilesInfo,
26  k7zIdPackInfo,
27  k7zIdUnpackInfo,
28  k7zIdSubStreamsInfo,
29  k7zIdSize,
30  k7zIdCRC,
31  k7zIdFolder,
32  k7zIdCodersUnpackSize,
33  k7zIdNumUnpackStream,
34  k7zIdEmptyStream,
35  k7zIdEmptyFile,
36  k7zIdAnti,
37  k7zIdName,
38  k7zIdCTime,
39  k7zIdATime,
40  k7zIdMTime,
41  k7zIdWinAttrib,
42  k7zIdComment,
43  k7zIdEncodedHeader,
44  k7zIdStartPos,
45  k7zIdDummy
46  // k7zNtSecure,
47  // k7zParent,
48  // k7zIsReal
49};
50
51Byte k7zSignature[k7zSignatureSize] = {'7', 'z', 0xBC, 0xAF, 0x27, 0x1C};
52
53#define NUM_FOLDER_CODERS_MAX 32
54#define NUM_CODER_STREAMS_MAX 32
55
56/*
57static int SzFolder_FindBindPairForInStream(const CSzFolder *p, UInt32 inStreamIndex)
58{
59  UInt32 i;
60  for (i = 0; i < p->NumBindPairs; i++)
61    if (p->BindPairs[i].InIndex == inStreamIndex)
62      return i;
63  return -1;
64}
65*/
66
67#define SzBitUi32s_Init(p) { (p)->Defs = 0; (p)->Vals = 0; }
68
69static SRes SzBitUi32s_Alloc(CSzBitUi32s *p, size_t num, ISzAlloc *alloc)
70{
71  MY_ALLOC(Byte, p->Defs, (num + 7) >> 3, alloc);
72  MY_ALLOC(UInt32, p->Vals, num, alloc);
73  return SZ_OK;
74}
75
76void SzBitUi32s_Free(CSzBitUi32s *p, ISzAlloc *alloc)
77{
78  IAlloc_Free(alloc, p->Defs); p->Defs = 0;
79  IAlloc_Free(alloc, p->Vals); p->Vals = 0;
80}
81
82#define SzBitUi64s_Init(p) { (p)->Defs = 0; (p)->Vals = 0; }
83
84void SzBitUi64s_Free(CSzBitUi64s *p, ISzAlloc *alloc)
85{
86  IAlloc_Free(alloc, p->Defs); p->Defs = 0;
87  IAlloc_Free(alloc, p->Vals); p->Vals = 0;
88}
89
90static void SzAr_Init(CSzAr *p)
91{
92  p->NumPackStreams = 0;
93  p->NumFolders = 0;
94  p->PackPositions = 0;
95  SzBitUi32s_Init(&p->FolderCRCs);
96  // p->Folders = 0;
97  p->FoCodersOffsets = 0;
98  p->FoSizesOffsets = 0;
99  p->FoStartPackStreamIndex = 0;
100
101  p->CodersData = 0;
102  // p->CoderUnpackSizes = 0;
103  p->UnpackSizesData = 0;
104}
105
106static void SzAr_Free(CSzAr *p, ISzAlloc *alloc)
107{
108  IAlloc_Free(alloc, p->UnpackSizesData);
109  IAlloc_Free(alloc, p->CodersData);
110  // IAlloc_Free(alloc, p->CoderUnpackSizes);
111
112  IAlloc_Free(alloc, p->PackPositions);
113
114  // IAlloc_Free(alloc, p->Folders);
115  IAlloc_Free(alloc, p->FoCodersOffsets);
116  IAlloc_Free(alloc, p->FoSizesOffsets);
117  IAlloc_Free(alloc, p->FoStartPackStreamIndex);
118
119  SzBitUi32s_Free(&p->FolderCRCs, alloc);
120
121  SzAr_Init(p);
122}
123
124
125void SzArEx_Init(CSzArEx *p)
126{
127  SzAr_Init(&p->db);
128  p->NumFiles = 0;
129  p->dataPos = 0;
130  // p->Files = 0;
131  p->UnpackPositions = 0;
132  // p->IsEmptyFiles = 0;
133  p->IsDirs = 0;
134  // p->FolderStartPackStreamIndex = 0;
135  // p->PackStreamStartPositions = 0;
136  p->FolderStartFileIndex = 0;
137  p->FileIndexToFolderIndexMap = 0;
138  p->FileNameOffsets = 0;
139  p->FileNames = 0;
140  SzBitUi32s_Init(&p->CRCs);
141  SzBitUi32s_Init(&p->Attribs);
142  // SzBitUi32s_Init(&p->Parents);
143  SzBitUi64s_Init(&p->MTime);
144  SzBitUi64s_Init(&p->CTime);
145}
146
147void SzArEx_Free(CSzArEx *p, ISzAlloc *alloc)
148{
149  // IAlloc_Free(alloc, p->FolderStartPackStreamIndex);
150  // IAlloc_Free(alloc, p->PackStreamStartPositions);
151  IAlloc_Free(alloc, p->FolderStartFileIndex);
152  IAlloc_Free(alloc, p->FileIndexToFolderIndexMap);
153
154  IAlloc_Free(alloc, p->FileNameOffsets);
155  IAlloc_Free(alloc, p->FileNames);
156
157  SzBitUi64s_Free(&p->CTime, alloc);
158  SzBitUi64s_Free(&p->MTime, alloc);
159  SzBitUi32s_Free(&p->CRCs, alloc);
160  // SzBitUi32s_Free(&p->Parents, alloc);
161  SzBitUi32s_Free(&p->Attribs, alloc);
162  IAlloc_Free(alloc, p->IsDirs);
163  // IAlloc_Free(alloc, p->IsEmptyFiles);
164  IAlloc_Free(alloc, p->UnpackPositions);
165  // IAlloc_Free(alloc, p->Files);
166
167  SzAr_Free(&p->db, alloc);
168  SzArEx_Init(p);
169}
170
171static int TestSignatureCandidate(Byte *testBytes)
172{
173  size_t i;
174  for (i = 0; i < k7zSignatureSize; i++)
175    if (testBytes[i] != k7zSignature[i])
176      return 0;
177  return 1;
178}
179
180#define SzData_Clear(p) { (p)->Data = 0; (p)->Size = 0; }
181
182static SRes SzReadByte(CSzData *sd, Byte *b)
183{
184  if (sd->Size == 0)
185    return SZ_ERROR_ARCHIVE;
186  sd->Size--;
187  *b = *sd->Data++;
188  return SZ_OK;
189}
190
191#define SZ_READ_BYTE_SD(_sd_, dest) if ((_sd_)->Size == 0) return SZ_ERROR_ARCHIVE; (_sd_)->Size--; dest = *(_sd_)->Data++;
192#define SZ_READ_BYTE(dest) SZ_READ_BYTE_SD(sd, dest)
193#define SZ_READ_BYTE_2(dest) if (sd.Size == 0) return SZ_ERROR_ARCHIVE; sd.Size--; dest = *sd.Data++;
194
195#define SKIP_DATA(sd, size) { sd->Size -= (size_t)(size); sd->Data += (size_t)(size); }
196#define SKIP_DATA2(sd, size) { sd.Size -= (size_t)(size); sd.Data += (size_t)(size); }
197
198#define SZ_READ_32(dest) if (sd.Size < 4) return SZ_ERROR_ARCHIVE; \
199   dest = GetUi32(sd.Data); SKIP_DATA2(sd, 4);
200
201static MY_NO_INLINE SRes ReadNumber(CSzData *sd, UInt64 *value)
202{
203  Byte firstByte, mask;
204  unsigned i;
205  UInt32 v;
206
207  SZ_READ_BYTE(firstByte);
208  if ((firstByte & 0x80) == 0)
209  {
210    *value = firstByte;
211    return SZ_OK;
212  }
213  SZ_READ_BYTE(v);
214  if ((firstByte & 0x40) == 0)
215  {
216    *value = (((UInt32)firstByte & 0x3F) << 8) | v;
217    return SZ_OK;
218  }
219  SZ_READ_BYTE(mask);
220  *value = v | ((UInt32)mask << 8);
221  mask = 0x20;
222  for (i = 2; i < 8; i++)
223  {
224    Byte b;
225    if ((firstByte & mask) == 0)
226    {
227      UInt64 highPart = firstByte & (mask - 1);
228      *value |= (highPart << (8 * i));
229      return SZ_OK;
230    }
231    SZ_READ_BYTE(b);
232    *value |= ((UInt64)b << (8 * i));
233    mask >>= 1;
234  }
235  return SZ_OK;
236}
237
238/*
239static MY_NO_INLINE const Byte *SzReadNumbers(const Byte *data, const Byte *dataLim, UInt64 *values, UInt32 num)
240{
241  for (; num != 0; num--)
242  {
243    Byte firstByte;
244    Byte mask;
245
246    unsigned i;
247    UInt32 v;
248    UInt64 value;
249
250    if (data == dataLim)
251      return NULL;
252    firstByte = *data++;
253
254    if ((firstByte & 0x80) == 0)
255    {
256      *values++ = firstByte;
257      continue;
258    }
259    if (data == dataLim)
260      return NULL;
261    v = *data++;
262    if ((firstByte & 0x40) == 0)
263    {
264      *values++ = (((UInt32)firstByte & 0x3F) << 8) | v;
265      continue;
266    }
267    if (data == dataLim)
268      return NULL;
269    value = v | ((UInt32)*data++ << 8);
270    mask = 0x20;
271    for (i = 2; i < 8; i++)
272    {
273      if ((firstByte & mask) == 0)
274      {
275        UInt64 highPart = firstByte & (mask - 1);
276        value |= (highPart << (8 * i));
277        break;
278      }
279      if (data == dataLim)
280        return NULL;
281      value |= ((UInt64)*data++ << (8 * i));
282      mask >>= 1;
283    }
284    *values++ = value;
285  }
286  return data;
287}
288*/
289
290static MY_NO_INLINE SRes SzReadNumber32(CSzData *sd, UInt32 *value)
291{
292  Byte firstByte;
293  UInt64 value64;
294  if (sd->Size == 0)
295    return SZ_ERROR_ARCHIVE;
296  firstByte = *sd->Data;
297  if ((firstByte & 0x80) == 0)
298  {
299    *value = firstByte;
300    sd->Data++;
301    sd->Size--;
302    return SZ_OK;
303  }
304  RINOK(ReadNumber(sd, &value64));
305  if (value64 >= (UInt32)0x80000000 - 1)
306    return SZ_ERROR_UNSUPPORTED;
307  if (value64 >= ((UInt64)(1) << ((sizeof(size_t) - 1) * 8 + 4)))
308    return SZ_ERROR_UNSUPPORTED;
309  *value = (UInt32)value64;
310  return SZ_OK;
311}
312
313#define ReadID(sd, value) ReadNumber(sd, value)
314
315static SRes SkipData(CSzData *sd)
316{
317  UInt64 size;
318  RINOK(ReadNumber(sd, &size));
319  if (size > sd->Size)
320    return SZ_ERROR_ARCHIVE;
321  SKIP_DATA(sd, size);
322  return SZ_OK;
323}
324
325static SRes WaitId(CSzData *sd, UInt64 id)
326{
327  for (;;)
328  {
329    UInt64 type;
330    RINOK(ReadID(sd, &type));
331    if (type == id)
332      return SZ_OK;
333    if (type == k7zIdEnd)
334      return SZ_ERROR_ARCHIVE;
335    RINOK(SkipData(sd));
336  }
337}
338
339static SRes RememberBitVector(CSzData *sd, UInt32 numItems, const Byte **v)
340{
341  UInt32 numBytes = (numItems + 7) >> 3;
342  if (numBytes > sd->Size)
343    return SZ_ERROR_ARCHIVE;
344  *v = sd->Data;
345  SKIP_DATA(sd, numBytes);
346  return SZ_OK;
347}
348
349static UInt32 CountDefinedBits(const Byte *bits, UInt32 numItems)
350{
351  Byte b = 0;
352  unsigned m = 0;
353  UInt32 sum = 0;
354  for (; numItems != 0; numItems--)
355  {
356    if (m == 0)
357    {
358      b = *bits++;
359      m = 8;
360    }
361    m--;
362    sum += ((b >> m) & 1);
363  }
364  return sum ;
365}
366
367static MY_NO_INLINE SRes ReadBitVector(CSzData *sd, UInt32 numItems, Byte **v, ISzAlloc *alloc)
368{
369  Byte allAreDefined;
370  UInt32 i;
371  Byte *v2;
372  UInt32 numBytes = (numItems + 7) >> 3;
373  RINOK(SzReadByte(sd, &allAreDefined));
374  if (allAreDefined == 0)
375  {
376    if (numBytes > sd->Size)
377      return SZ_ERROR_ARCHIVE;
378    MY_ALLOC(Byte, *v, numBytes, alloc);
379    memcpy(*v, sd->Data, numBytes);
380    SKIP_DATA(sd, numBytes);
381    return SZ_OK;
382  }
383  MY_ALLOC(Byte, *v, numBytes, alloc);
384  v2 = *v;
385  for (i = 0; i < numBytes; i++)
386    v2[i] = 0xFF;
387  {
388    unsigned numBits = (unsigned)numItems & 7;
389    if (numBits != 0)
390      v2[numBytes - 1] = (Byte)((((UInt32)1 << numBits) - 1) << (8 - numBits));
391  }
392  return SZ_OK;
393}
394
395static MY_NO_INLINE SRes ReadUi32s(CSzData *sd2, UInt32 numItems, CSzBitUi32s *crcs, ISzAlloc *alloc)
396{
397  UInt32 i;
398  CSzData sd;
399  UInt32 *vals;
400  const Byte *defs;
401  MY_ALLOC(UInt32, crcs->Vals, numItems, alloc);
402  sd = *sd2;
403  defs = crcs->Defs;
404  vals = crcs->Vals;
405  for (i = 0; i < numItems; i++)
406    if (SzBitArray_Check(defs, i))
407    {
408      SZ_READ_32(vals[i]);
409    }
410    else
411      vals[i] = 0;
412  *sd2 = sd;
413  return SZ_OK;
414}
415
416static SRes ReadBitUi32s(CSzData *sd, UInt32 numItems, CSzBitUi32s *crcs, ISzAlloc *alloc)
417{
418  SzBitUi32s_Free(crcs, alloc);
419  RINOK(ReadBitVector(sd, numItems, &crcs->Defs, alloc));
420  return ReadUi32s(sd, numItems, crcs, alloc);
421}
422
423static SRes SkipBitUi32s(CSzData *sd, UInt32 numItems)
424{
425  Byte allAreDefined;
426  UInt32 numDefined = numItems;
427  RINOK(SzReadByte(sd, &allAreDefined));
428  if (!allAreDefined)
429  {
430    size_t numBytes = (numItems + 7) >> 3;
431    if (numBytes > sd->Size)
432      return SZ_ERROR_ARCHIVE;
433    numDefined = CountDefinedBits(sd->Data, numItems);
434    SKIP_DATA(sd, numBytes);
435  }
436  if (numDefined > (sd->Size >> 2))
437    return SZ_ERROR_ARCHIVE;
438  SKIP_DATA(sd, (size_t)numDefined * 4);
439  return SZ_OK;
440}
441
442static SRes ReadPackInfo(CSzAr *p, CSzData *sd, ISzAlloc *alloc)
443{
444  RINOK(SzReadNumber32(sd, &p->NumPackStreams));
445
446  RINOK(WaitId(sd, k7zIdSize));
447  MY_ALLOC(UInt64, p->PackPositions, (size_t)p->NumPackStreams + 1, alloc);
448  {
449    UInt64 sum = 0;
450    UInt32 i;
451    UInt32 numPackStreams = p->NumPackStreams;
452    for (i = 0; i < numPackStreams; i++)
453    {
454      UInt64 packSize;
455      p->PackPositions[i] = sum;
456      RINOK(ReadNumber(sd, &packSize));
457      sum += packSize;
458      if (sum < packSize)
459        return SZ_ERROR_ARCHIVE;
460    }
461    p->PackPositions[i] = sum;
462  }
463
464  for (;;)
465  {
466    UInt64 type;
467    RINOK(ReadID(sd, &type));
468    if (type == k7zIdEnd)
469      return SZ_OK;
470    if (type == k7zIdCRC)
471    {
472      /* CRC of packed streams is unused now */
473      RINOK(SkipBitUi32s(sd, p->NumPackStreams));
474      continue;
475    }
476    RINOK(SkipData(sd));
477  }
478}
479
480/*
481static SRes SzReadSwitch(CSzData *sd)
482{
483  Byte external;
484  RINOK(SzReadByte(sd, &external));
485  return (external == 0) ? SZ_OK: SZ_ERROR_UNSUPPORTED;
486}
487*/
488
489#define SZ_NUM_IN_STREAMS_IN_FOLDER_MAX 16
490
491SRes SzGetNextFolderItem(CSzFolder *f, CSzData *sd, CSzData *sdSizes)
492{
493  UInt32 numCoders, numBindPairs, numPackStreams, i;
494  UInt32 numInStreams = 0, numOutStreams = 0;
495  const Byte *dataStart = sd->Data;
496  Byte inStreamUsed[SZ_NUM_IN_STREAMS_IN_FOLDER_MAX];
497
498  RINOK(SzReadNumber32(sd, &numCoders));
499  if (numCoders > SZ_NUM_CODERS_IN_FOLDER_MAX)
500    return SZ_ERROR_UNSUPPORTED;
501  f->NumCoders = numCoders;
502
503  for (i = 0; i < numCoders; i++)
504  {
505    Byte mainByte;
506    CSzCoderInfo *coder = f->Coders + i;
507    unsigned idSize, j;
508    UInt64 id;
509    RINOK(SzReadByte(sd, &mainByte));
510    if ((mainByte & 0xC0) != 0)
511      return SZ_ERROR_UNSUPPORTED;
512    idSize = (unsigned)(mainByte & 0xF);
513    if (idSize > sizeof(id))
514      return SZ_ERROR_UNSUPPORTED;
515    if (idSize > sd->Size)
516      return SZ_ERROR_ARCHIVE;
517    id = 0;
518    for (j = 0; j < idSize; j++)
519    {
520      id = ((id << 8) | *sd->Data);
521      sd->Data++;
522      sd->Size--;
523    }
524    if (id > (UInt32)0xFFFFFFFF)
525      return SZ_ERROR_UNSUPPORTED;
526    coder->MethodID = (UInt32)id;
527
528    coder->NumInStreams = 1;
529    coder->NumOutStreams = 1;
530    coder->PropsOffset = 0;
531    coder->PropsSize = 0;
532
533    if ((mainByte & 0x10) != 0)
534    {
535      UInt32 numStreams;
536      RINOK(SzReadNumber32(sd, &numStreams));
537      if (numStreams > NUM_CODER_STREAMS_MAX)
538        return SZ_ERROR_UNSUPPORTED;
539      coder->NumInStreams = (Byte)numStreams;
540      RINOK(SzReadNumber32(sd, &numStreams));
541      if (numStreams > NUM_CODER_STREAMS_MAX)
542        return SZ_ERROR_UNSUPPORTED;
543      coder->NumOutStreams = (Byte)numStreams;
544    }
545    if ((mainByte & 0x20) != 0)
546    {
547      UInt32 propsSize = 0;
548      RINOK(SzReadNumber32(sd, &propsSize));
549      if (propsSize >= 0x40)
550        return SZ_ERROR_UNSUPPORTED;
551      if (propsSize > sd->Size)
552        return SZ_ERROR_ARCHIVE;
553      coder->PropsOffset = sd->Data - dataStart;
554      coder->PropsSize = (Byte)propsSize;
555      sd->Data += (size_t)propsSize;
556      sd->Size -= (size_t)propsSize;
557    }
558    numInStreams += coder->NumInStreams;
559    numOutStreams += coder->NumOutStreams;
560  }
561
562  if (numOutStreams == 0)
563    return SZ_ERROR_UNSUPPORTED;
564
565  f->NumBindPairs = numBindPairs = numOutStreams - 1;
566  if (numInStreams < numBindPairs)
567    return SZ_ERROR_ARCHIVE;
568  if (numInStreams > SZ_NUM_IN_STREAMS_IN_FOLDER_MAX)
569    return SZ_ERROR_UNSUPPORTED;
570  f->MainOutStream = 0;
571  f->NumPackStreams = numPackStreams = numInStreams - numBindPairs;
572  if (numPackStreams > SZ_NUM_PACK_STREAMS_IN_FOLDER_MAX)
573    return SZ_ERROR_UNSUPPORTED;
574  for (i = 0; i < numInStreams; i++)
575    inStreamUsed[i] = False;
576  if (numBindPairs != 0)
577  {
578    Byte outStreamUsed[SZ_NUM_CODERS_OUT_STREAMS_IN_FOLDER_MAX];
579
580    if (numBindPairs > SZ_NUM_BINDS_IN_FOLDER_MAX)
581      return SZ_ERROR_UNSUPPORTED;
582
583    for (i = 0; i < numOutStreams; i++)
584      outStreamUsed[i] = False;
585
586    for (i = 0; i < numBindPairs; i++)
587    {
588      CSzBindPair *bp = f->BindPairs + i;
589      RINOK(SzReadNumber32(sd, &bp->InIndex));
590      if (bp->InIndex >= numInStreams)
591        return SZ_ERROR_ARCHIVE;
592      inStreamUsed[bp->InIndex] = True;
593      RINOK(SzReadNumber32(sd, &bp->OutIndex));
594      if (bp->OutIndex >= numInStreams)
595        return SZ_ERROR_ARCHIVE;
596      outStreamUsed[bp->OutIndex] = True;
597    }
598    for (i = 0; i < numOutStreams; i++)
599      if (!outStreamUsed[i])
600      {
601        f->MainOutStream = i;
602        break;
603      }
604    if (i == numOutStreams)
605      return SZ_ERROR_ARCHIVE;
606  }
607
608  if (numPackStreams == 1)
609  {
610    for (i = 0; i < numInStreams; i++)
611      if (!inStreamUsed[i])
612        break;
613    if (i == numInStreams)
614      return SZ_ERROR_ARCHIVE;
615    f->PackStreams[0] = i;
616  }
617  else
618    for (i = 0; i < numPackStreams; i++)
619    {
620      RINOK(SzReadNumber32(sd, f->PackStreams + i));
621    }
622
623  for (i = 0; i < numOutStreams; i++)
624  {
625    RINOK(ReadNumber(sdSizes, f->CodersUnpackSizes + i));
626  }
627
628  return SZ_OK;
629}
630
631static MY_NO_INLINE SRes SkipNumbers(CSzData *sd2, UInt32 num)
632{
633  CSzData sd;
634  sd = *sd2;
635  for (; num != 0; num--)
636  {
637    Byte firstByte, mask;
638    unsigned i;
639    SZ_READ_BYTE_2(firstByte);
640    if ((firstByte & 0x80) == 0)
641      continue;
642    if ((firstByte & 0x40) == 0)
643    {
644      if (sd.Size == 0)
645        return SZ_ERROR_ARCHIVE;
646      sd.Size--;
647      sd.Data++;
648      continue;
649    }
650    mask = 0x20;
651    for (i = 2; i < 8 && (firstByte & mask) != 0; i++)
652      mask >>= 1;
653    if (i > sd.Size)
654      return SZ_ERROR_ARCHIVE;
655    SKIP_DATA2(sd, i);
656  }
657  *sd2 = sd;
658  return SZ_OK;
659}
660
661#define k_InStreamUsed_MAX 64
662#define k_OutStreamUsed_MAX 64
663
664static SRes ReadUnpackInfo(CSzAr *p,
665    CSzData *sd2,
666    UInt32 numFoldersMax, const CBuf *tempBufs, UInt32 numTempBufs,
667    ISzAlloc *alloc)
668{
669  CSzData sd;
670  Byte inStreamUsed[k_InStreamUsed_MAX];
671  Byte outStreamUsed[k_OutStreamUsed_MAX];
672  UInt32 fo, numFolders, numCodersOutStreams, packStreamIndex;
673  const Byte *startBufPtr;
674  Byte external;
675
676  RINOK(WaitId(sd2, k7zIdFolder));
677  RINOK(SzReadNumber32(sd2, &numFolders));
678  if (p->NumFolders > numFoldersMax)
679    return SZ_ERROR_UNSUPPORTED;
680  p->NumFolders = numFolders;
681
682  SZ_READ_BYTE_SD(sd2, external);
683  if (external == 0)
684    sd = *sd2;
685  else
686  {
687    UInt32 index;
688    SzReadNumber32(sd2, &index);
689    if (index >= numTempBufs)
690      return SZ_ERROR_ARCHIVE;
691    sd.Data = tempBufs[index].data;
692    sd.Size = tempBufs[index].size;
693  }
694
695  MY_ALLOC(size_t, p->FoCodersOffsets, (size_t)numFolders + 1, alloc);
696  MY_ALLOC(size_t, p->FoSizesOffsets, (size_t)numFolders + 1, alloc);
697  MY_ALLOC(UInt32, p->FoStartPackStreamIndex, (size_t)numFolders + 1, alloc);
698
699  startBufPtr = sd.Data;
700
701  packStreamIndex = 0;
702  numCodersOutStreams = 0;
703
704  for (fo = 0; fo < numFolders; fo++)
705  {
706    UInt32 numCoders, ci, numInStreams = 0, numOutStreams = 0;
707
708    p->FoCodersOffsets[fo] = sd.Data - startBufPtr;
709    RINOK(SzReadNumber32(&sd, &numCoders));
710    if (numCoders > NUM_FOLDER_CODERS_MAX)
711      return SZ_ERROR_UNSUPPORTED;
712
713    for (ci = 0; ci < numCoders; ci++)
714    {
715      Byte mainByte;
716      unsigned idSize;
717      UInt32 coderInStreams, coderOutStreams;
718
719      SZ_READ_BYTE_2(mainByte);
720      if ((mainByte & 0xC0) != 0)
721        return SZ_ERROR_UNSUPPORTED;
722      idSize = (mainByte & 0xF);
723      if (idSize > 8)
724        return SZ_ERROR_UNSUPPORTED;
725      if (idSize > sd.Size)
726        return SZ_ERROR_ARCHIVE;
727      SKIP_DATA2(sd, idSize);
728
729      coderInStreams = 1;
730      coderOutStreams = 1;
731      if ((mainByte & 0x10) != 0)
732      {
733        RINOK(SzReadNumber32(&sd, &coderInStreams));
734        RINOK(SzReadNumber32(&sd, &coderOutStreams));
735        if (coderInStreams > NUM_CODER_STREAMS_MAX ||
736            coderOutStreams > NUM_CODER_STREAMS_MAX)
737          return SZ_ERROR_UNSUPPORTED;
738      }
739      numInStreams += coderInStreams;
740      numOutStreams += coderOutStreams;
741      if ((mainByte & 0x20) != 0)
742      {
743        UInt32 propsSize;
744        RINOK(SzReadNumber32(&sd, &propsSize));
745        if (propsSize > sd.Size)
746          return SZ_ERROR_ARCHIVE;
747        SKIP_DATA2(sd, propsSize);
748      }
749    }
750
751    {
752      UInt32 indexOfMainStream = 0;
753      UInt32 numPackStreams = 1;
754      if (numOutStreams != 1 || numInStreams != 1)
755      {
756        UInt32 i;
757        UInt32 numBindPairs = numOutStreams - 1;
758        if (numOutStreams == 0 || numInStreams < numBindPairs)
759          return SZ_ERROR_ARCHIVE;
760
761        if (numInStreams > k_InStreamUsed_MAX ||
762            numOutStreams > k_OutStreamUsed_MAX)
763          return SZ_ERROR_UNSUPPORTED;
764
765        for (i = 0; i < numInStreams; i++)
766          inStreamUsed[i] = False;
767        for (i = 0; i < numOutStreams; i++)
768          outStreamUsed[i] = False;
769
770        for (i = 0; i < numBindPairs; i++)
771        {
772          UInt32 index;
773          RINOK(SzReadNumber32(&sd, &index));
774          if (index >= numInStreams || inStreamUsed[index])
775            return SZ_ERROR_ARCHIVE;
776          inStreamUsed[index] = True;
777          RINOK(SzReadNumber32(&sd, &index));
778          if (index >= numInStreams || outStreamUsed[index])
779            return SZ_ERROR_ARCHIVE;
780          outStreamUsed[index] = True;
781        }
782
783        numPackStreams = numInStreams - numBindPairs;
784
785        if (numPackStreams != 1)
786          for (i = 0; i < numPackStreams; i++)
787          {
788            UInt32 temp;
789            RINOK(SzReadNumber32(&sd, &temp));
790            if (temp >= numInStreams)
791              return SZ_ERROR_ARCHIVE;
792          }
793
794        for (i = 0; i < numOutStreams; i++)
795          if (!outStreamUsed[i])
796          {
797            indexOfMainStream = i;
798            break;
799          }
800
801        if (i == numOutStreams)
802          return SZ_ERROR_ARCHIVE;
803      }
804      p->FoStartPackStreamIndex[fo] = packStreamIndex;
805      p->FoSizesOffsets[fo] = (numOutStreams << 8) | indexOfMainStream;
806      numCodersOutStreams += numOutStreams;
807      if (numCodersOutStreams < numOutStreams)
808        return SZ_ERROR_UNSUPPORTED;
809      packStreamIndex += numPackStreams;
810      if (packStreamIndex < numPackStreams)
811        return SZ_ERROR_UNSUPPORTED;
812      if (packStreamIndex > p->NumPackStreams)
813        return SZ_ERROR_ARCHIVE;
814    }
815  }
816
817  {
818    size_t dataSize = sd.Data - startBufPtr;
819    p->FoStartPackStreamIndex[fo] = packStreamIndex;
820    p->FoCodersOffsets[fo] = dataSize;
821    MY_ALLOC(Byte, p->CodersData, dataSize, alloc);
822    memcpy(p->CodersData, startBufPtr, dataSize);
823  }
824
825  if (external != 0)
826  {
827    if (sd.Size != 0)
828      return SZ_ERROR_ARCHIVE;
829    sd = *sd2;
830  }
831
832  RINOK(WaitId(&sd, k7zIdCodersUnpackSize));
833
834  // MY_ALLOC(UInt64, p->CoderUnpackSizes, (size_t)numCodersOutStreams, alloc);
835  {
836    size_t dataSize = sd.Size;
837    /*
838    UInt32 i;
839    for (i = 0; i < numCodersOutStreams; i++)
840    {
841    RINOK(ReadNumber(&sd, p->CoderUnpackSizes + i));
842    }
843    */
844    RINOK(SkipNumbers(&sd, numCodersOutStreams));
845    dataSize -= sd.Size;
846    MY_ALLOC(Byte, p->UnpackSizesData, dataSize, alloc);
847    memcpy(p->UnpackSizesData, sd.Data - dataSize, dataSize);
848    p->UnpackSizesDataSize = dataSize;
849    /*
850    const Byte *data = SzReadNumbers(sd.Data, sd.Data + sd.Size, p->CoderUnpackSizes, numCodersOutStreams);
851    if (data == NULL)
852    return SZ_ERROR_ARCHIVE;
853    sd.Size = sd.Data + sd.Size - data;
854    sd.Data = data;
855    */
856  }
857
858  for (;;)
859  {
860    UInt64 type;
861    RINOK(ReadID(&sd, &type));
862    if (type == k7zIdEnd)
863    {
864      *sd2 = sd;
865      return SZ_OK;
866    }
867    if (type == k7zIdCRC)
868    {
869      RINOK(ReadBitUi32s(&sd, numFolders, &p->FolderCRCs, alloc));
870      continue;
871    }
872    RINOK(SkipData(&sd));
873  }
874}
875
876typedef struct
877{
878  UInt32 NumTotalSubStreams;
879  UInt32 NumSubDigests;
880  CSzData sdNumSubStreams;
881  CSzData sdSizes;
882  CSzData sdCRCs;
883} CSubStreamInfo;
884
885#define SzUi32IndexMax (((UInt32)1 << 31) - 2)
886
887static SRes ReadSubStreamsInfo(CSzAr *p, CSzData *sd, CSubStreamInfo *ssi)
888{
889  UInt64 type = 0;
890  UInt32 i;
891  UInt32 numSubDigests = 0;
892  UInt32 numFolders = p->NumFolders;
893  UInt32 numUnpackStreams = numFolders;
894  UInt32 numUnpackSizesInData = 0;
895
896  for (;;)
897  {
898    RINOK(ReadID(sd, &type));
899    if (type == k7zIdNumUnpackStream)
900    {
901      ssi->sdNumSubStreams.Data = sd->Data;
902      numUnpackStreams = 0;
903      numSubDigests = 0;
904      for (i = 0; i < numFolders; i++)
905      {
906        UInt32 numStreams;
907        RINOK(SzReadNumber32(sd, &numStreams));
908        if (numUnpackStreams > numUnpackStreams + numStreams)
909          return SZ_ERROR_UNSUPPORTED;
910        numUnpackStreams += numStreams;
911        if (numStreams != 0)
912          numUnpackSizesInData += (numStreams - 1);
913        if (numStreams != 1 || !SzBitWithVals_Check(&p->FolderCRCs, i))
914          numSubDigests += numStreams;
915      }
916      ssi->sdNumSubStreams.Size = sd->Data - ssi->sdNumSubStreams.Data;
917      continue;
918    }
919    if (type == k7zIdCRC || type == k7zIdSize || type == k7zIdEnd)
920      break;
921    RINOK(SkipData(sd));
922  }
923
924  if (!ssi->sdNumSubStreams.Data)
925  {
926    numSubDigests = numFolders;
927    if (p->FolderCRCs.Defs)
928      numSubDigests = numFolders - CountDefinedBits(p->FolderCRCs.Defs, numFolders);
929  }
930
931  ssi->NumTotalSubStreams = numUnpackStreams;
932  ssi->NumSubDigests = numSubDigests;
933
934  if (type == k7zIdSize)
935  {
936    ssi->sdSizes.Data = sd->Data;
937    RINOK(SkipNumbers(sd, numUnpackSizesInData));
938    ssi->sdSizes.Size = sd->Data - ssi->sdSizes.Data;
939    RINOK(ReadID(sd, &type));
940  }
941
942  for (;;)
943  {
944    if (type == k7zIdEnd)
945      return SZ_OK;
946    if (type == k7zIdCRC)
947    {
948      ssi->sdCRCs.Data = sd->Data;
949      RINOK(SkipBitUi32s(sd, numSubDigests));
950      ssi->sdCRCs.Size = sd->Data - ssi->sdCRCs.Data;
951    }
952    else
953    {
954      RINOK(SkipData(sd));
955    }
956    RINOK(ReadID(sd, &type));
957  }
958}
959
960static SRes SzReadStreamsInfo(CSzAr *p,
961    CSzData *sd,
962    UInt32 numFoldersMax, const CBuf *tempBufs, UInt32 numTempBufs,
963    UInt64 *dataOffset,
964    CSubStreamInfo *ssi,
965    ISzAlloc *alloc)
966{
967  UInt64 type;
968
969  SzData_Clear(&ssi->sdSizes);
970  SzData_Clear(&ssi->sdCRCs);
971  SzData_Clear(&ssi->sdNumSubStreams);
972
973  *dataOffset = 0;
974  RINOK(ReadID(sd, &type));
975  if (type == k7zIdPackInfo)
976  {
977    RINOK(ReadNumber(sd, dataOffset));
978    RINOK(ReadPackInfo(p, sd, alloc));
979    RINOK(ReadID(sd, &type));
980  }
981  if (type == k7zIdUnpackInfo)
982  {
983    RINOK(ReadUnpackInfo(p, sd, numFoldersMax, tempBufs, numTempBufs, alloc));
984    RINOK(ReadID(sd, &type));
985  }
986  if (type == k7zIdSubStreamsInfo)
987  {
988    RINOK(ReadSubStreamsInfo(p, sd, ssi));
989    RINOK(ReadID(sd, &type));
990  }
991  else
992  {
993    ssi->NumTotalSubStreams = p->NumFolders;
994    // ssi->NumSubDigests = 0;
995  }
996
997  return (type == k7zIdEnd ? SZ_OK : SZ_ERROR_UNSUPPORTED);
998}
999
1000static SRes SzReadAndDecodePackedStreams(
1001    ILookInStream *inStream,
1002    CSzData *sd,
1003    CBuf *tempBufs,
1004    UInt32 numFoldersMax,
1005    UInt64 baseOffset,
1006    CSzAr *p,
1007    ISzAlloc *allocTemp)
1008{
1009  UInt64 dataStartPos;
1010  UInt32 fo;
1011  CSubStreamInfo ssi;
1012  CSzData sdCodersUnpSizes;
1013
1014  RINOK(SzReadStreamsInfo(p, sd, numFoldersMax, NULL, 0, &dataStartPos, &ssi, allocTemp));
1015
1016  dataStartPos += baseOffset;
1017  if (p->NumFolders == 0)
1018    return SZ_ERROR_ARCHIVE;
1019
1020  sdCodersUnpSizes.Data = p->UnpackSizesData;
1021  sdCodersUnpSizes.Size = p->UnpackSizesDataSize;
1022  for (fo = 0; fo < p->NumFolders; fo++)
1023    Buf_Init(tempBufs + fo);
1024  for (fo = 0; fo < p->NumFolders; fo++)
1025  {
1026    CBuf *tempBuf = tempBufs + fo;
1027    // folder = p->Folders;
1028    // unpackSize = SzAr_GetFolderUnpackSize(p, 0);
1029    UInt32 mix = (UInt32)p->FoSizesOffsets[fo];
1030    UInt32 mainIndex = mix & 0xFF;
1031    UInt32 numOutStreams = mix >> 8;
1032    UInt32 si;
1033    UInt64 unpackSize = 0;
1034    p->FoSizesOffsets[fo] = sdCodersUnpSizes.Data - p->UnpackSizesData;
1035    for (si = 0; si < numOutStreams; si++)
1036    {
1037      UInt64 curSize;
1038      RINOK(ReadNumber(&sdCodersUnpSizes, &curSize));
1039      if (si == mainIndex)
1040      {
1041        unpackSize = curSize;
1042        break;
1043      }
1044    }
1045    if (si == numOutStreams)
1046      return SZ_ERROR_FAIL;
1047    if ((size_t)unpackSize != unpackSize)
1048      return SZ_ERROR_MEM;
1049    if (!Buf_Create(tempBuf, (size_t)unpackSize, allocTemp))
1050      return SZ_ERROR_MEM;
1051  }
1052  p->FoSizesOffsets[fo] = sdCodersUnpSizes.Data - p->UnpackSizesData;
1053
1054  for (fo = 0; fo < p->NumFolders; fo++)
1055  {
1056    const CBuf *tempBuf = tempBufs + fo;
1057    RINOK(LookInStream_SeekTo(inStream, dataStartPos));
1058    RINOK(SzAr_DecodeFolder(p, fo, inStream, dataStartPos, tempBuf->data, tempBuf->size, allocTemp));
1059    if (SzBitWithVals_Check(&p->FolderCRCs, fo))
1060      if (CrcCalc(tempBuf->data, tempBuf->size) != p->FolderCRCs.Vals[fo])
1061        return SZ_ERROR_CRC;
1062  }
1063  return SZ_OK;
1064}
1065
1066static SRes SzReadFileNames(const Byte *data, size_t size, UInt32 numFiles, size_t *offsets)
1067{
1068  size_t pos = 0;
1069  *offsets++ = 0;
1070  if (numFiles == 0)
1071    return (size == 0) ? SZ_OK : SZ_ERROR_ARCHIVE;
1072  if (data[size - 2] != 0 || data[size - 1] != 0)
1073    return SZ_ERROR_ARCHIVE;
1074  do
1075  {
1076    const Byte *p;
1077    if (pos == size)
1078      return SZ_ERROR_ARCHIVE;
1079    for (p = data + pos;
1080      #ifdef _WIN32
1081      *(const UInt16 *)p != 0
1082      #else
1083      p[0] != 0 || p[1] != 0
1084      #endif
1085      ; p += 2);
1086    pos = p - data + 2;
1087    *offsets++ = (pos >> 1);
1088  }
1089  while (--numFiles);
1090  return (pos == size) ? SZ_OK : SZ_ERROR_ARCHIVE;
1091}
1092
1093static MY_NO_INLINE SRes ReadTime(CSzBitUi64s *p, UInt32 num,
1094    CSzData *sd2,
1095    const CBuf *tempBufs, UInt32 numTempBufs,
1096    ISzAlloc *alloc)
1097{
1098  CSzData sd;
1099  UInt32 i;
1100  CNtfsFileTime *vals;
1101  Byte *defs;
1102  Byte external;
1103  RINOK(ReadBitVector(sd2, num, &p->Defs, alloc));
1104  RINOK(SzReadByte(sd2, &external));
1105  if (external == 0)
1106    sd = *sd2;
1107  else
1108  {
1109    UInt32 index;
1110    SzReadNumber32(sd2, &index);
1111    if (index >= numTempBufs)
1112      return SZ_ERROR_ARCHIVE;
1113    sd.Data = tempBufs[index].data;
1114    sd.Size = tempBufs[index].size;
1115  }
1116  MY_ALLOC(CNtfsFileTime, p->Vals, num, alloc);
1117  vals = p->Vals;
1118  defs = p->Defs;
1119  for (i = 0; i < num; i++)
1120    if (SzBitArray_Check(defs, i))
1121    {
1122      if (sd.Size < 8)
1123        return SZ_ERROR_ARCHIVE;
1124      vals[i].Low = GetUi32(sd.Data);
1125      vals[i].High = GetUi32(sd.Data + 4);
1126      SKIP_DATA2(sd, 8);
1127    }
1128    else
1129      vals[i].High = vals[i].Low = 0;
1130  if (external == 0)
1131    *sd2 = sd;
1132  return SZ_OK;
1133}
1134
1135#define NUM_ADDITIONAL_STREAMS_MAX 8
1136
1137static SRes SzReadHeader2(
1138    CSzArEx *p,   /* allocMain */
1139    CSzData *sd,
1140    // Byte **emptyStreamVector, /* allocTemp */
1141    // Byte **emptyFileVector,   /* allocTemp */
1142    // Byte **lwtVector,         /* allocTemp */
1143    ILookInStream *inStream,
1144    CBuf *tempBufs,
1145    UInt32 *numTempBufs,
1146    ISzAlloc *allocMain,
1147    ISzAlloc *allocTemp
1148    )
1149{
1150  UInt64 type;
1151  UInt32 numFiles = 0;
1152  UInt32 numEmptyStreams = 0;
1153  UInt32 i;
1154  CSubStreamInfo ssi;
1155  const Byte *emptyStreams = 0;
1156  const Byte *emptyFiles = 0;
1157
1158  SzData_Clear(&ssi.sdSizes);
1159  SzData_Clear(&ssi.sdCRCs);
1160  SzData_Clear(&ssi.sdNumSubStreams);
1161
1162  ssi.NumSubDigests = 0;
1163  ssi.NumTotalSubStreams = 0;
1164
1165  RINOK(ReadID(sd, &type));
1166
1167  if (type == k7zIdArchiveProperties)
1168  {
1169    for (;;)
1170    {
1171      UInt64 type;
1172      RINOK(ReadID(sd, &type));
1173      if (type == k7zIdEnd)
1174        break;
1175      RINOK(SkipData(sd));
1176    }
1177    RINOK(ReadID(sd, &type));
1178  }
1179
1180  // if (type == k7zIdAdditionalStreamsInfo)     return SZ_ERROR_UNSUPPORTED;
1181
1182  if (type == k7zIdAdditionalStreamsInfo)
1183  {
1184    CSzAr tempAr;
1185    SRes res;
1186    UInt32 numTempFolders;
1187
1188    SzAr_Init(&tempAr);
1189    res = SzReadAndDecodePackedStreams(inStream, sd, tempBufs, NUM_ADDITIONAL_STREAMS_MAX,
1190        p->startPosAfterHeader, &tempAr, allocTemp);
1191    numTempFolders = tempAr.NumFolders;
1192    SzAr_Free(&tempAr, allocTemp);
1193    if (res != SZ_OK)
1194      return res;
1195    *numTempBufs = numTempFolders;
1196    RINOK(ReadID(sd, &type));
1197  }
1198
1199  if (type == k7zIdMainStreamsInfo)
1200  {
1201    RINOK(SzReadStreamsInfo(&p->db, sd, (UInt32)1 << 30, tempBufs, *numTempBufs,
1202        &p->dataPos, &ssi, allocMain));
1203    p->dataPos += p->startPosAfterHeader;
1204    RINOK(ReadID(sd, &type));
1205  }
1206
1207  if (type == k7zIdEnd)
1208  {
1209    // *sd2 = sd;
1210    return SZ_OK;
1211  }
1212  if (type != k7zIdFilesInfo)
1213    return SZ_ERROR_ARCHIVE;
1214
1215  RINOK(SzReadNumber32(sd, &numFiles));
1216  p->NumFiles = numFiles;
1217
1218  for (;;)
1219  {
1220    UInt64 type;
1221    UInt64 size;
1222    RINOK(ReadID(sd, &type));
1223    if (type == k7zIdEnd)
1224      break;
1225    RINOK(ReadNumber(sd, &size));
1226    if (size > sd->Size)
1227      return SZ_ERROR_ARCHIVE;
1228    if ((UInt64)(int)type != type)
1229    {
1230      SKIP_DATA(sd, size);
1231    }
1232    else switch((int)type)
1233    {
1234      case k7zIdName:
1235      {
1236        size_t namesSize;
1237        const Byte *namesData;
1238        Byte external;
1239
1240        SZ_READ_BYTE(external);
1241        if (external == 0)
1242        {
1243          namesSize = (size_t)size - 1;
1244          namesData = sd->Data;
1245        }
1246        else
1247        {
1248          UInt32 index;
1249          SzReadNumber32(sd, &index);
1250          if (index >= *numTempBufs)
1251            return SZ_ERROR_ARCHIVE;
1252          namesData = (tempBufs)[index].data;
1253          namesSize = (tempBufs)[index].size;
1254        }
1255
1256        if ((namesSize & 1) != 0)
1257          return SZ_ERROR_ARCHIVE;
1258        MY_ALLOC(Byte, p->FileNames, namesSize, allocMain);
1259        MY_ALLOC(size_t, p->FileNameOffsets, numFiles + 1, allocMain);
1260        memcpy(p->FileNames, namesData, namesSize);
1261        RINOK(SzReadFileNames(p->FileNames, namesSize, numFiles, p->FileNameOffsets))
1262        if (external == 0)
1263        {
1264          SKIP_DATA(sd, namesSize);
1265        }
1266        break;
1267      }
1268      case k7zIdEmptyStream:
1269      {
1270        RINOK(RememberBitVector(sd, numFiles, &emptyStreams));
1271        numEmptyStreams = CountDefinedBits(emptyStreams, numFiles);
1272        break;
1273      }
1274      case k7zIdEmptyFile:
1275      {
1276        RINOK(RememberBitVector(sd, numEmptyStreams, &emptyFiles));
1277        break;
1278      }
1279      case k7zIdWinAttrib:
1280      {
1281        Byte external;
1282        CSzData sdSwitch;
1283        CSzData *sdPtr;
1284        SzBitUi32s_Free(&p->Attribs, allocMain);
1285        RINOK(ReadBitVector(sd, numFiles, &p->Attribs.Defs, allocMain));
1286
1287        SZ_READ_BYTE(external);
1288        if (external == 0)
1289          sdPtr = sd;
1290        else
1291        {
1292          UInt32 index;
1293          SzReadNumber32(sd, &index);
1294          if (index >= *numTempBufs)
1295            return SZ_ERROR_ARCHIVE;
1296          sdSwitch.Data = (tempBufs)[index].data;
1297          sdSwitch.Size = (tempBufs)[index].size;
1298          sdPtr = &sdSwitch;
1299        }
1300        RINOK(ReadUi32s(sdPtr, numFiles, &p->Attribs, allocMain));
1301        break;
1302      }
1303      /*
1304      case k7zParent:
1305      {
1306        SzBitUi32s_Free(&p->Parents, allocMain);
1307        RINOK(ReadBitVector(sd, numFiles, &p->Parents.Defs, allocMain));
1308        RINOK(SzReadSwitch(sd));
1309        RINOK(ReadUi32s(sd, numFiles, &p->Parents, allocMain));
1310        break;
1311      }
1312      */
1313      case k7zIdMTime: RINOK(ReadTime(&p->MTime, numFiles, sd, tempBufs, *numTempBufs, allocMain)); break;
1314      case k7zIdCTime: RINOK(ReadTime(&p->CTime, numFiles, sd, tempBufs, *numTempBufs, allocMain)); break;
1315      default:
1316      {
1317        SKIP_DATA(sd, size);
1318      }
1319    }
1320  }
1321
1322  if (numFiles - numEmptyStreams != ssi.NumTotalSubStreams)
1323    return SZ_ERROR_ARCHIVE;
1324
1325  for (;;)
1326  {
1327    UInt64 type;
1328    RINOK(ReadID(sd, &type));
1329    if (type == k7zIdEnd)
1330      break;
1331    RINOK(SkipData(sd));
1332  }
1333
1334  {
1335    UInt32 emptyFileIndex = 0;
1336
1337    UInt32 folderIndex = 0;
1338    UInt32 indexInFolder = 0;
1339    UInt64 unpackPos = 0;
1340    const Byte *digestsDefs = 0;
1341    const Byte *digestsVals = 0;
1342    UInt32 digestsValsIndex = 0;
1343    UInt32 digestIndex;
1344    Byte allDigestsDefined = 0;
1345    UInt32 curNumSubStreams = (UInt32)(Int32)-1;
1346    Byte isDirMask = 0;
1347    Byte crcMask = 0;
1348    Byte mask = 0x80;
1349    // size_t unpSizesOffset = 0;
1350    CSzData sdCodersUnpSizes;
1351    sdCodersUnpSizes.Data = p->db.UnpackSizesData;
1352    sdCodersUnpSizes.Size = p->db.UnpackSizesDataSize;
1353
1354    MY_ALLOC(UInt32, p->FolderStartFileIndex, p->db.NumFolders + 1, allocMain);
1355    MY_ALLOC(UInt32, p->FileIndexToFolderIndexMap, p->NumFiles, allocMain);
1356    MY_ALLOC(UInt64, p->UnpackPositions, p->NumFiles + 1, allocMain);
1357    MY_ALLOC(Byte, p->IsDirs, (p->NumFiles + 7) >> 3, allocMain);
1358
1359    RINOK(SzBitUi32s_Alloc(&p->CRCs, p->NumFiles, allocMain));
1360
1361    if (ssi.sdCRCs.Size != 0)
1362    {
1363      RINOK(SzReadByte(&ssi.sdCRCs, &allDigestsDefined));
1364      if (allDigestsDefined)
1365        digestsVals = ssi.sdCRCs.Data;
1366      else
1367      {
1368        size_t numBytes = (ssi.NumSubDigests + 7) >> 3;
1369        digestsDefs = ssi.sdCRCs.Data;
1370        digestsVals = digestsDefs + numBytes;
1371      }
1372    }
1373
1374    digestIndex = 0;
1375    for (i = 0; i < numFiles; i++, mask >>= 1)
1376    {
1377      if (mask == 0)
1378      {
1379        UInt32 byteIndex = (i - 1) >> 3;
1380        p->IsDirs[byteIndex] = isDirMask;
1381        p->CRCs.Defs[byteIndex] = crcMask;
1382        isDirMask = 0;
1383        crcMask = 0;
1384        mask = 0x80;
1385      }
1386
1387      p->UnpackPositions[i] = unpackPos;
1388      p->CRCs.Vals[i] = 0;
1389      // p->CRCs.Defs[i] = 0;
1390      if (emptyStreams && SzBitArray_Check(emptyStreams , i))
1391      {
1392        if (!emptyFiles || !SzBitArray_Check(emptyFiles, emptyFileIndex))
1393          isDirMask |= mask;
1394        emptyFileIndex++;
1395        if (indexInFolder == 0)
1396        {
1397          p->FileIndexToFolderIndexMap[i] = (UInt32)-1;
1398          continue;
1399        }
1400      }
1401      if (indexInFolder == 0)
1402      {
1403        /*
1404        v3.13 incorrectly worked with empty folders
1405        v4.07: Loop for skipping empty folders
1406        */
1407        for (;;)
1408        {
1409          if (folderIndex >= p->db.NumFolders)
1410            return SZ_ERROR_ARCHIVE;
1411          p->FolderStartFileIndex[folderIndex] = i;
1412          if (curNumSubStreams == (UInt32)(Int32)-1);
1413          {
1414            curNumSubStreams = 1;
1415            if (ssi.sdNumSubStreams.Data != 0)
1416            {
1417              RINOK(SzReadNumber32(&ssi.sdNumSubStreams, &curNumSubStreams));
1418            }
1419          }
1420          if (curNumSubStreams != 0)
1421            break;
1422          curNumSubStreams = (UInt32)(Int32)-1;
1423          folderIndex++; // check it
1424        }
1425      }
1426      p->FileIndexToFolderIndexMap[i] = folderIndex;
1427      if (emptyStreams && SzBitArray_Check(emptyStreams , i))
1428        continue;
1429
1430      indexInFolder++;
1431      if (indexInFolder >= curNumSubStreams)
1432      {
1433        UInt64 folderUnpackSize = 0;
1434        UInt64 startFolderUnpackPos;
1435        {
1436          UInt32 mix = (UInt32)p->db.FoSizesOffsets[folderIndex];
1437          UInt32 mainIndex = mix & 0xFF;
1438          UInt32 numOutStreams = mix >> 8;
1439          UInt32 si;
1440          p->db.FoSizesOffsets[folderIndex] = sdCodersUnpSizes.Data - p->db.UnpackSizesData;
1441          for (si = 0; si < numOutStreams; si++)
1442          {
1443            UInt64 curSize;
1444            RINOK(ReadNumber(&sdCodersUnpSizes, &curSize));
1445            if (si == mainIndex)
1446            {
1447              folderUnpackSize = curSize;
1448              break;
1449            }
1450          }
1451          if (si == numOutStreams)
1452            return SZ_ERROR_FAIL;
1453        }
1454
1455        // UInt64 folderUnpackSize = SzAr_GetFolderUnpackSize(&p->db, folderIndex);
1456        startFolderUnpackPos = p->UnpackPositions[p->FolderStartFileIndex[folderIndex]];
1457        if (folderUnpackSize < unpackPos - startFolderUnpackPos)
1458          return SZ_ERROR_ARCHIVE;
1459        unpackPos = startFolderUnpackPos + folderUnpackSize;
1460
1461        if (curNumSubStreams == 1 && SzBitWithVals_Check(&p->db.FolderCRCs, i))
1462        {
1463          p->CRCs.Vals[i] = p->db.FolderCRCs.Vals[folderIndex];
1464          crcMask |= mask;
1465        }
1466        else if (allDigestsDefined || (digestsDefs && SzBitArray_Check(digestsDefs, digestIndex)))
1467        {
1468          p->CRCs.Vals[i] = GetUi32(digestsVals + (size_t)digestsValsIndex * 4);
1469          digestsValsIndex++;
1470          crcMask |= mask;
1471        }
1472        folderIndex++;
1473        indexInFolder = 0;
1474      }
1475      else
1476      {
1477        UInt64 v;
1478        RINOK(ReadNumber(&ssi.sdSizes, &v));
1479        unpackPos += v;
1480        if (allDigestsDefined || (digestsDefs && SzBitArray_Check(digestsDefs, digestIndex)))
1481        {
1482          p->CRCs.Vals[i] = GetUi32(digestsVals + (size_t)digestsValsIndex * 4);
1483          digestsValsIndex++;
1484          crcMask |= mask;
1485        }
1486      }
1487    }
1488    if (mask != 0x80)
1489    {
1490      UInt32 byteIndex = (i - 1) >> 3;
1491      p->IsDirs[byteIndex] = isDirMask;
1492      p->CRCs.Defs[byteIndex] = crcMask;
1493    }
1494    p->UnpackPositions[i] = unpackPos;
1495    p->FolderStartFileIndex[folderIndex] = i;
1496    p->db.FoSizesOffsets[folderIndex] = sdCodersUnpSizes.Data - p->db.UnpackSizesData;
1497  }
1498  return SZ_OK;
1499}
1500
1501static SRes SzReadHeader(
1502    CSzArEx *p,
1503    CSzData *sd,
1504    ILookInStream *inStream,
1505    ISzAlloc *allocMain
1506    ,ISzAlloc *allocTemp
1507    )
1508{
1509  // Byte *emptyStreamVector = 0;
1510  // Byte *emptyFileVector = 0;
1511  // Byte *lwtVector = 0;
1512  UInt32 i;
1513  UInt32 numTempBufs = 0;
1514  SRes res;
1515  CBuf tempBufs[NUM_ADDITIONAL_STREAMS_MAX];
1516
1517  for (i = 0; i < NUM_ADDITIONAL_STREAMS_MAX; i++)
1518    Buf_Init(tempBufs + i);
1519  // SzBitUi32s_Init(&digests);
1520
1521  res = SzReadHeader2(p, sd,
1522      // &emptyStreamVector,
1523      // &emptyFileVector,
1524      // &lwtVector,
1525      inStream,
1526      tempBufs, &numTempBufs,
1527      allocMain, allocTemp
1528      );
1529
1530  for (i = 0; i < numTempBufs; i++)
1531    Buf_Free(tempBufs + i, allocTemp);
1532
1533  // IAlloc_Free(allocTemp, emptyStreamVector);
1534  // IAlloc_Free(allocTemp, emptyFileVector);
1535  // IAlloc_Free(allocTemp, lwtVector);
1536
1537  RINOK(res);
1538  {
1539    if (sd->Size != 0)
1540      return SZ_ERROR_FAIL;
1541  }
1542
1543  return res;
1544}
1545
1546/*
1547static UInt64 SzAr_GetFolderUnpackSize(const CSzAr *p, UInt32 folderIndex)
1548{
1549  const CSzFolder2 *f = p->Folders + folderIndex;
1550
1551  // return p->CoderUnpackSizes[f->StartCoderUnpackSizesIndex + f->IndexOfMainOutStream];
1552
1553  UInt32 si;
1554  CSzData sdCodersUnpSizes;
1555  sdCodersUnpSizes.Data = p->UnpackSizesData + f->UnpackSizeDataOffset;
1556  sdCodersUnpSizes.Size = p->UnpackSizesDataSize - f->UnpackSizeDataOffset;
1557  for (si = 0; si < numOutStreams; si++)
1558  {
1559    UInt64 curSize;
1560    ReadNumber(&sdCodersUnpSizes, &curSize);
1561    if (si == mainIndex)
1562      return curSize;
1563  }
1564  return 0;
1565}
1566*/
1567
1568static SRes SzArEx_Open2(
1569    CSzArEx *p,
1570    ILookInStream *inStream,
1571    ISzAlloc *allocMain,
1572    ISzAlloc *allocTemp)
1573{
1574  Byte header[k7zStartHeaderSize];
1575  Int64 startArcPos;
1576  UInt64 nextHeaderOffset, nextHeaderSize;
1577  size_t nextHeaderSizeT;
1578  UInt32 nextHeaderCRC;
1579  CBuf buf;
1580  SRes res;
1581
1582  startArcPos = 0;
1583  RINOK(inStream->Seek(inStream, &startArcPos, SZ_SEEK_CUR));
1584
1585  RINOK(LookInStream_Read2(inStream, header, k7zStartHeaderSize, SZ_ERROR_NO_ARCHIVE));
1586
1587  if (!TestSignatureCandidate(header))
1588    return SZ_ERROR_NO_ARCHIVE;
1589  if (header[6] != k7zMajorVersion)
1590    return SZ_ERROR_UNSUPPORTED;
1591
1592  nextHeaderOffset = GetUi64(header + 12);
1593  nextHeaderSize = GetUi64(header + 20);
1594  nextHeaderCRC = GetUi32(header + 28);
1595
1596  p->startPosAfterHeader = startArcPos + k7zStartHeaderSize;
1597
1598  if (CrcCalc(header + 12, 20) != GetUi32(header + 8))
1599    return SZ_ERROR_CRC;
1600
1601  nextHeaderSizeT = (size_t)nextHeaderSize;
1602  if (nextHeaderSizeT != nextHeaderSize)
1603    return SZ_ERROR_MEM;
1604  if (nextHeaderSizeT == 0)
1605    return SZ_OK;
1606  if (nextHeaderOffset > nextHeaderOffset + nextHeaderSize ||
1607      nextHeaderOffset > nextHeaderOffset + nextHeaderSize + k7zStartHeaderSize)
1608    return SZ_ERROR_NO_ARCHIVE;
1609
1610  {
1611    Int64 pos = 0;
1612    RINOK(inStream->Seek(inStream, &pos, SZ_SEEK_END));
1613    if ((UInt64)pos < startArcPos + nextHeaderOffset ||
1614        (UInt64)pos < startArcPos + k7zStartHeaderSize + nextHeaderOffset ||
1615        (UInt64)pos < startArcPos + k7zStartHeaderSize + nextHeaderOffset + nextHeaderSize)
1616      return SZ_ERROR_INPUT_EOF;
1617  }
1618
1619  RINOK(LookInStream_SeekTo(inStream, startArcPos + k7zStartHeaderSize + nextHeaderOffset));
1620
1621  if (!Buf_Create(&buf, nextHeaderSizeT, allocTemp))
1622    return SZ_ERROR_MEM;
1623
1624  res = LookInStream_Read(inStream, buf.data, nextHeaderSizeT);
1625  if (res == SZ_OK)
1626  {
1627    res = SZ_ERROR_ARCHIVE;
1628    if (CrcCalc(buf.data, nextHeaderSizeT) == nextHeaderCRC)
1629    {
1630      CSzData sd;
1631      UInt64 type;
1632      sd.Data = buf.data;
1633      sd.Size = buf.size;
1634      res = ReadID(&sd, &type);
1635      if (res == SZ_OK && type == k7zIdEncodedHeader)
1636      {
1637        CSzAr tempAr;
1638        CBuf tempBuf;
1639        Buf_Init(&tempBuf);
1640
1641        SzAr_Init(&tempAr);
1642        res = SzReadAndDecodePackedStreams(inStream, &sd, &tempBuf, 1, p->startPosAfterHeader, &tempAr, allocTemp);
1643        SzAr_Free(&tempAr, allocTemp);
1644
1645        if (res != SZ_OK)
1646        {
1647          Buf_Free(&tempBuf, allocTemp);
1648        }
1649        else
1650        {
1651          Buf_Free(&buf, allocTemp);
1652          buf.data = tempBuf.data;
1653          buf.size = tempBuf.size;
1654          sd.Data = buf.data;
1655          sd.Size = buf.size;
1656          res = ReadID(&sd, &type);
1657        }
1658      }
1659      if (res == SZ_OK)
1660      {
1661        if (type == k7zIdHeader)
1662        {
1663          CSzData sd2;
1664          int ttt;
1665          for (ttt = 0; ttt < 1; ttt++)
1666          // for (ttt = 0; ttt < 40000; ttt++)
1667          {
1668            SzArEx_Free(p, allocMain);
1669            sd2 = sd;
1670            res = SzReadHeader(p, &sd2, inStream, allocMain, allocTemp
1671              );
1672            if (res != SZ_OK)
1673              break;
1674          }
1675
1676          // res = SzReadHeader(p, &sd, allocMain, allocTemp);
1677        }
1678        else
1679          res = SZ_ERROR_UNSUPPORTED;
1680      }
1681    }
1682  }
1683  Buf_Free(&buf, allocTemp);
1684  return res;
1685}
1686
1687// #include <stdio.h>
1688
1689SRes SzArEx_Open(CSzArEx *p, ILookInStream *inStream,
1690    ISzAlloc *allocMain, ISzAlloc *allocTemp)
1691{
1692  SRes res = SzArEx_Open2(p, inStream, allocMain, allocTemp);
1693  if (res != SZ_OK)
1694    SzArEx_Free(p, allocMain);
1695  // printf ("\nrrr=%d\n", rrr);
1696  return res;
1697}
1698
1699SRes SzArEx_Extract(
1700    const CSzArEx *p,
1701    ILookInStream *inStream,
1702    UInt32 fileIndex,
1703    UInt32 *blockIndex,
1704    Byte **tempBuf,
1705    size_t *outBufferSize,
1706    size_t *offset,
1707    size_t *outSizeProcessed,
1708    ISzAlloc *allocMain,
1709    ISzAlloc *allocTemp)
1710{
1711  UInt32 folderIndex = p->FileIndexToFolderIndexMap[fileIndex];
1712  SRes res = SZ_OK;
1713  *offset = 0;
1714  *outSizeProcessed = 0;
1715  if (folderIndex == (UInt32)-1)
1716  {
1717    IAlloc_Free(allocMain, *tempBuf);
1718    *blockIndex = folderIndex;
1719    *tempBuf = 0;
1720    *outBufferSize = 0;
1721    return SZ_OK;
1722  }
1723
1724  if (*tempBuf == 0 || *blockIndex != folderIndex)
1725  {
1726    // UInt64 unpackSizeSpec = SzAr_GetFolderUnpackSize(&p->db, folderIndex);
1727    UInt64 unpackSizeSpec =
1728        p->UnpackPositions[p->FolderStartFileIndex[folderIndex + 1]] -
1729        p->UnpackPositions[p->FolderStartFileIndex[folderIndex]];
1730    size_t unpackSize = (size_t)unpackSizeSpec;
1731
1732    if (unpackSize != unpackSizeSpec)
1733      return SZ_ERROR_MEM;
1734    *blockIndex = folderIndex;
1735    IAlloc_Free(allocMain, *tempBuf);
1736    *tempBuf = 0;
1737
1738    // RINOK(LookInStream_SeekTo(inStream, startOffset));
1739
1740    if (res == SZ_OK)
1741    {
1742      *outBufferSize = unpackSize;
1743      if (unpackSize != 0)
1744      {
1745        *tempBuf = (Byte *)IAlloc_Alloc(allocMain, unpackSize);
1746        if (*tempBuf == 0)
1747          res = SZ_ERROR_MEM;
1748      }
1749      if (res == SZ_OK)
1750      {
1751        res = SzAr_DecodeFolder(&p->db, folderIndex,
1752          inStream,
1753          p->dataPos,
1754          *tempBuf, unpackSize, allocTemp);
1755        if (res == SZ_OK)
1756        {
1757          if (SzBitWithVals_Check(&p->db.FolderCRCs, folderIndex))
1758          {
1759            if (CrcCalc(*tempBuf, unpackSize) != p->db.FolderCRCs.Vals[folderIndex])
1760              res = SZ_ERROR_CRC;
1761          }
1762        }
1763      }
1764    }
1765  }
1766  if (res == SZ_OK)
1767  {
1768    UInt64 unpackPos = p->UnpackPositions[fileIndex];
1769    *offset = (size_t)(unpackPos - p->UnpackPositions[p->FolderStartFileIndex[folderIndex]]);
1770    *outSizeProcessed = (size_t)(p->UnpackPositions[fileIndex + 1] - unpackPos);
1771    if (*offset + *outSizeProcessed > *outBufferSize)
1772      return SZ_ERROR_FAIL;
1773    if (SzBitWithVals_Check(&p->CRCs, fileIndex) && CrcCalc(*tempBuf + *offset, *outSizeProcessed) != p->CRCs.Vals[fileIndex])
1774      res = SZ_ERROR_CRC;
1775  }
1776  return res;
1777}
1778
1779
1780size_t SzArEx_GetFileNameUtf16(const CSzArEx *p, size_t fileIndex, UInt16 *dest)
1781{
1782  size_t offs = p->FileNameOffsets[fileIndex];
1783  size_t len = p->FileNameOffsets[fileIndex + 1] - offs;
1784  if (dest != 0)
1785  {
1786    size_t i;
1787    const Byte *src = p->FileNames + offs * 2;
1788    for (i = 0; i < len; i++)
1789      dest[i] = GetUi16(src + i * 2);
1790  }
1791  return len;
1792}
1793
1794/*
1795size_t SzArEx_GetFullNameLen(const CSzArEx *p, size_t fileIndex)
1796{
1797  size_t len;
1798  if (!p->FileNameOffsets)
1799    return 1;
1800  len = 0;
1801  for (;;)
1802  {
1803    UInt32 parent = (UInt32)(Int32)-1;
1804    len += p->FileNameOffsets[fileIndex + 1] - p->FileNameOffsets[fileIndex];
1805    if SzBitWithVals_Check(&p->Parents, fileIndex)
1806      parent = p->Parents.Vals[fileIndex];
1807    if (parent == (UInt32)(Int32)-1)
1808      return len;
1809    fileIndex = parent;
1810  }
1811}
1812
1813UInt16 *SzArEx_GetFullNameUtf16_Back(const CSzArEx *p, size_t fileIndex, UInt16 *dest)
1814{
1815  Bool needSlash;
1816  if (!p->FileNameOffsets)
1817  {
1818    *(--dest) = 0;
1819    return dest;
1820  }
1821  needSlash = False;
1822  for (;;)
1823  {
1824    UInt32 parent = (UInt32)(Int32)-1;
1825    size_t curLen = p->FileNameOffsets[fileIndex + 1] - p->FileNameOffsets[fileIndex];
1826    SzArEx_GetFileNameUtf16(p, fileIndex, dest - curLen);
1827    if (needSlash)
1828      *(dest - 1) = '/';
1829    needSlash = True;
1830    dest -= curLen;
1831
1832    if SzBitWithVals_Check(&p->Parents, fileIndex)
1833      parent = p->Parents.Vals[fileIndex];
1834    if (parent == (UInt32)(Int32)-1)
1835      return dest;
1836    fileIndex = parent;
1837  }
1838}
1839*/
1840