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