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