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 "../../Common/RegisterArc.h"
14 #include "../../Common/StreamUtils.h"
15 
16 #include "UdfIn.h"
17 
18 #ifdef SHOW_DEBUG_INFO
19 #define PRF(x) x
20 #else
21 #define PRF(x)
22 #endif
23 
24 #define Get16(p) GetUi16(p)
25 #define Get32(p) GetUi32(p)
26 #define Get64(p) GetUi64(p)
27 
28 namespace NArchive {
29 namespace NUdf {
30 
31 static const unsigned kNumPartitionsMax = 64;
32 static const unsigned kNumLogVolumesMax = 64;
33 static const unsigned kNumRecursionLevelsMax = 1 << 10;
34 static const unsigned kNumItemsMax = 1 << 27;
35 static const unsigned kNumFilesMax = 1 << 28;
36 static const unsigned kNumRefsMax = 1 << 28;
37 static const UInt32 kNumExtentsMax = (UInt32)1 << 30;
38 static const UInt64 kFileNameLengthTotalMax = (UInt64)1 << 33;
39 static const UInt64 kInlineExtentsSizeMax = (UInt64)1 << 33;
40 
41 #define CRC16_INIT_VAL 0
42 // #define CRC16_GET_DIGEST(crc) (crc)
43 #define CRC16_UPDATE_BYTE(crc, b) ((UInt16)(g_Crc16Table[(((crc) >> 8) ^ (b)) & 0xFF] ^ ((crc) << 8)))
44 
45 #define kCrc16Poly 0x1021
46 static UInt16 g_Crc16Table[256];
47 
Crc16GenerateTable(void)48 static void MY_FAST_CALL Crc16GenerateTable(void)
49 {
50   UInt32 i;
51   for (i = 0; i < 256; i++)
52   {
53     UInt32 r = (i << 8);
54     for (unsigned j = 0; j < 8; j++)
55       r = ((r << 1) ^ (kCrc16Poly & ((UInt32)0 - (r >> 15)))) & 0xFFFF;
56     g_Crc16Table[i] = (UInt16)r;
57   }
58 }
59 
Crc16_Update(UInt32 v,const void * data,size_t size)60 static UInt32 MY_FAST_CALL Crc16_Update(UInt32 v, const void *data, size_t size)
61 {
62   const Byte *p = (const Byte *)data;
63   for (; size > 0 ; size--, p++)
64     v = CRC16_UPDATE_BYTE(v, *p);
65   return v;
66 }
67 
Crc16Calc(const void * data,size_t size)68 static UInt32 MY_FAST_CALL Crc16Calc(const void *data, size_t size)
69 {
70   return Crc16_Update(CRC16_INIT_VAL, data, size);
71 }
72 
CCrc16TableInitNArchive::NUdf::CCrc16TableInit73 static struct CCrc16TableInit { CCrc16TableInit() { Crc16GenerateTable(); } } g_Crc16TableInit;
74 
75 
76 
Parse(const Byte * p,unsigned size)77 void CDString::Parse(const Byte *p, unsigned size)
78 {
79   Data.CopyFrom(p, size);
80 }
81 
ParseDString(const Byte * data,unsigned size)82 static UString ParseDString(const Byte *data, unsigned size)
83 {
84   UString res;
85   if (size > 0)
86   {
87     wchar_t *p;
88     Byte type = data[0];
89     if (type == 8)
90     {
91       p = res.GetBuf(size);
92       for (unsigned i = 1; i < size; i++)
93       {
94         wchar_t c = data[i];
95         if (c == 0)
96           break;
97         *p++ = c;
98       }
99     }
100     else if (type == 16)
101     {
102       p = res.GetBuf(size / 2);
103       for (unsigned i = 1; i + 2 <= size; i += 2)
104       {
105         wchar_t c = GetBe16(data + i);
106         if (c == 0)
107           break;
108         *p++ = c;
109       }
110     }
111     else
112       return UString("[unknown]");
113     *p = 0;
114     res.ReleaseBuf_SetLen((unsigned)(p - (const wchar_t *)res));
115   }
116   return res;
117 }
118 
GetString() const119 UString CDString128::GetString() const
120 {
121   unsigned size = Data[sizeof(Data) - 1];
122   return ParseDString(Data, MyMin(size, (unsigned)(sizeof(Data) - 1)));
123 }
124 
GetString() const125 UString CDString::GetString() const { return ParseDString(Data, (unsigned)Data.Size()); }
126 
Parse(const Byte * buf)127 void CTime::Parse(const Byte *buf) { memcpy(Data, buf, sizeof(Data)); }
128 
129 /*
130 void CRegId::Parse(const Byte *buf)
131 {
132   Flags = buf[0];
133   memcpy(Id, buf + 1, sizeof(Id));
134   memcpy(Suffix, buf + 24, sizeof(Suffix));
135 }
136 */
137 
138 // ECMA 3/7.1
139 
140 struct CExtent
141 {
142   UInt32 Len;
143   UInt32 Pos;
144 
145   void Parse(const Byte *buf);
146 };
147 
Parse(const Byte * buf)148 void CExtent::Parse(const Byte *buf)
149 {
150   Len = Get32(buf);
151   Pos = Get32(buf + 4);
152 }
153 
154 // ECMA 3/7.2
155 
156 struct CTag
157 {
158   UInt16 Id;
159   UInt16 Version;
160   // Byte Checksum;
161   // UInt16 SerialNumber;
162   // UInt16 Crc;
163   // UInt16 CrcLen;
164   // UInt32 TagLocation;
165 
166   HRESULT Parse(const Byte *buf, size_t size);
167 };
168 
Parse(const Byte * buf,size_t size)169 HRESULT CTag::Parse(const Byte *buf, size_t size)
170 {
171   if (size < 16)
172     return S_FALSE;
173   Byte sum = 0;
174   int i;
175   for (i = 0; i <  4; i++) sum = (Byte)(sum + buf[i]);
176   for (i = 5; i < 16; i++) sum = (Byte)(sum + buf[i]);
177   if (sum != buf[4] || buf[5] != 0) return S_FALSE;
178 
179   Id = Get16(buf);
180   Version = Get16(buf + 2);
181   // SerialNumber = Get16(buf + 6);
182   UInt32 crc = Get16(buf + 8);
183   UInt32 crcLen = Get16(buf + 10);
184   // TagLocation = Get32(buf + 12);
185 
186   if (size >= 16 + crcLen)
187     if (crc == Crc16Calc(buf + 16, (size_t)crcLen))
188       return S_OK;
189   return S_FALSE;
190 }
191 
192 // ECMA 3/7.2.1
193 
194 enum EDescriptorType
195 {
196   DESC_TYPE_SpoaringTable       = 0, // UDF
197   DESC_TYPE_PrimVol             = 1,
198   DESC_TYPE_AnchorVolPtr        = 2,
199   DESC_TYPE_VolPtr              = 3,
200   DESC_TYPE_ImplUseVol          = 4,
201   DESC_TYPE_Partition           = 5,
202   DESC_TYPE_LogicalVol          = 6,
203   DESC_TYPE_UnallocSpace        = 7,
204   DESC_TYPE_Terminating         = 8,
205   DESC_TYPE_LogicalVolIntegrity = 9,
206   DESC_TYPE_FileSet             = 256,
207   DESC_TYPE_FileId              = 257,
208   DESC_TYPE_AllocationExtent    = 258,
209   DESC_TYPE_Indirect            = 259,
210   DESC_TYPE_Terminal            = 260,
211   DESC_TYPE_File                = 261,
212   DESC_TYPE_ExtendedAttrHeader  = 262,
213   DESC_TYPE_UnallocatedSpace    = 263,
214   DESC_TYPE_SpaceBitmap         = 264,
215   DESC_TYPE_PartitionIntegrity  = 265,
216   DESC_TYPE_ExtendedFile        = 266
217 };
218 
219 
Parse(const Byte * buf)220 void CLogBlockAddr::Parse(const Byte *buf)
221 {
222   Pos = Get32(buf);
223   PartitionRef = Get16(buf + 4);
224 }
225 
Parse(const Byte * buf)226 void CShortAllocDesc::Parse(const Byte *buf)
227 {
228   Len = Get32(buf);
229   Pos = Get32(buf + 4);
230 }
231 
232 /*
233 void CADImpUse::Parse(const Byte *buf)
234 {
235   Flags = Get16(buf);
236   UdfUniqueId = Get32(buf + 2);
237 }
238 */
239 
Parse(const Byte * buf)240 void CLongAllocDesc::Parse(const Byte *buf)
241 {
242   Len = Get32(buf);
243   Location.Parse(buf + 4);
244   // memcpy(ImplUse, buf + 10, sizeof(ImplUse));
245   // adImpUse.Parse(ImplUse);
246 }
247 
CheckExtent(int volIndex,int partitionRef,UInt32 blockPos,UInt32 len) const248 bool CInArchive::CheckExtent(int volIndex, int partitionRef, UInt32 blockPos, UInt32 len) const
249 {
250   const CLogVol &vol = LogVols[volIndex];
251   if (partitionRef >= (int)vol.PartitionMaps.Size())
252     return false;
253   const CPartition &partition = Partitions[vol.PartitionMaps[partitionRef].PartitionIndex];
254   UInt64 offset = ((UInt64)partition.Pos << SecLogSize) + (UInt64)blockPos * vol.BlockSize;
255   return (offset + len) <= (((UInt64)partition.Pos + partition.Len) << SecLogSize);
256 }
257 
CheckItemExtents(int volIndex,const CItem & item) const258 bool CInArchive::CheckItemExtents(int volIndex, const CItem &item) const
259 {
260   FOR_VECTOR (i, item.Extents)
261   {
262     const CMyExtent &e = item.Extents[i];
263     if (!CheckExtent(volIndex, e.PartitionRef, e.Pos, e.GetLen()))
264       return false;
265   }
266   return true;
267 }
268 
Read(int volIndex,int partitionRef,UInt32 blockPos,UInt32 len,Byte * buf)269 HRESULT CInArchive::Read(int volIndex, int partitionRef, UInt32 blockPos, UInt32 len, Byte *buf)
270 {
271   if (!CheckExtent(volIndex, partitionRef, blockPos, len))
272     return S_FALSE;
273   const CLogVol &vol = LogVols[volIndex];
274   const CPartition &partition = Partitions[vol.PartitionMaps[partitionRef].PartitionIndex];
275   UInt64 offset = ((UInt64)partition.Pos << SecLogSize) + (UInt64)blockPos * vol.BlockSize;
276   RINOK(_stream->Seek(offset, STREAM_SEEK_SET, NULL));
277   HRESULT res = ReadStream_FALSE(_stream, buf, len);
278   if (res == S_FALSE && offset + len > FileSize)
279     UnexpectedEnd = true;
280   RINOK(res);
281   UpdatePhySize(offset + len);
282   return S_OK;
283 }
284 
Read(int volIndex,const CLongAllocDesc & lad,Byte * buf)285 HRESULT CInArchive::Read(int volIndex, const CLongAllocDesc &lad, Byte *buf)
286 {
287   return Read(volIndex, lad.Location.PartitionRef, lad.Location.Pos, lad.GetLen(), (Byte *)buf);
288 }
289 
ReadFromFile(int volIndex,const CItem & item,CByteBuffer & buf)290 HRESULT CInArchive::ReadFromFile(int volIndex, const CItem &item, CByteBuffer &buf)
291 {
292   if (item.Size >= (UInt32)1 << 30)
293     return S_FALSE;
294   if (item.IsInline)
295   {
296     buf = item.InlineData;
297     return S_OK;
298   }
299   buf.Alloc((size_t)item.Size);
300   size_t pos = 0;
301   FOR_VECTOR (i, item.Extents)
302   {
303     const CMyExtent &e = item.Extents[i];
304     UInt32 len = e.GetLen();
305     RINOK(Read(volIndex, e.PartitionRef, e.Pos, len, (Byte *)buf + pos));
306     pos += len;
307   }
308   return S_OK;
309 }
310 
311 
Parse(const Byte * p)312 void CIcbTag::Parse(const Byte *p)
313 {
314   // PriorDirectNum = Get32(p);
315   // StrategyType = Get16(p + 4);
316   // StrategyParam = Get16(p + 6);
317   // MaxNumOfEntries = Get16(p + 8);
318   FileType = p[11];
319   // ParentIcb.Parse(p + 12);
320   Flags = Get16(p + 18);
321 }
322 
Parse(const Byte * p)323 void CItem::Parse(const Byte *p)
324 {
325   // Uid = Get32(p + 36);
326   // Gid = Get32(p + 40);
327   // Permissions = Get32(p + 44);
328   // FileLinkCount = Get16(p + 48);
329   // RecordFormat = p[50];
330   // RecordDisplayAttr = p[51];
331   // RecordLen = Get32(p + 52);
332   Size = Get64(p + 56);
333   NumLogBlockRecorded = Get64(p + 64);
334   ATime.Parse(p + 72);
335   MTime.Parse(p + 84);
336   // AttrtTime.Parse(p + 96);
337   // CheckPoint = Get32(p + 108);
338   // ExtendedAttrIcb.Parse(p + 112);
339   // ImplId.Parse(p + 128);
340   // UniqueId = Get64(p + 160);
341 }
342 
343 // 4/14.4
344 struct CFileId
345 {
346   // UInt16 FileVersion;
347   Byte FileCharacteristics;
348   // CByteBuffer ImplUse;
349   CDString Id;
350   CLongAllocDesc Icb;
351 
IsItLinkParentNArchive::NUdf::CFileId352   bool IsItLinkParent() const { return (FileCharacteristics & FILEID_CHARACS_Parent) != 0; }
353   HRESULT Parse(const Byte *p, size_t size, size_t &processed);
354 };
355 
Parse(const Byte * p,size_t size,size_t & processed)356 HRESULT CFileId::Parse(const Byte *p, size_t size, size_t &processed)
357 {
358   processed = 0;
359   if (size < 38)
360     return S_FALSE;
361   CTag tag;
362   RINOK(tag.Parse(p, size));
363   if (tag.Id != DESC_TYPE_FileId)
364     return S_FALSE;
365   // FileVersion = Get16(p + 16);
366   FileCharacteristics = p[18];
367   unsigned idLen = p[19];
368   Icb.Parse(p + 20);
369   unsigned impLen = Get16(p + 36);
370   if (size < 38 + idLen + impLen)
371     return S_FALSE;
372   // ImplUse.SetCapacity(impLen);
373   processed = 38;
374   // memcpy(ImplUse, p + processed, impLen);
375   processed += impLen;
376   Id.Parse(p + processed, idLen);
377   processed += idLen;
378   for (;(processed & 3) != 0; processed++)
379     if (p[processed] != 0)
380       return S_FALSE;
381   return (processed <= size) ? S_OK : S_FALSE;
382 }
383 
ReadFileItem(int volIndex,int fsIndex,const CLongAllocDesc & lad,int numRecurseAllowed)384 HRESULT CInArchive::ReadFileItem(int volIndex, int fsIndex, const CLongAllocDesc &lad, int numRecurseAllowed)
385 {
386   if (Files.Size() % 100 == 0)
387     RINOK(_progress->SetCompleted(Files.Size(), _processedProgressBytes));
388   if (numRecurseAllowed-- == 0)
389     return S_FALSE;
390   CFile &file = Files.Back();
391   const CLogVol &vol = LogVols[volIndex];
392   unsigned partitionRef = lad.Location.PartitionRef;
393   if (partitionRef >= vol.PartitionMaps.Size())
394     return S_FALSE;
395   CPartition &partition = Partitions[vol.PartitionMaps[partitionRef].PartitionIndex];
396 
397   UInt32 key = lad.Location.Pos;
398   UInt32 value;
399   const UInt32 kRecursedErrorValue = (UInt32)(Int32)-1;
400   if (partition.Map.Find(key, value))
401   {
402     if (value == kRecursedErrorValue)
403       return S_FALSE;
404     file.ItemIndex = value;
405   }
406   else
407   {
408     value = Items.Size();
409     file.ItemIndex = (int)value;
410     if (partition.Map.Set(key, kRecursedErrorValue))
411       return S_FALSE;
412     RINOK(ReadItem(volIndex, fsIndex, lad, numRecurseAllowed));
413     if (!partition.Map.Set(key, value))
414       return S_FALSE;
415   }
416   return S_OK;
417 }
418 
ReadItem(int volIndex,int fsIndex,const CLongAllocDesc & lad,int numRecurseAllowed)419 HRESULT CInArchive::ReadItem(int volIndex, int fsIndex, const CLongAllocDesc &lad, int numRecurseAllowed)
420 {
421   if (Items.Size() > kNumItemsMax)
422     return S_FALSE;
423   Items.Add(CItem());
424   CItem &item = Items.Back();
425 
426   const CLogVol &vol = LogVols[volIndex];
427 
428   if (lad.GetLen() != vol.BlockSize)
429     return S_FALSE;
430 
431   const size_t size = lad.GetLen();
432   CByteBuffer buf(size);
433   RINOK(Read(volIndex, lad, buf));
434 
435   CTag tag;
436   const Byte *p = buf;
437   RINOK(tag.Parse(p, size));
438   if (size < 176)
439     return S_FALSE;
440   if (tag.Id != DESC_TYPE_File)
441     return S_FALSE;
442 
443   item.IcbTag.Parse(p + 16);
444   if (item.IcbTag.FileType != ICB_FILE_TYPE_DIR &&
445       item.IcbTag.FileType != ICB_FILE_TYPE_FILE)
446     return S_FALSE;
447 
448   item.Parse(p);
449 
450   _processedProgressBytes += (UInt64)item.NumLogBlockRecorded * vol.BlockSize + size;
451 
452   UInt32 extendedAttrLen = Get32(p + 168);
453   UInt32 allocDescriptorsLen = Get32(p + 172);
454 
455   if ((extendedAttrLen & 3) != 0)
456     return S_FALSE;
457   size_t pos = 176;
458   if (extendedAttrLen > size - pos)
459     return S_FALSE;
460   /*
461   if (extendedAttrLen != 16)
462   {
463     if (extendedAttrLen < 24)
464       return S_FALSE;
465     CTag attrTag;
466     RINOK(attrTag.Parse(p + pos, size));
467     if (attrTag.Id != DESC_TYPE_ExtendedAttrHeader)
468       return S_FALSE;
469     // UInt32 implAttrLocation = Get32(p + pos + 16);
470     // UInt32 applicationlAttrLocation = Get32(p + pos + 20);
471   }
472   */
473   pos += extendedAttrLen;
474 
475   int desctType = item.IcbTag.GetDescriptorType();
476   if (allocDescriptorsLen > size - pos)
477     return S_FALSE;
478   if (desctType == ICB_DESC_TYPE_INLINE)
479   {
480     item.IsInline = true;
481     item.InlineData.CopyFrom(p + pos, allocDescriptorsLen);
482   }
483   else
484   {
485     item.IsInline = false;
486     if (desctType != ICB_DESC_TYPE_SHORT && desctType != ICB_DESC_TYPE_LONG)
487       return S_FALSE;
488     for (UInt32 i = 0; i < allocDescriptorsLen;)
489     {
490       CMyExtent e;
491       if (desctType == ICB_DESC_TYPE_SHORT)
492       {
493         if (i + 8 > allocDescriptorsLen)
494           return S_FALSE;
495         CShortAllocDesc sad;
496         sad.Parse(p + pos + i);
497         e.Pos = sad.Pos;
498         e.Len = sad.Len;
499         e.PartitionRef = lad.Location.PartitionRef;
500         i += 8;
501       }
502       else
503       {
504         if (i + 16 > allocDescriptorsLen)
505           return S_FALSE;
506         CLongAllocDesc ladNew;
507         ladNew.Parse(p + pos + i);
508         e.Pos = ladNew.Location.Pos;
509         e.PartitionRef = ladNew.Location.PartitionRef;
510         e.Len = ladNew.Len;
511         i += 16;
512       }
513       item.Extents.Add(e);
514     }
515   }
516 
517   if (item.IcbTag.IsDir())
518   {
519     if (!item.CheckChunkSizes() || !CheckItemExtents(volIndex, item))
520       return S_FALSE;
521     CByteBuffer buf2;
522     RINOK(ReadFromFile(volIndex, item, buf2));
523     item.Size = 0;
524     item.Extents.ClearAndFree();
525     item.InlineData.Free();
526 
527     const Byte *p2 = buf2;
528     const size_t size2 = buf2.Size();
529     size_t processedTotal = 0;
530     for (; processedTotal < size2;)
531     {
532       size_t processedCur;
533       CFileId fileId;
534       RINOK(fileId.Parse(p2 + processedTotal, size2 - processedTotal, processedCur));
535       if (!fileId.IsItLinkParent())
536       {
537         CFile file;
538         // file.FileVersion = fileId.FileVersion;
539         // file.FileCharacteristics = fileId.FileCharacteristics;
540         // file.ImplUse = fileId.ImplUse;
541         file.Id = fileId.Id;
542 
543         _fileNameLengthTotal += file.Id.Data.Size();
544         if (_fileNameLengthTotal > kFileNameLengthTotalMax)
545           return S_FALSE;
546 
547         item.SubFiles.Add(Files.Size());
548         if (Files.Size() > kNumFilesMax)
549           return S_FALSE;
550         Files.Add(file);
551         RINOK(ReadFileItem(volIndex, fsIndex, fileId.Icb, numRecurseAllowed));
552       }
553       processedTotal += processedCur;
554     }
555   }
556   else
557   {
558     if ((UInt32)item.Extents.Size() > kNumExtentsMax - _numExtents)
559       return S_FALSE;
560     _numExtents += item.Extents.Size();
561 
562     if (item.InlineData.Size() > kInlineExtentsSizeMax - _inlineExtentsSize)
563       return S_FALSE;
564     _inlineExtentsSize += item.InlineData.Size();
565   }
566 
567   return S_OK;
568 }
569 
FillRefs(CFileSet & fs,unsigned fileIndex,int parent,int numRecurseAllowed)570 HRESULT CInArchive::FillRefs(CFileSet &fs, unsigned fileIndex, int parent, int numRecurseAllowed)
571 {
572   if ((_numRefs & 0xFFF) == 0)
573   {
574     RINOK(_progress->SetCompleted());
575   }
576   if (numRecurseAllowed-- == 0)
577     return S_FALSE;
578   if (_numRefs >= kNumRefsMax)
579     return S_FALSE;
580   _numRefs++;
581   CRef ref;
582   ref.FileIndex = fileIndex;
583   ref.Parent = parent;
584   parent = fs.Refs.Size();
585   fs.Refs.Add(ref);
586   const CItem &item = Items[Files[fileIndex].ItemIndex];
587   FOR_VECTOR (i, item.SubFiles)
588   {
589     RINOK(FillRefs(fs, item.SubFiles[i], parent, numRecurseAllowed));
590   }
591   return S_OK;
592 }
593 
IsArc_Udf(const Byte * p,size_t size)594 API_FUNC_IsArc IsArc_Udf(const Byte *p, size_t size)
595 {
596   UInt32 res = k_IsArc_Res_NO;
597   unsigned SecLogSize;
598   for (SecLogSize = 11;; SecLogSize -= 3)
599   {
600     if (SecLogSize < 8)
601       return res;
602     const UInt32 offset = (UInt32)256 << SecLogSize;
603     const UInt32 bufSize = (UInt32)1 << SecLogSize;
604     if (offset + bufSize > size)
605       res = k_IsArc_Res_NEED_MORE;
606     else
607     {
608       CTag tag;
609       if (tag.Parse(p + offset, bufSize) == S_OK)
610         if (tag.Id == DESC_TYPE_AnchorVolPtr)
611           return k_IsArc_Res_YES;
612     }
613   }
614 }
615 
616 
Open2()617 HRESULT CInArchive::Open2()
618 {
619   Clear();
620   UInt64 fileSize;
621   RINOK(_stream->Seek(0, STREAM_SEEK_END, &fileSize));
622   FileSize = fileSize;
623 
624   // Some UDFs contain additional pad zeros (2 KB).
625   // Seek to STREAM_SEEK_END for direct DVD reading can return 8 KB more, so we check last 16 KB.
626   // And when we read last block, result read size can be smaller than required size.
627 
628   /*
629   const size_t kBufSize = 1 << 14;
630   Byte buf[kBufSize];
631   size_t readSize = (fileSize < kBufSize) ? (size_t)fileSize : kBufSize;
632   RINOK(_stream->Seek(fileSize - readSize, STREAM_SEEK_SET, NULL));
633   RINOK(ReadStream(_stream, buf, &readSize));
634   size_t i = readSize;
635   for (;;)
636   {
637     const size_t kSecSizeMin = 1 << 8;
638     if (i < kSecSizeMin)
639       return S_FALSE;
640     i -= kSecSizeMin;
641     SecLogSize = (readSize - i < ((size_t)1 << 11)) ? 8 : 11;
642     CTag tag;
643     if (tag.Parse(buf + i, (1 << SecLogSize)) == S_OK)
644       if (tag.Id == DESC_TYPE_AnchorVolPtr)
645         break;
646   }
647   PhySize = fileSize;
648   CExtent extentVDS;
649   extentVDS.Parse(buf + i + 16);
650   */
651 
652   const size_t kBufSize = 1 << 11;
653   Byte buf[kBufSize];
654 
655   for (SecLogSize = 11;; SecLogSize -= 3)
656   {
657     if (SecLogSize < 8)
658       return S_FALSE;
659     UInt32 offset = (UInt32)256 << SecLogSize;
660     if (offset >= fileSize)
661       continue;
662     RINOK(_stream->Seek(offset, STREAM_SEEK_SET, NULL));
663     const size_t bufSize = (size_t)1 << SecLogSize;
664     size_t readSize = bufSize;
665     RINOK(ReadStream(_stream, buf, &readSize));
666     if (readSize == bufSize)
667     {
668       CTag tag;
669       if (tag.Parse(buf, readSize) == S_OK)
670         if (tag.Id == DESC_TYPE_AnchorVolPtr)
671           break;
672     }
673   }
674 
675   PhySize = (UInt32)(256 + 1) << SecLogSize;
676   IsArc = true;
677 
678   CExtent extentVDS;
679   extentVDS.Parse(buf + 16);
680   {
681     CExtent extentVDS2;
682     extentVDS2.Parse(buf + 24);
683     UpdatePhySize(((UInt64)extentVDS.Pos << SecLogSize) + extentVDS.Len);
684     UpdatePhySize(((UInt64)extentVDS2.Pos << SecLogSize) + extentVDS2.Len);
685   }
686 
687   for (UInt32 location = 0; ; location++)
688   {
689     const size_t bufSize = (size_t)1 << SecLogSize;
690     if (((UInt64)(location + 1) << SecLogSize) > extentVDS.Len)
691       return S_FALSE;
692 
693     UInt64 offs = (UInt64)(extentVDS.Pos + location) << SecLogSize;
694     RINOK(_stream->Seek(offs, STREAM_SEEK_SET, NULL));
695     HRESULT res = ReadStream_FALSE(_stream, buf, bufSize);
696     if (res == S_FALSE && offs + bufSize > FileSize)
697       UnexpectedEnd = true;
698     RINOK(res);
699 
700 
701     CTag tag;
702     {
703       const size_t pos = 0;
704       RINOK(tag.Parse(buf + pos, bufSize - pos));
705     }
706     if (tag.Id == DESC_TYPE_Terminating)
707       break;
708 
709     if (tag.Id == DESC_TYPE_Partition)
710     {
711       // Partition Descriptor
712       // ECMA 167 3/10.5
713       // UDF / 2.2.14
714 
715       if (Partitions.Size() >= kNumPartitionsMax)
716         return S_FALSE;
717       CPartition partition;
718       // UInt32 volDescSeqNumer = Get32(buf + 16);
719       // partition.Flags = Get16(buf + 20);
720       partition.Number = Get16(buf + 22);
721       // partition.ContentsId.Parse(buf + 24);
722 
723       // memcpy(partition.ContentsUse, buf + 56, sizeof(partition.ContentsUse));
724       // ContentsUse is Partition Header Description.
725 
726       // partition.AccessType = Get32(buf + 184);
727       partition.Pos = Get32(buf + 188);
728       partition.Len = Get32(buf + 192);
729       // partition.ImplId.Parse(buf + 196);
730       // memcpy(partition.ImplUse, buf + 228, sizeof(partition.ImplUse));
731 
732       PRF(printf("\nPartition number = %2d   pos = %d   len = %d", partition.Number, partition.Pos, partition.Len));
733       Partitions.Add(partition);
734     }
735     else if (tag.Id == DESC_TYPE_LogicalVol)
736     {
737       /* Logical Volume Descriptor
738           ECMA 3/10.6
739           UDF 2.60 2.2.4 */
740 
741       if (LogVols.Size() >= kNumLogVolumesMax)
742         return S_FALSE;
743       CLogVol vol;
744       vol.Id.Parse(buf + 84);
745       vol.BlockSize = Get32(buf + 212);
746       // vol.DomainId.Parse(buf + 216);
747 
748       if (vol.BlockSize < 512 || vol.BlockSize > ((UInt32)1 << 30))
749         return S_FALSE;
750 
751       // memcpy(vol.ContentsUse, buf + 248, sizeof(vol.ContentsUse));
752       vol.FileSetLocation.Parse(buf + 248);
753       /* the extent in which the first File Set Descriptor Sequence
754          of the logical volume is recorded */
755 
756       // UInt32 mapTableLength = Get32(buf + 264);
757       UInt32 numPartitionMaps = Get32(buf + 268);
758       if (numPartitionMaps > kNumPartitionsMax)
759         return S_FALSE;
760       // vol.ImplId.Parse(buf + 272);
761       // memcpy(vol.ImplUse, buf + 128, sizeof(vol.ImplUse));
762 
763       PRF(printf("\nLogicalVol numPartitionMaps = %2d", numPartitionMaps));
764       size_t pos = 440;
765       for (UInt32 i = 0; i < numPartitionMaps; i++)
766       {
767         if (pos + 2 > bufSize)
768           return S_FALSE;
769         CPartitionMap pm;
770         pm.Type = buf[pos];
771         // pm.Length = buf[pos + 1];
772         Byte len = buf[pos + 1];
773 
774         if (pos + len > bufSize)
775           return S_FALSE;
776 
777         // memcpy(pm.Data, buf + pos + 2, pm.Length - 2);
778         if (pm.Type == 1)
779         {
780           if (len != 6) // < 6
781             return S_FALSE;
782           // pm.VolSeqNumber = Get16(buf + pos + 2);
783           pm.PartitionNumber = Get16(buf + pos + 4);
784           PRF(printf("\nPartitionMap type 1 PartitionNumber = %2d", pm.PartitionNumber));
785         }
786         else if (pm.Type == 2)
787         {
788           if (len != 64)
789             return S_FALSE;
790           /* ECMA 10.7.3 / Type 2 Partition Map
791              62 bytes: Partition Identifier. */
792 
793           /* UDF 2.6
794              2.2.8 Virtual Partition Map
795              This is an extension of ECMA 167 to expand its scope to include
796              sequentially written media (eg. CD-R).  This extension is for a
797              Partition Map entry to describe a virtual space.   */
798 
799           // It's not implemented still.
800           if (Get16(buf + pos + 2) != 0)
801             return S_FALSE;
802           // pm.VolSeqNumber = Get16(buf + pos + 36);
803           pm.PartitionNumber = Get16(buf + pos + 38);
804           PRF(printf("\nPartitionMap type 2 PartitionNumber = %2d", pm.PartitionNumber));
805           // Unsupported = true;
806           return S_FALSE;
807         }
808         else
809           return S_FALSE;
810         pos += len;
811         vol.PartitionMaps.Add(pm);
812       }
813       LogVols.Add(vol);
814     }
815   }
816 
817   UInt64 totalSize = 0;
818 
819   unsigned volIndex;
820   for (volIndex = 0; volIndex < LogVols.Size(); volIndex++)
821   {
822     CLogVol &vol = LogVols[volIndex];
823     FOR_VECTOR (pmIndex, vol.PartitionMaps)
824     {
825       CPartitionMap &pm = vol.PartitionMaps[pmIndex];
826       unsigned i;
827       for (i = 0; i < Partitions.Size(); i++)
828       {
829         CPartition &part = Partitions[i];
830         if (part.Number == pm.PartitionNumber)
831         {
832           if (part.VolIndex >= 0)
833           {
834             // it's for 2.60. Fix it
835             if (part.VolIndex != (int)volIndex)
836               return S_FALSE;
837             // return S_FALSE;
838           }
839           pm.PartitionIndex = i;
840           part.VolIndex = volIndex;
841 
842           totalSize += (UInt64)part.Len << SecLogSize;
843           break;
844         }
845       }
846       if (i == Partitions.Size())
847         return S_FALSE;
848     }
849   }
850 
851   RINOK(_progress->SetTotal(totalSize));
852 
853   PRF(printf("\n Read files"));
854 
855   for (volIndex = 0; volIndex < LogVols.Size(); volIndex++)
856   {
857     CLogVol &vol = LogVols[volIndex];
858 
859     PRF(printf("\nLogVol %2d", volIndex));
860 
861     CLongAllocDesc nextExtent = vol.FileSetLocation;
862     // while (nextExtent.ExtentLen != 0)
863     // for (int i = 0; i < 1; i++)
864     {
865       if (nextExtent.GetLen() < 512)
866         return S_FALSE;
867       CByteBuffer buf2(nextExtent.GetLen());
868       RINOK(Read(volIndex, nextExtent, buf2));
869       const Byte *p = buf2;
870       size_t size = nextExtent.GetLen();
871 
872       CTag tag;
873       RINOK(tag.Parse(p, size));
874 
875       if (tag.Id == DESC_TYPE_ExtendedFile)
876       {
877         // ECMA 4 / 14.17
878         // 2.60 ??
879         return S_FALSE;
880       }
881 
882       if (tag.Id != DESC_TYPE_FileSet)
883         return S_FALSE;
884 
885       PRF(printf("\n FileSet", volIndex));
886       CFileSet fs;
887       fs.RecodringTime.Parse(p + 16);
888       // fs.InterchangeLevel = Get16(p + 18);
889       // fs.MaxInterchangeLevel = Get16(p + 20);
890       // fs.FileSetNumber = Get32(p + 40);
891       // fs.FileSetDescNumber = Get32(p + 44);
892 
893       // fs.Id.Parse(p + 304);
894       // fs.CopyrightId.Parse(p + 336);
895       // fs.AbstractId.Parse(p + 368);
896 
897       fs.RootDirICB.Parse(p + 400);
898       // fs.DomainId.Parse(p + 416);
899 
900       // fs.SystemStreamDirICB.Parse(p + 464);
901 
902       vol.FileSets.Add(fs);
903 
904       // nextExtent.Parse(p + 448);
905     }
906 
907     FOR_VECTOR (fsIndex, vol.FileSets)
908     {
909       CFileSet &fs = vol.FileSets[fsIndex];
910       unsigned fileIndex = Files.Size();
911       Files.AddNew();
912       RINOK(ReadFileItem(volIndex, fsIndex, fs.RootDirICB, kNumRecursionLevelsMax));
913       RINOK(FillRefs(fs, fileIndex, -1, kNumRecursionLevelsMax));
914     }
915   }
916 
917 
918   for (volIndex = 0; volIndex < LogVols.Size(); volIndex++)
919   {
920     const CLogVol &vol = LogVols[volIndex];
921     // bool showFileSetName = (vol.FileSets.Size() > 1);
922     FOR_VECTOR (fsIndex, vol.FileSets)
923     {
924       const CFileSet &fs = vol.FileSets[fsIndex];
925       for (unsigned i =
926           // ((showVolName || showFileSetName) ? 0 : 1)
927             0; i < fs.Refs.Size(); i++)
928       {
929         const CRef &ref = vol.FileSets[fsIndex].Refs[i];
930         const CFile &file = Files[ref.FileIndex];
931         const CItem &item = Items[file.ItemIndex];
932         UInt64 size = item.Size;
933 
934         if (!item.IsRecAndAlloc() || !item.CheckChunkSizes() || !CheckItemExtents(volIndex, item))
935           continue;
936 
937         FOR_VECTOR (extentIndex, item.Extents)
938         {
939           const CMyExtent &extent = item.Extents[extentIndex];
940           UInt32 len = extent.GetLen();
941           if (len == 0)
942             continue;
943           if (size < len)
944             break;
945 
946           int partitionIndex = vol.PartitionMaps[extent.PartitionRef].PartitionIndex;
947           UInt32 logBlockNumber = extent.Pos;
948           const CPartition &partition = Partitions[partitionIndex];
949           UInt64 offset = ((UInt64)partition.Pos << SecLogSize) +
950               (UInt64)logBlockNumber * vol.BlockSize;
951           UpdatePhySize(offset + len);
952         }
953       }
954     }
955   }
956 
957   {
958     const UInt32 secMask = ((UInt32)1 << SecLogSize) - 1;
959     PhySize = (PhySize + secMask) & ~(UInt64)secMask;
960   }
961 
962   NoEndAnchor = true;
963 
964   if (PhySize < fileSize)
965   {
966     UInt64 rem = fileSize - PhySize;
967     const size_t secSize = (size_t)1 << SecLogSize;
968 
969     RINOK(_stream->Seek(PhySize, STREAM_SEEK_SET, NULL));
970 
971     // some UDF images contain ZEROs before "Anchor Volume Descriptor Pointer" at the end
972 
973     for (unsigned sec = 0; sec < 1024; sec++)
974     {
975       if (rem == 0)
976         break;
977 
978       size_t readSize = secSize;
979       if (readSize > rem)
980         readSize = (size_t)rem;
981 
982       RINOK(ReadStream(_stream, buf, &readSize));
983 
984       if (readSize == 0)
985         break;
986 
987       if (readSize == secSize && NoEndAnchor)
988       {
989         CTag tag;
990         if (tag.Parse(buf, readSize) == S_OK &&
991             tag.Id == DESC_TYPE_AnchorVolPtr)
992         {
993           NoEndAnchor = false;
994           rem -= readSize;
995           PhySize = fileSize - rem;
996           continue;
997         }
998       }
999 
1000       size_t i;
1001       for (i = 0; i < readSize && buf[i] == 0; i++);
1002       if (i != readSize)
1003         break;
1004       rem -= readSize;
1005     }
1006 
1007     if (rem == 0)
1008       PhySize = fileSize;
1009   }
1010 
1011   return S_OK;
1012 }
1013 
1014 
Open(IInStream * inStream,CProgressVirt * progress)1015 HRESULT CInArchive::Open(IInStream *inStream, CProgressVirt *progress)
1016 {
1017   _progress = progress;
1018   _stream = inStream;
1019   HRESULT res = Open2();
1020   if (res == S_FALSE && IsArc && !UnexpectedEnd)
1021     Unsupported = true;
1022   return res;
1023 
1024   /*
1025   HRESULT res;
1026   try
1027   {
1028     res = Open2();
1029   }
1030   catch(...)
1031   {
1032     // Clear();
1033     // res = S_FALSE;
1034     _stream.Release();
1035     throw;
1036   }
1037   _stream.Release();
1038   return res;
1039   */
1040 }
1041 
Clear()1042 void CInArchive::Clear()
1043 {
1044   IsArc = false;
1045   Unsupported = false;
1046   UnexpectedEnd = false;
1047   NoEndAnchor = false;
1048 
1049   PhySize = 0;
1050   FileSize = 0;
1051 
1052   Partitions.Clear();
1053   LogVols.Clear();
1054   Items.Clear();
1055   Files.Clear();
1056   _fileNameLengthTotal = 0;
1057   _numRefs = 0;
1058   _numExtents = 0;
1059   _inlineExtentsSize = 0;
1060   _processedProgressBytes = 0;
1061 }
1062 
GetComment() const1063 UString CInArchive::GetComment() const
1064 {
1065   UString res;
1066   FOR_VECTOR (i, LogVols)
1067   {
1068     if (i != 0)
1069       res.Add_Space();
1070     res += LogVols[i].GetName();
1071   }
1072   return res;
1073 }
1074 
GetSpecName(const UString & name)1075 static UString GetSpecName(const UString &name)
1076 {
1077   UString name2 = name;
1078   name2.Trim();
1079   if (name2.IsEmpty())
1080     return UString("[]");
1081   return name;
1082 }
1083 
UpdateWithName(UString & res,const UString & addString)1084 static void UpdateWithName(UString &res, const UString &addString)
1085 {
1086   if (res.IsEmpty())
1087     res = addString;
1088   else
1089     res.Insert(0, addString + WCHAR_PATH_SEPARATOR);
1090 }
1091 
GetItemPath(int volIndex,int fsIndex,int refIndex,bool showVolName,bool showFsName) const1092 UString CInArchive::GetItemPath(int volIndex, int fsIndex, int refIndex,
1093     bool showVolName, bool showFsName) const
1094 {
1095   // showVolName = true;
1096   const CLogVol &vol = LogVols[volIndex];
1097   const CFileSet &fs = vol.FileSets[fsIndex];
1098 
1099   UString name;
1100 
1101   for (;;)
1102   {
1103     const CRef &ref = fs.Refs[refIndex];
1104     refIndex = ref.Parent;
1105     if (refIndex < 0)
1106       break;
1107     UpdateWithName(name, GetSpecName(Files[ref.FileIndex].GetName()));
1108   }
1109 
1110   if (showFsName)
1111   {
1112     UString newName ("File Set ");
1113     newName.Add_UInt32(fsIndex);
1114     UpdateWithName(name, newName);
1115   }
1116 
1117   if (showVolName)
1118   {
1119     UString newName;
1120     newName.Add_UInt32(volIndex);
1121     UString newName2 = vol.GetName();
1122     if (newName2.IsEmpty())
1123       newName2 = "Volume";
1124     newName += '-';
1125     newName += newName2;
1126     UpdateWithName(name, newName);
1127   }
1128   return name;
1129 }
1130 
1131 }}
1132