xref: /aosp_15_r20/external/lzma/CPP/7zip/Archive/Udf/UdfIn.cpp (revision f6dc9357d832569d4d1f5d24eacdb3935a1ae8e6)
1 // Archive/UdfIn.cpp
2 
3 #include "StdAfx.h"
4 
5 // #define SHOW_DEBUG_INFO
6 
7 #ifdef SHOW_DEBUG_INFO
8 #include <stdio.h>
9 #endif
10 
11 #include "../../../../C/CpuArch.h"
12 
13 #include "../../../Windows/PropVariantUtils.h"
14 
15 #include "../../Common/RegisterArc.h"
16 #include "../../Common/StreamUtils.h"
17 
18 #include "UdfIn.h"
19 
20 #ifdef SHOW_DEBUG_INFO
21 #define PRF(x) x
22 #else
23 #define PRF(x)
24 #endif
25 
26 #define Get16(p) GetUi16(p)
27 #define Get32(p) GetUi32(p)
28 #define Get64(p) GetUi64(p)
29 
30 #define G16(_offs_, dest) dest = Get16(p + (_offs_))
31 #define G32(_offs_, dest) dest = Get32(p + (_offs_))
32 #define G64(_offs_, dest) dest = Get64(p + (_offs_))
33 
34 namespace NArchive {
35 namespace NUdf {
36 
37 static const unsigned kNumPartitionsMax = 64;
38 static const unsigned kNumLogVolumesMax = 64;
39 static const unsigned kNumRecursionLevelsMax = 1 << 10;
40 static const unsigned kNumItemsMax = 1 << 27;
41 static const unsigned kNumFilesMax = 1 << 28;
42 static const unsigned kNumRefsMax = 1 << 28;
43 static const UInt32 kNumExtentsMax = (UInt32)1 << 30;
44 static const UInt64 kFileNameLengthTotalMax = (UInt64)1 << 33;
45 static const UInt64 kInlineExtentsSizeMax = (UInt64)1 << 33;
46 
47 #define CRC16_INIT_VAL 0
48 #define CRC16_UPDATE_BYTE(crc, b) ((UInt16)(g_Crc16Table[(((crc) >> 8) ^ (b)) & 0xFF] ^ ((crc) << 8)))
49 
50 #define kCrc16Poly 0x1021
51 static UInt16 g_Crc16Table[256];
52 
Crc16GenerateTable(void)53 static void Z7_FASTCALL Crc16GenerateTable(void)
54 {
55   UInt32 i;
56   for (i = 0; i < 256; i++)
57   {
58     UInt32 r = (i << 8);
59     for (unsigned j = 0; j < 8; j++)
60       r = ((r << 1) ^ (kCrc16Poly & ((UInt32)0 - (r >> 15)))) & 0xFFFF;
61     g_Crc16Table[i] = (UInt16)r;
62   }
63 }
64 
Crc16Calc(const void * data,size_t size)65 static UInt32 Z7_FASTCALL Crc16Calc(const void *data, size_t size)
66 {
67   UInt32 v = CRC16_INIT_VAL;
68   const Byte *p = (const Byte *)data;
69   const Byte *pEnd = p + size;
70   for (; p != pEnd; p++)
71     v = CRC16_UPDATE_BYTE(v, *p);
72   return v;
73 }
74 
CCrc16TableInitNArchive::NUdf::CCrc16TableInit75 static struct CCrc16TableInit { CCrc16TableInit() { Crc16GenerateTable(); } } g_Crc16TableInit;
76 
77 
78 // ---------- ECMA Part 1 ----------
79 
Parse(const Byte * p,unsigned size)80 void CDString::Parse(const Byte *p, unsigned size)
81 {
82   Data.CopyFrom(p, size);
83 }
84 
ParseDString(const Byte * data,unsigned size)85 static UString ParseDString(const Byte *data, unsigned size)
86 {
87   UString res;
88   if (size != 0)
89   {
90     wchar_t *p;
91     const Byte type = *data++;
92     size--;
93     if (type == 8)
94     {
95       p = res.GetBuf(size);
96       for (unsigned i = 0; i < size; i++)
97       {
98         const wchar_t c = data[i];
99         if (c == 0)
100           break;
101         *p++ = c;
102       }
103     }
104     else if (type == 16)
105     {
106       size &= ~(unsigned)1;
107       p = res.GetBuf(size / 2);
108       for (unsigned i = 0; i < size; i += 2)
109       {
110         const wchar_t c = GetBe16(data + i);
111         if (c == 0)
112           break;
113         *p++ = c;
114       }
115     }
116     else
117       return UString("[unknown]");
118     *p = 0;
119     res.ReleaseBuf_SetLen((unsigned)(p - (const wchar_t *)res));
120   }
121   return res;
122 }
123 
GetString() const124 UString CDString32::GetString() const
125 {
126   const unsigned size = Data[sizeof(Data) - 1];
127   return ParseDString(Data, MyMin(size, (unsigned)(sizeof(Data) - 1)));
128 }
129 
GetString() const130 UString CDString128::GetString() const
131 {
132   const unsigned size = Data[sizeof(Data) - 1];
133   return ParseDString(Data, MyMin(size, (unsigned)(sizeof(Data) - 1)));
134 }
135 
GetString() const136 UString CDString::GetString() const { return ParseDString(Data, (unsigned)Data.Size()); }
137 
Parse(const Byte * p)138 void CTime::Parse(const Byte *p) { memcpy(Data, p, sizeof(Data)); }
139 
140 
AddCommentChars(UString & dest,const char * s,size_t size)141 static void AddCommentChars(UString &dest, const char *s, size_t size)
142 {
143   for (size_t i = 0; i < size; i++)
144   {
145     char c = s[i];
146     if (c == 0)
147       break;
148     if (c < 0x20)
149       c = '_';
150     dest += (wchar_t)c;
151   }
152 }
153 
154 
Parse(const Byte * p)155 void CRegId::Parse(const Byte *p)
156 {
157   Flags = p[0];
158   memcpy(Id, p + 1, sizeof(Id));
159   memcpy(Suffix, p + 24, sizeof(Suffix));
160 }
161 
AddCommentTo(UString & s) const162 void CRegId::AddCommentTo(UString &s) const
163 {
164   AddCommentChars(s, Id, sizeof(Id));
165 }
166 
AddUdfVersionTo(UString & s) const167 void CRegId::AddUdfVersionTo(UString &s) const
168 {
169   // use it only for "Domain Identifier Suffix" and "UDF Identifier Suffix"
170   // UDF 2.1.5.3
171   // Revision in hex (3 digits)
172   const Byte minor = Suffix[0];
173   const Byte major = Suffix[1];
174   if (major != 0 || minor != 0)
175   {
176     char temp[16];
177     ConvertUInt32ToHex(major, temp);
178     s += temp;
179     s.Add_Dot();
180     ConvertUInt32ToHex8Digits(minor, temp);
181     s += &temp[8 - 2];
182   }
183 }
184 
185 
186 // ---------- ECMA Part 3: Volume Structure ----------
187 
Parse(const Byte * p)188 void CExtent::Parse(const Byte *p)
189 {
190   /* Len shall be less than < 2^30.
191      Unless otherwise specified, the length shall be an integral multiple of the logical sector size.
192      If (Len == 0), no extent is specified and (Pos) shall contain 0 */
193   G32 (0, Len);
194   G32 (4, Pos);
195 }
196 
197 
198 // ECMA 3/7.2
199 
200 struct CTag
201 {
202   UInt16 Id;
203   // UInt16 Version;
204   // Byte Checksum;
205   // UInt16 SerialNumber;
206   // UInt16 Crc;
207   UInt16 CrcLen;
208   // UInt32 TagLocation; // the number of the logical sector
209 
210   HRESULT Parse(const Byte *p, size_t size);
211 };
212 
Parse(const Byte * p,size_t size)213 HRESULT CTag::Parse(const Byte *p, size_t size)
214 {
215   if (size < 16)
216     return S_FALSE;
217   {
218     unsigned sum = 0;
219     for (unsigned i = 0; i < 16; i++)
220       sum = sum + p[i];
221     if ((Byte)(sum - p[4]) != p[4] || p[5] != 0)
222       return S_FALSE;
223   }
224   Id = Get16(p);
225   const UInt16 Version = Get16(p + 2);
226   if (Version != 2 && Version != 3)
227     return S_FALSE;
228   // SerialNumber = Get16(p + 6);
229   const UInt32 crc = Get16(p + 8);
230   CrcLen = Get16(p + 10);
231   // TagLocation = Get32(p + 12);
232 
233   if (size >= 16 + (size_t)CrcLen)
234     if (crc == Crc16Calc(p + 16, (size_t)CrcLen))
235       return S_OK;
236   return S_FALSE;
237 }
238 
239 // ECMA 3/7.2.1
240 
241 enum EDescriptorType
242 {
243   DESC_TYPE_SpoaringTable       = 0, // UDF
244   DESC_TYPE_PrimVol             = 1,
245   DESC_TYPE_AnchorVolPtr        = 2,
246   DESC_TYPE_VolPtr              = 3,
247   DESC_TYPE_ImplUseVol          = 4,
248   DESC_TYPE_Partition           = 5,
249   DESC_TYPE_LogicalVol          = 6,
250   DESC_TYPE_UnallocSpace        = 7,
251   DESC_TYPE_Terminating         = 8,
252   DESC_TYPE_LogicalVolIntegrity = 9,
253   DESC_TYPE_FileSet             = 256,
254   DESC_TYPE_FileId              = 257,
255   DESC_TYPE_AllocationExtent    = 258,
256   DESC_TYPE_Indirect            = 259,
257   DESC_TYPE_Terminal            = 260,
258   DESC_TYPE_File                = 261,
259   DESC_TYPE_ExtendedAttrHeader  = 262,
260   DESC_TYPE_UnallocatedSpaceEntry = 263,
261   DESC_TYPE_SpaceBitmap         = 264,
262   DESC_TYPE_PartitionIntegrity  = 265,
263   DESC_TYPE_ExtendedFile        = 266
264 };
265 
266 
Parse(const Byte * p)267 void CLogBlockAddr::Parse(const Byte *p)
268 {
269   G32 (0, Pos);
270   G16 (4, PartitionRef);
271 }
272 
Parse(const Byte * p)273 void CShortAllocDesc::Parse(const Byte *p)
274 {
275   G32 (0, Len);
276   G32 (4, Pos);
277 }
278 
279 /*
280 void CADImpUse::Parse(const Byte *p)
281 {
282   G16 (0, Flags);
283   G32 (2, UdfUniqueId);
284 }
285 */
286 
Parse(const Byte * p)287 void CLongAllocDesc::Parse(const Byte *p)
288 {
289   G32 (0, Len);
290   Location.Parse(p + 4);
291   // memcpy(ImplUse, p + 10, sizeof(ImplUse));
292   // adImpUse.Parse(ImplUse);
293 }
294 
295 
Parse(const Byte * p)296 void CPrimeVol::Parse(const Byte *p)
297 {
298   // G32 (16, VolumeDescriptorSequenceNumber);
299   G32 (20, PrimaryVolumeDescriptorNumber);
300   VolumeId.Parse(p + 24);
301   G16 (56, VolumeSequenceNumber);
302   G16 (58, MaximumVolumeSequenceNumber);
303   // G16 (60, InterchangeLevel);
304   // G16 (62, MaximumInterchangeLevel);
305   // G32 (64, CharacterSetList)
306   // G32 (68, MaximumCharacterSetList)
307   VolumeSetId.Parse(p + 72);
308   // 200 64 Descriptor Character Set charspec (1/7.2.1)
309   // 264 64 Explanatory Character Set charspec (1/7.2.1)
310   // VolumeAbstract.Parse(p + 328);
311   // VolumeCopyrightNotice.Parse(p + 336);
312   ApplicationId.Parse(p + 344);
313   RecordingTime.Parse(p + 376);
314   ImplId.Parse(p + 388);
315   // 420 64 Implementation Use bytes
316   // G32 (484, PredecessorVolumeDescriptorSequenceLocation);
317   // G16 (488, Flags);
318 }
319 
320 
321 
CheckExtent(unsigned volIndex,unsigned partitionRef,UInt32 blockPos,UInt32 len) const322 bool CInArchive::CheckExtent(unsigned volIndex, unsigned partitionRef, UInt32 blockPos, UInt32 len) const
323 {
324   const CLogVol &vol = LogVols[volIndex];
325   if (partitionRef >= vol.PartitionMaps.Size())
326     return false;
327   const CPartition &partition = Partitions[vol.PartitionMaps[partitionRef].PartitionIndex];
328   return ((UInt64)blockPos * vol.BlockSize + len) <= ((UInt64)partition.Len << SecLogSize);
329 }
330 
CheckItemExtents(unsigned volIndex,const CItem & item) const331 bool CInArchive::CheckItemExtents(unsigned volIndex, const CItem &item) const
332 {
333   FOR_VECTOR (i, item.Extents)
334   {
335     const CMyExtent &e = item.Extents[i];
336     if (!CheckExtent(volIndex, e.PartitionRef, e.Pos, e.GetLen()))
337       return false;
338   }
339   return true;
340 }
341 
Read(unsigned volIndex,unsigned partitionRef,UInt32 blockPos,UInt32 len,Byte * buf)342 HRESULT CInArchive::Read(unsigned volIndex, unsigned partitionRef, UInt32 blockPos, UInt32 len, Byte *buf)
343 {
344   if (!CheckExtent(volIndex, partitionRef, blockPos, len))
345     return S_FALSE;
346   const CLogVol &vol = LogVols[volIndex];
347   const CPartition &partition = Partitions[vol.PartitionMaps[partitionRef].PartitionIndex];
348   UInt64 offset = ((UInt64)partition.Pos << SecLogSize) + (UInt64)blockPos * vol.BlockSize;
349   RINOK(InStream_SeekSet(_stream, offset))
350   offset += len;
351   UpdatePhySize(offset);
352   const HRESULT res = ReadStream_FALSE(_stream, buf, len);
353   if (res == S_FALSE && offset > FileSize)
354     UnexpectedEnd = true;
355   return res;
356 }
357 
ReadLad(unsigned volIndex,const CLongAllocDesc & lad,Byte * buf)358 HRESULT CInArchive::ReadLad(unsigned volIndex, const CLongAllocDesc &lad, Byte *buf)
359 {
360   return Read(volIndex, lad.Location.PartitionRef, lad.Location.Pos, lad.GetLen(), (Byte *)buf);
361 }
362 
ReadFromFile(unsigned volIndex,const CItem & item,CByteBuffer & buf)363 HRESULT CInArchive::ReadFromFile(unsigned volIndex, const CItem &item, CByteBuffer &buf)
364 {
365   if (item.Size >= (UInt32)1 << 30)
366     return S_FALSE;
367   if (item.IsInline)
368   {
369     buf = item.InlineData;
370     return S_OK;
371   }
372   buf.Alloc((size_t)item.Size);
373   size_t pos = 0;
374   FOR_VECTOR (i, item.Extents)
375   {
376     const CMyExtent &e = item.Extents[i];
377     const UInt32 len = e.GetLen();
378     RINOK(Read(volIndex, e.PartitionRef, e.Pos, len, (Byte *)buf + pos))
379     pos += len;
380   }
381   return S_OK;
382 }
383 
384 
Parse(const Byte * p)385 void CIcbTag::Parse(const Byte *p)
386 {
387   // G32 (0, PriorDirectNum);
388   // G16 (4, StrategyType);
389   // G16 (6, StrategyParam);
390   // G16 (8, MaxNumOfEntries);
391   FileType = p[11];
392   // ParentIcb.Parse(p + 12);
393   G16 (18, Flags);
394 }
395 
396 
397 // ECMA 4/14.9 File Entry
398 // UDF FileEntry 2.3.6
399 
400 // ECMA 4/14.17 Extended File Entry
401 
Parse(const Byte * p)402 void CItem::Parse(const Byte *p)
403 {
404   // (-1) can be stored in Uid/Gid.
405   // G32 (36, Uid);
406   // G32 (40, Gid);
407   // G32 (44, Permissions);
408   G16 (48, FileLinkCount);
409   // RecordFormat = p[50];
410   // RecordDisplayAttr = p[51];
411   // G32 (52, RecordLen);
412   G64 (56, Size);
413   if (IsExtended)
414   {
415     // The sum of all Information Length fields for all streams of a file (including the default stream). If this file has no
416     // streams, the Object Size shall be equal to the Information Length.
417     // G64 (64, ObjectSize);
418     p += 8;
419   }
420   G64 (64, NumLogBlockRecorded);
421   ATime.Parse(p + 72);
422   MTime.Parse(p + 84);
423   if (IsExtended)
424   {
425     CreateTime.Parse(p + 96);
426     p += 12;
427   }
428   AttribTime.Parse(p + 96);
429   // G32 (108, CheckPoint);
430   /*
431   if (IsExtended)
432   {
433     // Get32(p + 112); // reserved
434     p += 4;
435   }
436   // ExtendedAttrIcb.Parse(p + 112);
437   if (IsExtended)
438   {
439     StreamDirectoryIcb.Parse(p + 128);
440     p += 16;
441   }
442   */
443 
444   // ImplId.Parse(p + 128);
445   // G64 (160, UniqueId);
446 }
447 
448 
449 // ECMA 4/14.4
450 // UDF 2.3.4
451 
452 /*
453 File Characteristics:
454 Deleted bit:
455   ECMA: If set to ONE, shall mean this File Identifier Descriptor
456         identifies a file that has been deleted;
457   UDF:  If the space for the file or directory is deallocated,
458         the implementation shall set the ICB field to zero.
459     ECMA 167 4/8.6 requires that the File Identifiers of all FIDs in a directory shall be unique.
460     The implementations shall follow these rules when a Deleted bit is set:
461     rewrire the compression ID of the File Identifier: 8 -> 254, 16 -> 255.
462 */
463 
464 struct CFileId
465 {
466   // UInt16 FileVersion;
467   Byte FileCharacteristics;
468   // CByteBuffer ImplUse;
469   CDString Id;
470   CLongAllocDesc Icb;
471 
IsItLink_DirNArchive::NUdf::CFileId472   bool IsItLink_Dir    () const { return (FileCharacteristics & FILEID_CHARACS_Dir)     != 0; }
IsItLink_DeletedNArchive::NUdf::CFileId473   bool IsItLink_Deleted() const { return (FileCharacteristics & FILEID_CHARACS_Deleted) != 0; }
IsItLink_ParentNArchive::NUdf::CFileId474   bool IsItLink_Parent () const { return (FileCharacteristics & FILEID_CHARACS_Parent)  != 0; }
475 
476   size_t Parse(const Byte *p, size_t size);
477 };
478 
Parse(const Byte * p,size_t size)479 size_t CFileId::Parse(const Byte *p, size_t size)
480 {
481   size_t processed = 0;
482   if (size < 38)
483     return 0;
484   CTag tag;
485   if (tag.Parse(p, size) != S_OK)
486     return 0;
487   if (tag.Id != DESC_TYPE_FileId)
488     return 0;
489   // FileVersion = Get16(p + 16);
490   // UDF: There shall be only one version of a file as specified below with the value being set to 1.
491 
492   FileCharacteristics = p[18];
493   const unsigned idLen = p[19];
494   Icb.Parse(p + 20);
495   const unsigned impLen = Get16(p + 36);
496   if (size < 38 + idLen + impLen)
497     return 0;
498   processed = 38;
499   // ImplUse.CopyFrom(p + processed, impLen);
500   processed += impLen;
501   Id.Parse(p + processed, idLen);
502   processed += idLen;
503   for (;(processed & 3) != 0; processed++)
504     if (p[processed] != 0)
505       return 0;
506   if ((size_t)tag.CrcLen + 16 != processed) return 0;
507   return (processed <= size) ? processed : 0;
508 }
509 
510 
511 
ReadFileItem(unsigned volIndex,unsigned fsIndex,const CLongAllocDesc & lad,bool isDir,int numRecurseAllowed)512 HRESULT CInArchive::ReadFileItem(unsigned volIndex, unsigned fsIndex, const CLongAllocDesc &lad, bool isDir, int numRecurseAllowed)
513 {
514   if (Files.Size() % 100 == 0)
515     RINOK(_progress->SetCompleted(Files.Size(), _processedProgressBytes))
516   if (numRecurseAllowed-- == 0)
517     return S_FALSE;
518   CFile &file = Files.Back();
519   const CLogVol &vol = LogVols[volIndex];
520   const unsigned partitionRef = lad.Location.PartitionRef;
521   if (partitionRef >= vol.PartitionMaps.Size())
522     return S_FALSE;
523   CPartition &partition = Partitions[vol.PartitionMaps[partitionRef].PartitionIndex];
524 
525   const UInt32 key = lad.Location.Pos;
526   UInt32 value;
527   const UInt32 kRecursedErrorValue = (UInt32)(Int32)-1;
528   if (partition.Map.Find(key, value))
529   {
530     if (value == kRecursedErrorValue)
531       return S_FALSE;
532     file.ItemIndex = (int)(Int32)value;
533   }
534   else
535   {
536     value = Items.Size();
537     file.ItemIndex = (int)(Int32)value;
538     if (partition.Map.Set(key, kRecursedErrorValue))
539       return S_FALSE;
540     RINOK(ReadItem(volIndex, (int)fsIndex, lad, isDir, numRecurseAllowed))
541     if (!partition.Map.Set(key, value))
542       return S_FALSE;
543   }
544   return S_OK;
545 }
546 
547 
548 // (fsIndex = -1) means that it's metadata file
549 
ReadItem(unsigned volIndex,int fsIndex,const CLongAllocDesc & lad,bool isDir,int numRecurseAllowed)550 HRESULT CInArchive::ReadItem(unsigned volIndex, int fsIndex, const CLongAllocDesc &lad, bool isDir, int numRecurseAllowed)
551 {
552   if (Items.Size() >= kNumItemsMax)
553     return S_FALSE;
554   CItem &item = Items.AddNew();
555 
556   const CLogVol &vol = LogVols[volIndex];
557 
558   const size_t size = lad.GetLen();
559   if (size != vol.BlockSize)
560     return S_FALSE;
561 
562   CByteBuffer buf(size);
563   RINOK(ReadLad(volIndex, lad, buf))
564 
565   CTag tag;
566   const Byte *p = buf;
567   RINOK(tag.Parse(p, size))
568 
569   item.IsExtended = (tag.Id == DESC_TYPE_ExtendedFile);
570   const size_t kExtendOffset = item.IsExtended ? 40 : 0;
571 
572   if (size < kExtendOffset + 176)
573     return S_FALSE;
574   if (tag.Id != DESC_TYPE_File &&
575       tag.Id != DESC_TYPE_ExtendedFile)
576     return S_FALSE;
577 
578   item.IcbTag.Parse(p + 16);
579 
580   if (fsIndex < 0)
581   {
582     if (item.IcbTag.FileType != ICB_FILE_TYPE_METADATA &&
583         item.IcbTag.FileType != ICB_FILE_TYPE_METADATA_MIRROR)
584       return S_FALSE;
585   }
586   else if (
587       item.IcbTag.FileType != ICB_FILE_TYPE_DIR &&
588       item.IcbTag.FileType != ICB_FILE_TYPE_FILE)
589     return S_FALSE;
590 
591   item.Parse(p);
592 
593   _processedProgressBytes += (UInt64)item.NumLogBlockRecorded * vol.BlockSize + size;
594 
595   const UInt32 extendedAttrLen = Get32(p + 168 + kExtendOffset);
596   const UInt32 allocDescriptorsLen = Get32(p + 172 + kExtendOffset);
597 
598   if ((extendedAttrLen & 3) != 0)
599     return S_FALSE;
600   size_t pos = 176 + kExtendOffset;
601   if (extendedAttrLen > size - pos)
602     return S_FALSE;
603   /*
604   if (extendedAttrLen != 16)
605   {
606     if (extendedAttrLen < 24)
607       return S_FALSE;
608     CTag attrTag;
609     RINOK(attrTag.Parse(p + pos, size));
610     if (attrTag.Id != DESC_TYPE_ExtendedAttrHeader)
611       return S_FALSE;
612     // UInt32 implAttrLocation = Get32(p + pos + 16);
613     // UInt32 applicationlAttrLocation = Get32(p + pos + 20);
614   }
615   */
616   pos += extendedAttrLen;
617 
618   const int descType = item.IcbTag.GetDescriptorType();
619   if (allocDescriptorsLen > size - pos)
620     return S_FALSE;
621   if (descType == ICB_DESC_TYPE_INLINE)
622   {
623     item.IsInline = true;
624     item.InlineData.CopyFrom(p + pos, allocDescriptorsLen);
625   }
626   else
627   {
628     item.IsInline = false;
629     if (descType != ICB_DESC_TYPE_SHORT && descType != ICB_DESC_TYPE_LONG)
630       return S_FALSE;
631     for (UInt32 i = 0; i < allocDescriptorsLen;)
632     {
633       CMyExtent e;
634       if (descType == ICB_DESC_TYPE_SHORT)
635       {
636         if (i + 8 > allocDescriptorsLen)
637           return S_FALSE;
638         CShortAllocDesc sad;
639         sad.Parse(p + pos + i);
640         e.Pos = sad.Pos;
641         e.Len = sad.Len;
642         e.PartitionRef = lad.Location.PartitionRef;
643         i += 8;
644       }
645       else
646       {
647         if (i + 16 > allocDescriptorsLen)
648           return S_FALSE;
649         CLongAllocDesc ladNew;
650         ladNew.Parse(p + pos + i);
651         e.Pos = ladNew.Location.Pos;
652         e.PartitionRef = ladNew.Location.PartitionRef;
653         e.Len = ladNew.Len;
654         i += 16;
655       }
656       item.Extents.Add(e);
657     }
658   }
659 
660   if (isDir != item.IcbTag.IsDir())
661     return S_FALSE;
662 
663   if (item.IcbTag.IsDir())
664   {
665     if (fsIndex < 0)
666       return S_FALSE;
667 
668     if (!item.CheckChunkSizes() || !CheckItemExtents(volIndex, item))
669       return S_FALSE;
670     CByteBuffer buf2;
671     RINOK(ReadFromFile(volIndex, item, buf2))
672     item.Size = 0;
673     item.Extents.ClearAndFree();
674     item.InlineData.Free();
675 
676     const Byte *p2 = buf2;
677     size_t size2 = buf2.Size();
678     while (size2 != 0)
679     {
680       CFileId fileId;
681       {
682         const size_t cur = fileId.Parse(p2, size2);
683         if (cur == 0)
684           return S_FALSE;
685         p2 += cur;
686         size2 -= cur;
687       }
688       if (fileId.IsItLink_Parent())
689         continue;
690       if (fileId.IsItLink_Deleted())
691         continue;
692       {
693         CFile file;
694         // file.FileVersion = fileId.FileVersion;
695         // file.FileCharacteristics = fileId.FileCharacteristics;
696         // file.ImplUse = fileId.ImplUse;
697         file.Id = fileId.Id;
698 
699         _fileNameLengthTotal += file.Id.Data.Size();
700         if (_fileNameLengthTotal > kFileNameLengthTotalMax)
701           return S_FALSE;
702 
703         item.SubFiles.Add(Files.Size());
704         if (Files.Size() >= kNumFilesMax)
705           return S_FALSE;
706         Files.Add(file);
707         RINOK(ReadFileItem(volIndex, (unsigned)fsIndex, fileId.Icb,
708             fileId.IsItLink_Dir(), numRecurseAllowed))
709       }
710     }
711   }
712   else
713   {
714     if ((UInt32)item.Extents.Size() > kNumExtentsMax - _numExtents)
715       return S_FALSE;
716     _numExtents += item.Extents.Size();
717 
718     if (item.InlineData.Size() > kInlineExtentsSizeMax - _inlineExtentsSize)
719       return S_FALSE;
720     _inlineExtentsSize += item.InlineData.Size();
721   }
722 
723   return S_OK;
724 }
725 
726 
FillRefs(CFileSet & fs,unsigned fileIndex,int parent,int numRecurseAllowed)727 HRESULT CInArchive::FillRefs(CFileSet &fs, unsigned fileIndex, int parent, int numRecurseAllowed)
728 {
729   if ((_numRefs & 0xFFF) == 0)
730   {
731     RINOK(_progress->SetCompleted())
732   }
733   if (numRecurseAllowed-- == 0)
734     return S_FALSE;
735   if (_numRefs >= kNumRefsMax)
736     return S_FALSE;
737   _numRefs++;
738   CRef ref;
739   ref.FileIndex = fileIndex;
740   ref.Parent = parent;
741   parent = (int)fs.Refs.Size();
742   fs.Refs.Add(ref);
743   const CItem &item = Items[Files[fileIndex].ItemIndex];
744   FOR_VECTOR (i, item.SubFiles)
745   {
746     RINOK(FillRefs(fs, item.SubFiles[i], parent, numRecurseAllowed))
747   }
748   return S_OK;
749 }
750 
751 
IsArc_Udf(const Byte * p,size_t size)752 API_FUNC_IsArc IsArc_Udf(const Byte *p, size_t size)
753 {
754   UInt32 res = k_IsArc_Res_NO;
755   unsigned SecLogSize;
756   for (SecLogSize = 11;; SecLogSize -= 2)
757   {
758     if (SecLogSize < 9)
759       return res;
760     const UInt32 offset = (UInt32)256 << SecLogSize;
761     const UInt32 bufSize = (UInt32)1 << SecLogSize;
762     if (offset + bufSize > size)
763       res = k_IsArc_Res_NEED_MORE;
764     else
765     {
766       CTag tag;
767       if (tag.Parse(p + offset, bufSize) == S_OK)
768         if (tag.Id == DESC_TYPE_AnchorVolPtr)
769         {
770           if (Get32(p + offset + 12) == 256 &&  // TagLocation
771               tag.CrcLen >= 16)
772             return k_IsArc_Res_YES;
773         }
774     }
775   }
776 }
777 
778 
Open2()779 HRESULT CInArchive::Open2()
780 {
781   Clear();
782   UInt64 fileSize;
783   RINOK(InStream_GetSize_SeekToEnd(_stream, fileSize))
784   FileSize = fileSize;
785 
786   // Some UDFs contain additional pad zeros (2 KB).
787   // Seek to STREAM_SEEK_END for direct DVD reading can return 8 KB more, so we check last 16 KB.
788   // And when we read last block, result read size can be smaller than required size.
789 
790   /*
791   const size_t kBufSize = 1 << 14;
792   Byte buf[kBufSize];
793   size_t readSize = (fileSize < kBufSize) ? (size_t)fileSize : kBufSize;
794   RINOK(InStream_SeekSet(_stream, fileSize - readSize))
795   RINOK(ReadStream(_stream, buf, &readSize));
796   size_t i = readSize;
797   for (;;)
798   {
799     const size_t kSecSizeMin = 1 << 8;
800     if (i < kSecSizeMin)
801       return S_FALSE;
802     i -= kSecSizeMin;
803     SecLogSize = (readSize - i < ((size_t)1 << 11)) ? 8 : 11;
804     CTag tag;
805     if (tag.Parse(buf + i, (1 << SecLogSize)) == S_OK)
806       if (tag.Id == DESC_TYPE_AnchorVolPtr)
807         break;
808   }
809   PhySize = fileSize;
810   CExtent extentVDS;
811   extentVDS.Parse(buf + i + 16);
812   */
813 
814   /*
815   An Anchor Volume Descriptor Pointer structure shall be recorded in at
816   least 2 of the following 3 locations on the media:
817       Logical Sector 256.
818       Logical Sector (N - 256).
819       N
820   */
821 
822   const size_t kBufSize = 1 << 11;
823   Byte buf[kBufSize];
824 
825   for (SecLogSize = 11;; SecLogSize -= 2)
826   {
827     // Windows 10 uses unusual (SecLogSize = 9)
828     if (SecLogSize < 9)
829       return S_FALSE;
830     const UInt32 offset = (UInt32)256 << SecLogSize;
831     if (offset >= fileSize)
832       continue;
833     RINOK(InStream_SeekSet(_stream, offset))
834     const size_t bufSize = (size_t)1 << SecLogSize;
835     size_t readSize = bufSize;
836     RINOK(ReadStream(_stream, buf, &readSize))
837     if (readSize == bufSize)
838     {
839       CTag tag;
840       if (tag.Parse(buf, readSize) == S_OK)
841         if (tag.Id == DESC_TYPE_AnchorVolPtr)
842         {
843           if (Get32(buf + 12) == 256 &&
844             tag.CrcLen >= 16) // TagLocation
845             break;
846         }
847     }
848   }
849 
850   PhySize = (UInt32)(256 + 1) << SecLogSize;
851   IsArc = true;
852 
853   // UDF 2.2.3  AnchorVolumeDescriptorPointer
854 
855   CExtent extentVDS;
856   extentVDS.Parse(buf + 16);
857   {
858     CExtent extentVDS2;
859     extentVDS2.Parse(buf + 24);
860     UpdatePhySize(extentVDS);
861     UpdatePhySize(extentVDS2);
862   }
863 
864   for (UInt32 location = 0; ; location++)
865   {
866     if (location >= (extentVDS.Len >> SecLogSize))
867       return S_FALSE;
868 
869     const size_t bufSize = (size_t)1 << SecLogSize;
870     {
871       const UInt64 offs = ((UInt64)extentVDS.Pos + location) << SecLogSize;
872       RINOK(InStream_SeekSet(_stream, offs))
873       const HRESULT res = ReadStream_FALSE(_stream, buf, bufSize);
874       if (res == S_FALSE && offs + bufSize > FileSize)
875         UnexpectedEnd = true;
876       RINOK(res)
877     }
878 
879     CTag tag;
880     RINOK(tag.Parse(buf, bufSize))
881 
882     if (tag.Id == DESC_TYPE_Terminating)
883       break;
884 
885     if (tag.Id == DESC_TYPE_PrimVol)
886     {
887       CPrimeVol &pm = PrimeVols.AddNew();
888       pm.Parse(buf);
889       continue;
890     }
891 
892     if (tag.Id == DESC_TYPE_Partition)
893     {
894       // Partition Descriptor
895       // ECMA 3/10.5
896       // UDF 2.2.14
897       if (Partitions.Size() >= kNumPartitionsMax)
898         return S_FALSE;
899       CPartition partition;
900       // const UInt32 volDescSeqNumer = Get32(buf + 16);
901       partition.Flags = Get16(buf + 20);
902       partition.Number = Get16(buf + 22);
903       partition.ContentsId.Parse(buf + 24);
904 
905       // memcpy(partition.ContentsUse, buf + 56, sizeof(partition.ContentsUse));
906       // ContentsUse contains Partition Header Description.
907       // ECMA 4/14.3
908       // UDF PartitionHeaderDescriptor 2.3.3
909 
910       partition.AccessType = Get32(buf + 184);
911       partition.Pos = Get32(buf + 188);
912       partition.Len = Get32(buf + 192);
913       partition.ImplId.Parse(buf + 196);
914       // memcpy(partition.ImplUse, buf + 228, sizeof(partition.ImplUse));
915 
916       PRF(printf("\nPartition number = %2d   pos = %d   len = %d", partition.Number, partition.Pos, partition.Len));
917       Partitions.Add(partition);
918       continue;
919     }
920 
921     if (tag.Id == DESC_TYPE_LogicalVol)
922     {
923       /* Logical Volume Descriptor
924           ECMA 3/10.6
925           UDF 2.60 2.2.4 */
926 
927       if (LogVols.Size() >= kNumLogVolumesMax)
928         return S_FALSE;
929       CLogVol &vol = LogVols.AddNew();
930 
931       vol.Id.Parse(buf + 84);
932       vol.BlockSize = Get32(buf + 212);
933       if (vol.BlockSize != ((UInt32)1 << SecLogSize))
934       {
935         // UDF 2.2.4.2 LogicalBlockSize
936         // UDF probably doesn't allow different sizes
937         return S_FALSE;
938       }
939       /*
940       if (vol.BlockSize < 512 || vol.BlockSize > ((UInt32)1 << 30))
941         return S_FALSE;
942       */
943 
944       vol.DomainId.Parse(buf + 216);
945 
946       // ECMA 4/3.1
947       // UDF 2.2.4.4 LogicalVolumeContentsUse
948       /* the extent in which the first File Set Descriptor Sequence
949          of the logical volume is recorded */
950       vol.FileSetLocation.Parse(buf + 248);
951       // memcpy(vol.ContentsUse, buf + 248, sizeof(vol.ContentsUse));
952 
953       vol.ImplId.Parse(buf + 272);
954       // memcpy(vol.ImplUse, buf + 304, sizeof(vol.ImplUse));
955       // vol.IntegritySequenceExtent.Parse(buf + 432);
956 
957       const UInt32 mapTableLen = Get32(buf + 264);
958       const UInt32 numPartitionMaps = Get32(buf + 268);
959       if (numPartitionMaps > kNumPartitionsMax)
960         return S_FALSE;
961 
962       PRF(printf("\nLogicalVol numPartitionMaps = %2d", numPartitionMaps));
963 
964       size_t pos = 440;
965       if (mapTableLen > bufSize - pos)
966         return S_FALSE;
967       const size_t posLimit = pos + mapTableLen;
968 
969       for (UInt32 i = 0; i < numPartitionMaps; i++)
970       {
971         // ECMA 3/10.7 Partition maps
972         if (pos + 2 > posLimit)
973           return S_FALSE;
974         CPartitionMap pm;
975         pm.Type = buf[pos + 0];
976         // pm.Length = buf[pos + 1];
977         const Byte len = buf[pos + 1];
978         if (pos + len > posLimit)
979           return S_FALSE;
980 
981         // memcpy(pm.Data, buf + pos + 2, pm.Length - 2);
982         if (pm.Type == 1)
983         {
984           // ECMA 3/10.7.2
985           if (len != 6)
986             return S_FALSE;
987           pm.VolumeSequenceNumber = Get16(buf + pos + 2);
988           pm.PartitionNumber = Get16(buf + pos + 4);
989           PRF(printf("\nPartitionMap type 1 PartitionNumber = %2d", pm.PartitionNumber));
990         }
991         else if (pm.Type == 2)
992         {
993           if (len != 64)
994             return S_FALSE;
995           /* ECMA 10.7.3 / Type 2 Partition Map
996              62 bytes: Partition Identifier. */
997 
998           /* UDF
999               2.2.8   "*UDF Virtual Partition"
1000               2.2.9   "*UDF Sparable Partition"
1001               2.2.10  "*UDF Metadata Partition"
1002           */
1003 
1004           if (Get16(buf + pos + 2) != 0) // reserved
1005             return S_FALSE;
1006 
1007           pm.PartitionTypeId.Parse(buf + pos + 4);
1008           pm.VolumeSequenceNumber = Get16(buf + pos + 36);
1009           pm.PartitionNumber = Get16(buf + pos + 38);
1010 
1011           if (memcmp(pm.PartitionTypeId.Id, "*UDF Metadata Partition", 23) != 0)
1012             return S_FALSE;
1013 
1014           // UDF 2.2.10 Metadata Partition Map
1015           pm.MetadataFileLocation = Get32(buf + pos + 40);
1016           // pm.MetadataMirrorFileLocation = Get32(buf + pos + 44);
1017           // pm.MetadataBitmapFileLocation = Get32(buf + pos + 48);
1018           // pm.AllocationUnitSize = Get32(buf + pos + 52);
1019           // pm.AlignmentUnitSize = Get16(buf + pos + 56);
1020           // pm.Flags = buf[pos + 58];
1021 
1022           PRF(printf("\nPartitionMap type 2 PartitionNumber = %2d", pm.PartitionNumber));
1023           // Unsupported = true;
1024           // return S_FALSE;
1025         }
1026         else
1027           return S_FALSE;
1028         pos += len;
1029         vol.PartitionMaps.Add(pm);
1030       }
1031       continue;
1032     }
1033 
1034     /*
1035     if (tag.Id == DESC_TYPE_UnallocSpace)
1036     {
1037       // UInt32 volDescSeqNumer = Get32(buf + 16);
1038       const UInt32 numAlocDescs = Get32(buf + 20);
1039       // we need examples for (numAlocDescs != 0) case
1040       if (numAlocDescs > (bufSize - 24) / 8)
1041         return S_FALSE;
1042       for (UInt32 i = 0; i < numAlocDescs; i++)
1043       {
1044         CExtent e;
1045         e.Parse(buf + 24 + i * 8);
1046       }
1047       continue;
1048     }
1049     else
1050       continue;
1051     */
1052   }
1053 
1054   UInt64 totalSize = 0;
1055 
1056   unsigned volIndex;
1057   for (volIndex = 0; volIndex < LogVols.Size(); volIndex++)
1058   {
1059     CLogVol &vol = LogVols[volIndex];
1060     FOR_VECTOR (pmIndex, vol.PartitionMaps)
1061     {
1062       CPartitionMap &pm = vol.PartitionMaps[pmIndex];
1063       for (unsigned i = 0;; i++)
1064       {
1065         if (i == Partitions.Size())
1066           return S_FALSE;
1067         CPartition &part = Partitions[i];
1068         if (part.Number == pm.PartitionNumber)
1069         {
1070           pm.PartitionIndex = i;
1071           if (pm.Type == 2)
1072             break;
1073 
1074           /*
1075           if (part.VolIndex >= 0)
1076           {
1077             // it's for 2.60. Fix it
1078             if (part.VolIndex != (int)volIndex)
1079               return S_FALSE;
1080             // return S_FALSE;
1081           }
1082           part.VolIndex = volIndex;
1083           */
1084 
1085           totalSize += (UInt64)part.Len << SecLogSize;
1086           break;
1087         }
1088       }
1089     }
1090   }
1091 
1092   for (volIndex = 0; volIndex < LogVols.Size(); volIndex++)
1093   {
1094     CLogVol &vol = LogVols[volIndex];
1095     FOR_VECTOR (pmIndex, vol.PartitionMaps)
1096     {
1097       CPartitionMap &pm = vol.PartitionMaps[pmIndex];
1098       if (pm.Type != 2)
1099         continue;
1100 
1101       {
1102         CLongAllocDesc lad;
1103         lad.Len = vol.BlockSize;
1104         lad.Location.Pos = pm.MetadataFileLocation;
1105         // lad.Location.Pos = pm.MetadataMirrorFileLocation;
1106 
1107         lad.Location.PartitionRef = (UInt16)pmIndex;
1108 
1109         /* we need correct PartitionMaps[lad.Location.PartitionRef].PartitionIndex.
1110            so we can use pmIndex or find (Type==1) PartitionMap */
1111         FOR_VECTOR (pmIndex2, vol.PartitionMaps)
1112         {
1113           const CPartitionMap &pm2 = vol.PartitionMaps[pmIndex2];
1114           if (pm2.PartitionNumber == pm.PartitionNumber && pm2.Type == 1)
1115           {
1116             lad.Location.PartitionRef = (UInt16)pmIndex2;
1117             break;
1118           }
1119         }
1120 
1121         RINOK(ReadItem(volIndex,
1122             -1, // (fsIndex = -1) means that it's metadata
1123             lad,
1124             false, // isDir
1125             1)) // numRecurseAllowed
1126       }
1127       {
1128         const CItem &item = Items.Back();
1129         if (!CheckItemExtents(volIndex, item))
1130           return S_FALSE;
1131         if (item.Extents.Size() != 1)
1132         {
1133           if (item.Extents.Size() < 1)
1134             return S_FALSE;
1135           /* Windows 10 writes empty record item.Extents[1].
1136              we ignore such extent here */
1137           for (unsigned k = 1; k < item.Extents.Size(); k++)
1138           {
1139             const CMyExtent &e = item.Extents[k];
1140             if (e.GetLen() != 0)
1141               return S_FALSE;
1142           }
1143         }
1144 
1145         const CMyExtent &e = item.Extents[0];
1146         const CPartition &part = Partitions[pm.PartitionIndex];
1147         CPartition mp = part;
1148         mp.IsMetadata = true;
1149         // mp.Number = part.Number;
1150         mp.Pos = part.Pos + e.Pos;
1151         mp.Len = e.Len >> SecLogSize;
1152         pm.PartitionIndex = Partitions.Add(mp);
1153       }
1154       // Items.DeleteBack(); // we can delete that metadata item
1155 
1156       /*
1157       // short version of code to read metadata file.
1158       RINOK(CInArchive::Read(volIndex, pmIndex, pm.MetadataFileLocation, 224, buf));
1159       CTag tag;
1160       RINOK(tag.Parse(buf, 224));
1161       if (tag.Id != DESC_TYPE_ExtendedFile)
1162         return S_FALSE;
1163       CShortAllocDesc sad;
1164       sad.Parse(buf + 216);
1165       const CPartition &part = Partitions[pm.PartitionIndex];
1166       CPartition mp = part;
1167       mp.IsMetadata = true;
1168       // mp.Number = part.Number;
1169       mp.Pos = part.Pos + sad.Pos;
1170       mp.Len = sad.Len >> SecLogSize;
1171       pm.PartitionIndex = Partitions.Add(mp);
1172       */
1173     }
1174   }
1175 
1176   RINOK(_progress->SetTotal(totalSize))
1177 
1178   PRF(printf("\n Read files"));
1179 
1180   for (volIndex = 0; volIndex < LogVols.Size(); volIndex++)
1181   {
1182     CLogVol &vol = LogVols[volIndex];
1183 
1184     PRF(printf("\nLogVol %2d", volIndex));
1185 
1186     CLongAllocDesc nextExtent = vol.FileSetLocation;
1187     // while (nextExtent.ExtentLen != 0)
1188     // for (int i = 0; i < 1; i++)
1189     {
1190       if (nextExtent.GetLen() < 512)
1191         return S_FALSE;
1192       CByteBuffer buf2(nextExtent.GetLen());
1193       RINOK(ReadLad(volIndex, nextExtent, buf2))
1194       const Byte *p = buf2;
1195       const size_t size = nextExtent.GetLen();
1196 
1197       CTag tag;
1198       RINOK(tag.Parse(p, size))
1199 
1200       /*
1201       // commented in 22.01
1202       if (tag.Id == DESC_TYPE_ExtendedFile)
1203       {
1204         // ECMA 4 / 14.17
1205         // 2.60 ??
1206         return S_FALSE;
1207       }
1208       */
1209 
1210       if (tag.Id != DESC_TYPE_FileSet)
1211         return S_FALSE;
1212 
1213       PRF(printf("\n FileSet", volIndex));
1214       CFileSet fs;
1215       fs.RecordingTime.Parse(p + 16);
1216       // fs.InterchangeLevel = Get16(p + 18);
1217       // fs.MaxInterchangeLevel = Get16(p + 20);
1218       fs.FileSetNumber = Get32(p + 40);
1219       fs.FileSetDescNumber = Get32(p + 44);
1220 
1221       fs.LogicalVolumeId.Parse(p + 112);
1222       fs.Id.Parse(p + 304);
1223       fs.CopyrightId.Parse(p + 336);
1224       fs.AbstractId.Parse(p + 368);
1225 
1226       fs.RootDirICB.Parse(p + 400);
1227       fs.DomainId.Parse(p + 416);
1228 
1229       // fs.SystemStreamDirICB.Parse(p + 464);
1230 
1231       vol.FileSets.Add(fs);
1232 
1233       // nextExtent.Parse(p + 448);
1234     }
1235 
1236     FOR_VECTOR (fsIndex, vol.FileSets)
1237     {
1238       CFileSet &fs = vol.FileSets[fsIndex];
1239       const unsigned fileIndex = Files.Size();
1240       Files.AddNew();
1241       RINOK(ReadFileItem(volIndex, fsIndex, fs.RootDirICB,
1242           true, // isDir
1243           kNumRecursionLevelsMax))
1244       RINOK(FillRefs(fs, fileIndex, -1, kNumRecursionLevelsMax))
1245     }
1246   }
1247 
1248 
1249   for (volIndex = 0; volIndex < LogVols.Size(); volIndex++)
1250   {
1251     const CLogVol &vol = LogVols[volIndex];
1252     // bool showFileSetName = (vol.FileSets.Size() > 1);
1253     FOR_VECTOR (fsIndex, vol.FileSets)
1254     {
1255       const CFileSet &fs = vol.FileSets[fsIndex];
1256       for (unsigned i =
1257           // ((showVolName || showFileSetName) ? 0 : 1)
1258             0; i < fs.Refs.Size(); i++)
1259       {
1260         const CRef &ref = vol.FileSets[fsIndex].Refs[i];
1261         const CFile &file = Files[ref.FileIndex];
1262         const CItem &item = Items[file.ItemIndex];
1263         UInt64 size = item.Size;
1264 
1265         if (!item.IsRecAndAlloc() || !item.CheckChunkSizes() || !CheckItemExtents(volIndex, item))
1266           continue;
1267 
1268         FOR_VECTOR (extentIndex, item.Extents)
1269         {
1270           const CMyExtent &extent = item.Extents[extentIndex];
1271           const UInt32 len = extent.GetLen();
1272           if (len == 0)
1273             continue;
1274           if (size < len)
1275             break;
1276 
1277           const unsigned partitionIndex = vol.PartitionMaps[extent.PartitionRef].PartitionIndex;
1278           const UInt32 logBlockNumber = extent.Pos;
1279           const CPartition &partition = Partitions[partitionIndex];
1280           const UInt64 offset = ((UInt64)partition.Pos << SecLogSize) +
1281               (UInt64)logBlockNumber * vol.BlockSize;
1282           UpdatePhySize(offset + len);
1283         }
1284       }
1285     }
1286   }
1287 
1288   {
1289     const UInt32 secMask = ((UInt32)1 << SecLogSize) - 1;
1290     PhySize = (PhySize + secMask) & ~(UInt64)secMask;
1291   }
1292 
1293   NoEndAnchor = true;
1294 
1295   if (PhySize < fileSize)
1296   {
1297     UInt64 rem = fileSize - PhySize;
1298     const size_t secSize = (size_t)1 << SecLogSize;
1299 
1300     RINOK(InStream_SeekSet(_stream, PhySize))
1301 
1302     // some UDF images contain ZEROs before "Anchor Volume Descriptor Pointer" at the end
1303 
1304     for (unsigned sec = 0; sec < 1024; sec++)
1305     {
1306       if (rem == 0)
1307         break;
1308 
1309       size_t readSize = secSize;
1310       if (readSize > rem)
1311         readSize = (size_t)rem;
1312 
1313       RINOK(ReadStream(_stream, buf, &readSize))
1314 
1315       if (readSize == 0)
1316         break;
1317 
1318       // some udf contain many EndAnchors
1319       if (readSize == secSize /* && NoEndAnchor */)
1320       {
1321         CTag tag;
1322         if (tag.Parse(buf, readSize) == S_OK
1323             && tag.Id == DESC_TYPE_AnchorVolPtr
1324             && Get32(buf + 12) == (UInt32)((fileSize - rem) >> SecLogSize))
1325         {
1326           NoEndAnchor = false;
1327           rem -= readSize;
1328           PhySize = fileSize - rem;
1329           continue;
1330         }
1331       }
1332 
1333       size_t i;
1334       for (i = 0; i < readSize && buf[i] == 0; i++);
1335       if (i != readSize)
1336         break;
1337       rem -= readSize;
1338     }
1339 
1340     if (rem == 0)
1341       PhySize = fileSize;
1342   }
1343 
1344   return S_OK;
1345 }
1346 
1347 
Open(IInStream * inStream,CProgressVirt * progress)1348 HRESULT CInArchive::Open(IInStream *inStream, CProgressVirt *progress)
1349 {
1350   _progress = progress;
1351   _stream = inStream;
1352   HRESULT res = Open2();
1353   if (res == S_FALSE && IsArc && !UnexpectedEnd)
1354     Unsupported = true;
1355   return res;
1356 
1357   /*
1358   HRESULT res;
1359   try
1360   {
1361     res = Open2();
1362   }
1363   catch(...)
1364   {
1365     // Clear();
1366     // res = S_FALSE;
1367     _stream.Release();
1368     throw;
1369   }
1370   _stream.Release();
1371   return res;
1372   */
1373 }
1374 
Clear()1375 void CInArchive::Clear()
1376 {
1377   IsArc = false;
1378   Unsupported = false;
1379   UnexpectedEnd = false;
1380   NoEndAnchor = false;
1381 
1382   PhySize = 0;
1383   FileSize = 0;
1384 
1385   Partitions.Clear();
1386   LogVols.Clear();
1387   PrimeVols.Clear();
1388   Items.Clear();
1389   Files.Clear();
1390   _fileNameLengthTotal = 0;
1391   _numRefs = 0;
1392   _numExtents = 0;
1393   _inlineExtentsSize = 0;
1394   _processedProgressBytes = 0;
1395 }
1396 
1397 
1398 static const char * const g_PartitionTypes[] =
1399 {
1400     "Pseudo-Overwritable" // UDF
1401   , "Read-Only"
1402   , "Write-Once"
1403   , "Rewritable"
1404   , "Overwritable"
1405 };
1406 
1407 
AddComment_Align(UString & s)1408 static void AddComment_Align(UString &s)
1409 {
1410   s += "  ";
1411 }
1412 
AddComment_PropName(UString & s,const char * name)1413 static void AddComment_PropName(UString &s, const char *name)
1414 {
1415   AddComment_Align(s);
1416   s += name;
1417   s += ": ";
1418 }
1419 
AddComment_UInt32(UString & s,const char * name,UInt32 val)1420 static void AddComment_UInt32(UString &s, const char *name, UInt32 val)
1421 {
1422   AddComment_PropName(s, name);
1423   s.Add_UInt32(val);
1424   s.Add_LF();
1425 }
1426 
AddComment_UInt32_2(UString & s,const char * name,UInt32 val)1427 static void AddComment_UInt32_2(UString &s, const char *name, UInt32 val)
1428 {
1429   AddComment_Align(s);
1430   AddComment_UInt32(s, name, val);
1431 }
1432 
1433 
AddComment_UInt64(UString & s,const char * name,UInt64 val)1434 static void AddComment_UInt64(UString &s, const char *name, UInt64 val)
1435 {
1436   AddComment_PropName(s, name);
1437   s.Add_UInt64(val);
1438   s.Add_LF();
1439 }
1440 
AddComment_RegId(UString & s,const char * name,const CRegId & ri)1441 static void AddComment_RegId(UString &s, const char *name, const CRegId &ri)
1442 {
1443   AddComment_PropName(s, name);
1444   ri.AddCommentTo(s);
1445   s.Add_LF();
1446 }
1447 
AddComment_RegId_Domain(UString & s,const char * name,const CRegId & ri)1448 static void AddComment_RegId_Domain(UString &s, const char *name, const CRegId &ri)
1449 {
1450   AddComment_PropName(s, name);
1451   ri.AddCommentTo(s);
1452   {
1453     UString s2;
1454     ri.AddUdfVersionTo(s2);
1455     if (!s2.IsEmpty())
1456     {
1457       s += "::";
1458       s += s2;
1459     }
1460   }
1461   s.Add_LF();
1462 }
1463 
1464 
1465 // UDF 6.3.1 OS Class
1466 
1467 static const char * const g_OsClasses[] =
1468 {
1469     NULL
1470   , "DOS"
1471   , "OS/2"
1472   , "Macintosh OS"
1473   , "UNIX"
1474   , "Windows 9x"
1475   , "Windows NT"
1476   , "OS/400"
1477   , "BeOS"
1478   , "Windows CE"
1479 };
1480 
1481 // UDF 6.3.2 OS Identifier
1482 
1483 static const char * const g_OsIds_Unix[] =
1484 {
1485     NULL // "Generic"
1486   , "AIX"
1487   , "SUN OS / Solaris"
1488   , "HP/UX"
1489   , "Silicon Graphics Irix"
1490   , "Linux"
1491   , "MKLinux"
1492   , "FreeBSD"
1493   , "NetBSD"
1494 };
1495 
AddOs_Class_Id(UString & s,const Byte * p)1496 static void AddOs_Class_Id(UString &s, const Byte *p)
1497 {
1498   // UDF 2.1.5.3 Implementation Identifier Suffix
1499   // Appendix 6.3 Operating System Identifiers.
1500   const Byte osClass = p[0];
1501   if (osClass != 0)
1502   {
1503     s += "::";
1504     s += TypeToString(g_OsClasses, Z7_ARRAY_SIZE(g_OsClasses), osClass);
1505   }
1506   const Byte osId = p[1];
1507   if (osId != 0)
1508   {
1509     s += "::";
1510     if (osClass == 4) // unix
1511     {
1512       s += TypeToString(g_OsIds_Unix, Z7_ARRAY_SIZE(g_OsIds_Unix), osId);
1513     }
1514     else
1515       s.Add_UInt32(osId);
1516   }
1517 }
1518 
1519 
AddComment_RegId_Impl(UString & s,const char * name,const CRegId & ri)1520 static void AddComment_RegId_Impl(UString &s, const char *name, const CRegId &ri)
1521 {
1522   AddComment_PropName(s, name);
1523   ri.AddCommentTo(s);
1524   {
1525     AddOs_Class_Id(s, ri.Suffix);
1526   }
1527   s.Add_LF();
1528 }
1529 
1530 
AddComment_RegId_UdfId(UString & s,const char * name,const CRegId & ri)1531 static void AddComment_RegId_UdfId(UString &s, const char *name, const CRegId &ri)
1532 {
1533   AddComment_PropName(s, name);
1534   ri.AddCommentTo(s);
1535   {
1536     // UDF 2.1.5.3
1537     // UDF Identifier Suffix format
1538     UString s2;
1539     ri.AddUdfVersionTo(s2);
1540     if (!s2.IsEmpty())
1541     {
1542       s += "::";
1543       s += s2;
1544     }
1545     AddOs_Class_Id(s, &ri.Suffix[2]);
1546   }
1547   s.Add_LF();
1548 }
1549 
AddComment_DString32(UString & s,const char * name,const CDString32 & d)1550 static void AddComment_DString32(UString &s, const char *name, const CDString32 &d)
1551 {
1552   AddComment_Align(s);
1553   AddComment_PropName(s, name);
1554   s += d.GetString();
1555   s.Add_LF();
1556 }
1557 
GetComment() const1558 UString CInArchive::GetComment() const
1559 {
1560   UString s;
1561   {
1562     s += "Primary Volumes:";
1563     s.Add_LF();
1564     FOR_VECTOR (i, PrimeVols)
1565     {
1566       if (i != 0)
1567         s.Add_LF();
1568       const CPrimeVol &pv = PrimeVols[i];
1569       // AddComment_UInt32(s, "VolumeDescriptorSequenceNumber", pv.VolumeDescriptorSequenceNumber);
1570       // if (PrimeVols.Size() != 1 || pv.PrimaryVolumeDescriptorNumber != 0)
1571         AddComment_UInt32(s, "PrimaryVolumeDescriptorNumber", pv.PrimaryVolumeDescriptorNumber);
1572       // if (pv.MaximumVolumeSequenceNumber != 1 || pv.VolumeSequenceNumber != 1)
1573         AddComment_UInt32(s, "VolumeSequenceNumber", pv.VolumeSequenceNumber);
1574       if (pv.MaximumVolumeSequenceNumber != 1)
1575         AddComment_UInt32(s, "MaximumVolumeSequenceNumber", pv.MaximumVolumeSequenceNumber);
1576       AddComment_PropName(s, "VolumeId");
1577       s += pv.VolumeId.GetString();
1578       s.Add_LF();
1579       AddComment_PropName(s, "VolumeSetId");
1580       s += pv.VolumeSetId.GetString();
1581       s.Add_LF();
1582       // AddComment_UInt32(s, "InterchangeLevel", pv.InterchangeLevel);
1583       // AddComment_UInt32(s, "MaximumInterchangeLevel", pv.MaximumInterchangeLevel);
1584       AddComment_RegId(s, "ApplicationId", pv.ApplicationId);
1585       AddComment_RegId_Impl(s, "ImplementationId", pv.ImplId);
1586     }
1587   }
1588   {
1589     s += "Partitions:";
1590     s.Add_LF();
1591     FOR_VECTOR (i, Partitions)
1592     {
1593       if (i != 0)
1594         s.Add_LF();
1595       const CPartition &part = Partitions[i];
1596       AddComment_UInt32(s, "PartitionIndex", i);
1597       AddComment_UInt32(s, "PartitionNumber", part.Number);
1598       if (part.IsMetadata)
1599         AddComment_UInt32(s, "IsMetadata", 1);
1600       else
1601       {
1602         AddComment_RegId(s, "ContentsId", part.ContentsId);
1603         AddComment_RegId_Impl(s, "ImplementationId", part.ImplId);
1604         AddComment_PropName(s, "AccessType");
1605         s += TypeToString(g_PartitionTypes, Z7_ARRAY_SIZE(g_PartitionTypes), part.AccessType);
1606         s.Add_LF();
1607       }
1608       AddComment_UInt64(s, "Size", (UInt64)part.Len << SecLogSize);
1609       AddComment_UInt64(s, "Pos", (UInt64)part.Pos << SecLogSize);
1610     }
1611   }
1612   s += "Logical Volumes:";
1613   s.Add_LF();
1614   {
1615     FOR_VECTOR (i, LogVols)
1616     {
1617       if (i != 0)
1618         s.Add_LF();
1619       const CLogVol &vol = LogVols[i];
1620       if (LogVols.Size() != 1)
1621         AddComment_UInt32(s, "Number", i);
1622       AddComment_PropName(s, "Id");
1623       s += vol.Id.GetString();
1624       s.Add_LF();
1625       AddComment_UInt32(s, "BlockSize", vol.BlockSize);
1626       AddComment_RegId_Domain(s, "DomainId", vol.DomainId);
1627       AddComment_RegId_Impl(s, "ImplementationId", vol.ImplId);
1628       // AddComment_UInt64(s, "IntegritySequenceExtent_Len", vol.IntegritySequenceExtent.Len);
1629       // AddComment_UInt64(s, "IntegritySequenceExtent_Pos", (UInt64)vol.IntegritySequenceExtent.Pos << SecLogSize);
1630 
1631       s += "  Partition Maps:";
1632       s.Add_LF();
1633       {
1634         FOR_VECTOR (j, vol.PartitionMaps)
1635         {
1636           if (j != 0)
1637             s.Add_LF();
1638           const CPartitionMap &pm = vol.PartitionMaps[j];
1639           AddComment_UInt32_2(s, "PartitionMap", j);
1640           AddComment_UInt32_2(s, "Type", pm.Type);
1641           AddComment_UInt32_2(s, "VolumeSequenceNumber", pm.VolumeSequenceNumber);
1642           AddComment_UInt32_2(s, "PartitionNumber", pm.PartitionNumber);
1643           if (pm.Type == 2)
1644           {
1645             AddComment_UInt32_2(s, "MetadataFileLocation", pm.MetadataFileLocation);
1646             // AddComment_UInt32_2(s, "MetadataMirrorFileLocation", pm.MetadataMirrorFileLocation);
1647             // AddComment_UInt32_2(s, "MetadataBitmapFileLocation", pm.MetadataBitmapFileLocation);
1648             // AddComment_UInt32_2(s, "AllocationUnitSize", pm.AllocationUnitSize);
1649             // AddComment_UInt32_2(s, "AlignmentUnitSize", pm.AlignmentUnitSize);
1650             // AddComment_UInt32_2(s, "Flags", pm.Flags);
1651             AddComment_Align(s); AddComment_RegId_UdfId(s, "PartitionTypeId", pm.PartitionTypeId);
1652           }
1653         }
1654       }
1655       s += "  File Sets:";
1656       s.Add_LF();
1657       {
1658         FOR_VECTOR (j, vol.FileSets)
1659         {
1660           if (j != 0)
1661             s.Add_LF();
1662           const CFileSet &fs = vol.FileSets[j];
1663           AddComment_Align(s); AddComment_UInt32(s, "FileSetNumber", fs.FileSetNumber);
1664           AddComment_Align(s); AddComment_UInt32(s, "FileSetDescNumber", fs.FileSetDescNumber);
1665 
1666           AddComment_Align(s);
1667           AddComment_PropName(s, "LogicalVolumeId");
1668           s += fs.LogicalVolumeId.GetString();
1669           s.Add_LF();
1670 
1671           AddComment_DString32(s, "Id", fs.Id);
1672           AddComment_DString32(s, "CopyrightId", fs.CopyrightId);
1673           AddComment_DString32(s, "AbstractId", fs.AbstractId);
1674 
1675           AddComment_Align(s);
1676           AddComment_RegId_Domain(s, "DomainId", fs.DomainId);
1677         }
1678       }
1679     }
1680   }
1681   return s;
1682 }
1683 
GetSpecName(const UString & name)1684 static UString GetSpecName(const UString &name)
1685 {
1686   UString name2 = name;
1687   name2.Trim();
1688   if (name2.IsEmpty())
1689     return UString("[]");
1690   return name;
1691 }
1692 
UpdateWithName(UString & res,const UString & addString)1693 static void UpdateWithName(UString &res, const UString &addString)
1694 {
1695   if (res.IsEmpty())
1696     res = addString;
1697   else
1698     res.Insert(0, addString + WCHAR_PATH_SEPARATOR);
1699 }
1700 
GetItemPath(unsigned volIndex,unsigned fsIndex,unsigned refIndex,bool showVolName,bool showFsName) const1701 UString CInArchive::GetItemPath(unsigned volIndex, unsigned fsIndex, unsigned refIndex,
1702     bool showVolName, bool showFsName) const
1703 {
1704   // showVolName = true;
1705   const CLogVol &vol = LogVols[volIndex];
1706   const CFileSet &fs = vol.FileSets[fsIndex];
1707 
1708   UString name;
1709 
1710   for (;;)
1711   {
1712     const CRef &ref = fs.Refs[refIndex];
1713     // we break on root file (that probably has empty name)
1714     if (ref.Parent < 0)
1715       break;
1716     refIndex = (unsigned)ref.Parent;
1717     UpdateWithName(name, GetSpecName(Files[ref.FileIndex].GetName()));
1718   }
1719 
1720   if (showFsName)
1721   {
1722     UString newName ("File Set ");
1723     newName.Add_UInt32(fsIndex);
1724     UpdateWithName(name, newName);
1725   }
1726 
1727   if (showVolName)
1728   {
1729     UString newName;
1730     newName.Add_UInt32(volIndex);
1731     UString newName2 = vol.GetName();
1732     if (newName2.IsEmpty())
1733       newName2 = "Volume";
1734     newName.Add_Minus();
1735     newName += newName2;
1736     UpdateWithName(name, newName);
1737   }
1738   return name;
1739 }
1740 
1741 }}
1742