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