1 // Archive/UdfIn.h -- UDF / ECMA-167 2 3 #ifndef ZIP7_INC_ARCHIVE_UDF_IN_H 4 #define ZIP7_INC_ARCHIVE_UDF_IN_H 5 6 #include "../../../Common/IntToString.h" 7 #include "../../../Common/MyBuffer.h" 8 #include "../../../Common/MyCom.h" 9 #include "../../../Common/MyMap.h" 10 #include "../../../Common/MyString.h" 11 12 #include "../../IStream.h" 13 14 namespace NArchive { 15 namespace NUdf { 16 17 // ---------- ECMA Part 1 ---------- 18 19 // ECMA 1/7.2.12 20 // UDF 2.1.3 21 22 struct CDString32 23 { 24 Byte Data[32]; 25 ParseCDString3226 void Parse(const Byte *buf) { memcpy(Data, buf, sizeof(Data)); } 27 UString GetString() const; 28 }; 29 30 struct CDString128 31 { 32 Byte Data[128]; 33 ParseCDString12834 void Parse(const Byte *buf) { memcpy(Data, buf, sizeof(Data)); } 35 UString GetString() const; 36 }; 37 38 struct CDString 39 { 40 CByteBuffer Data; 41 42 void Parse(const Byte *p, unsigned size); 43 UString GetString() const; 44 }; 45 46 47 // ECMA 1/7.3 48 // UDF 2.1.4 timestamp 49 50 struct CTime 51 { 52 Byte Data[12]; 53 GetTypeCTime54 unsigned GetType() const { return Data[1] >> 4; } IsLocalCTime55 bool IsLocal() const { return GetType() == 1; } GetMinutesOffsetCTime56 int GetMinutesOffset() const 57 { 58 int t = (Data[0] | ((unsigned)Data[1] << 8)) & 0xFFF; 59 if ((t >> 11) != 0) 60 t -= (1 << 12); 61 return (t > (60 * 24) || t < -(60 * 24)) ? 0 : t; 62 } GetYearCTime63 unsigned GetYear() const { return (Data[2] | ((unsigned)Data[3] << 8)); } 64 void Parse(const Byte *buf); 65 }; 66 67 68 // ECMA 1/7.4 regid 69 // UDF 2.1.5 EntityID 70 71 struct CRegId 72 { 73 Byte Flags; 74 char Id[23]; 75 Byte Suffix[8]; 76 77 void Parse(const Byte *buf); 78 void AddCommentTo(UString &s) const; 79 void AddUdfVersionTo(UString &s) const; 80 }; 81 82 83 84 // ---------- ECMA Part 3: Volume Structure ---------- 85 86 // ECMA 3/7.1 87 88 struct CExtent 89 { 90 UInt32 Len; 91 UInt32 Pos; // logical sector number 92 93 void Parse(const Byte *p); 94 }; 95 96 97 // ECMA 3/10.1 98 // UDF 2.2.2 PrimaryVolumeDescriptor 99 100 struct CPrimeVol 101 { 102 // UInt32 VolumeDescriptorSequenceNumber; 103 UInt32 PrimaryVolumeDescriptorNumber; 104 CDString32 VolumeId; 105 UInt16 VolumeSequenceNumber; 106 UInt16 MaximumVolumeSequenceNumber; 107 // UInt16 InterchangeLevel; 108 // UInt16 MaximumInterchangeLevel; 109 // UInt32 CharacterSetList; 110 // UInt32 MaximumCharacterSetList; 111 CDString128 VolumeSetId; 112 // charspec DescriptorCharacterSet; // (1/7.2.1) 113 // charspec ExplanatoryCharacterSet; // (1/7.2.1) 114 // CExtent VolumeAbstract; 115 // CExtent VolumeCopyrightNotice; 116 CRegId ApplicationId; 117 CTime RecordingTime; 118 CRegId ImplId; 119 // bytes ImplementationUse 120 // UInt32 PredecessorVolumeDescriptorSequenceLocation; 121 // UInt16 Flags; 122 123 void Parse(const Byte *p); 124 }; 125 126 127 // ECMA 3/10.5 128 // UDF 2.2.14 PartitionDescriptor 129 130 struct CPartition 131 { 132 UInt32 Pos; 133 UInt32 Len; 134 135 UInt16 Flags; 136 UInt16 Number; 137 CRegId ContentsId; 138 // Byte ContentsUse[128]; 139 UInt32 AccessType; 140 141 CRegId ImplId; 142 // Byte ImplUse[128]; 143 144 // int VolIndex; 145 CMap32 Map; 146 147 bool IsMetadata; 148 CPartitionCPartition149 CPartition(): 150 // VolIndex(-1), 151 IsMetadata(false) {} 152 153 // bool IsNsr() const { return (strncmp(ContentsId.Id, "+NSR0", 5) == 0); } 154 // bool IsAllocated() const { return ((Flags & 1) != 0); } 155 }; 156 157 158 // ECMA 4/7.1 lb_addr 159 160 struct CLogBlockAddr 161 { 162 UInt32 Pos; 163 UInt16 PartitionRef; 164 165 void Parse(const Byte *p); 166 }; 167 168 169 enum EShortAllocDescType 170 { 171 SHORT_ALLOC_DESC_TYPE_RecordedAndAllocated = 0, 172 SHORT_ALLOC_DESC_TYPE_NotRecordedButAllocated = 1, 173 SHORT_ALLOC_DESC_TYPE_NotRecordedAndNotAllocated = 2, 174 SHORT_ALLOC_DESC_TYPE_NextExtent = 3 175 }; 176 177 178 // ECMA 4/14.14.1 short_ad 179 180 struct CShortAllocDesc 181 { 182 UInt32 Len; 183 UInt32 Pos; 184 185 // UInt32 GetLen() const { return Len & 0x3FFFFFFF; } 186 // UInt32 GetType() const { return Len >> 30; } 187 // bool IsRecAndAlloc() const { return GetType() == SHORT_ALLOC_DESC_TYPE_RecordedAndAllocated; } 188 void Parse(const Byte *p); 189 }; 190 191 /* 192 struct CADImpUse 193 { 194 UInt16 Flags; 195 UInt32 UdfUniqueId; 196 void Parse(const Byte *p); 197 }; 198 */ 199 200 // ECMA 4/14.14.2 long_ad 201 // UDF 2.3.10.1 202 203 struct CLongAllocDesc 204 { 205 UInt32 Len; 206 CLogBlockAddr Location; 207 208 // Byte ImplUse[6]; 209 // CADImpUse adImpUse; // UDF 210 GetLenCLongAllocDesc211 UInt32 GetLen() const { return Len & 0x3FFFFFFF; } GetTypeCLongAllocDesc212 UInt32 GetType() const { return Len >> 30; } IsRecAndAllocCLongAllocDesc213 bool IsRecAndAlloc() const { return GetType() == SHORT_ALLOC_DESC_TYPE_RecordedAndAllocated; } 214 void Parse(const Byte *p); 215 }; 216 217 218 // ECMA 3/10.7 Partition maps 219 // UDF 2.2.8-2.2.10 Partition Maps 220 221 struct CPartitionMap 222 { 223 unsigned PartitionIndex; 224 225 Byte Type; 226 // Byte Len; 227 228 // ECMA 10.7.2 229 UInt16 VolumeSequenceNumber; 230 UInt16 PartitionNumber; 231 232 CRegId PartitionTypeId; 233 234 // UDF 2.2.10 Metadata Partition Map 235 UInt32 MetadataFileLocation; 236 // UInt32 MetadataMirrorFileLocation; 237 // UInt32 MetadataBitmapFileLocation; 238 // UInt32 AllocationUnitSize; // (Blocks) 239 // UInt16 AlignmentUnitSize; // (Blocks) 240 // Byte Flags; 241 242 // Byte Data[256]; 243 // CPartitionMap(): PartitionIndex(-1) {} 244 }; 245 246 247 // ECMA 4/14.6.6 248 249 enum EIcbFileType 250 { 251 ICB_FILE_TYPE_DIR = 4, 252 ICB_FILE_TYPE_FILE = 5, 253 254 ICB_FILE_TYPE_METADATA = 250, // 2.2.13.1 Metadata File 255 ICB_FILE_TYPE_METADATA_MIRROR = 251 256 }; 257 258 enum EIcbDescriptorType 259 { 260 ICB_DESC_TYPE_SHORT = 0, 261 ICB_DESC_TYPE_LONG = 1, 262 ICB_DESC_TYPE_EXTENDED = 2, 263 ICB_DESC_TYPE_INLINE = 3 264 }; 265 266 // ECMA 4/14.6 267 // UDF 3.3.2 268 269 struct CIcbTag 270 { 271 // UInt32 PriorDirectNum; 272 // UInt16 StrategyType; 273 // UInt16 StrategyParam; 274 // UInt16 MaxNumOfEntries; 275 Byte FileType; 276 // CLogBlockAddr ParentIcb; 277 UInt16 Flags; 278 IsDirCIcbTag279 bool IsDir() const { return FileType == ICB_FILE_TYPE_DIR; } GetDescriptorTypeCIcbTag280 int GetDescriptorType() const { return Flags & 3; } 281 void Parse(const Byte *p); 282 }; 283 284 285 // ECMA 4/14.4.3 286 // UDF 2.3.4.2 FileCharacteristics 287 288 // const Byte FILEID_CHARACS_Existance = (1 << 0); 289 const Byte FILEID_CHARACS_Dir = (1 << 1); 290 const Byte FILEID_CHARACS_Deleted = (1 << 2); 291 const Byte FILEID_CHARACS_Parent = (1 << 3); 292 // const Byte FILEID_CHARACS_Metadata = (1 << 4); 293 294 struct CFile 295 { 296 int ItemIndex; 297 // UInt16 FileVersion; 298 // Byte FileCharacteristics; 299 // CByteBuffer ImplUse; 300 CDString Id; 301 CFileCFile302 CFile(): /* FileVersion(0), FileCharacteristics(0), */ ItemIndex(-1) {} GetNameCFile303 UString GetName() const { return Id.GetString(); } 304 }; 305 306 307 struct CMyExtent 308 { 309 UInt32 Pos; 310 UInt32 Len; 311 unsigned PartitionRef; // index in CLogVol::PartitionMaps 312 GetLenCMyExtent313 UInt32 GetLen() const { return Len & 0x3FFFFFFF; } GetTypeCMyExtent314 UInt32 GetType() const { return Len >> 30; } IsRecAndAllocCMyExtent315 bool IsRecAndAlloc() const { return GetType() == SHORT_ALLOC_DESC_TYPE_RecordedAndAllocated; } 316 }; 317 318 319 struct CItem 320 { 321 CIcbTag IcbTag; 322 323 // UInt32 Uid; 324 // UInt32 Gid; 325 // UInt32 Permissions; 326 UInt16 FileLinkCount; 327 // Byte RecordFormat; 328 // Byte RecordDisplayAttr; 329 // UInt32 RecordLen; 330 UInt64 Size; 331 UInt64 NumLogBlockRecorded; 332 // UInt64 ObjectSize; 333 334 CTime ATime; 335 CTime MTime; 336 CTime AttribTime; // Attribute time : most recent date and time of the day of file creation or modification of the attributes of. 337 CTime CreateTime; 338 // UInt32 CheckPoint; 339 // CLongAllocDesc ExtendedAttrIcb; 340 // CRegId ImplId; 341 // UInt64 UniqueId; 342 343 bool IsExtended; 344 bool IsInline; 345 CByteBuffer InlineData; 346 CRecordVector<CMyExtent> Extents; 347 CUIntVector SubFiles; 348 349 void Parse(const Byte *p); 350 IsRecAndAllocCItem351 bool IsRecAndAlloc() const 352 { 353 FOR_VECTOR (i, Extents) 354 if (!Extents[i].IsRecAndAlloc()) 355 return false; 356 return true; 357 } 358 GetChunksSumSizeCItem359 UInt64 GetChunksSumSize() const 360 { 361 if (IsInline) 362 return InlineData.Size(); 363 UInt64 size = 0; 364 FOR_VECTOR (i, Extents) 365 size += Extents[i].GetLen(); 366 return size; 367 } 368 CheckChunkSizesCItem369 bool CheckChunkSizes() const { return GetChunksSumSize() == Size; } 370 IsDirCItem371 bool IsDir() const { return IcbTag.IsDir(); } 372 }; 373 374 375 struct CRef 376 { 377 unsigned FileIndex; 378 int Parent; 379 }; 380 381 382 // ECMA 4 / 14.1 383 struct CFileSet 384 { 385 CRecordVector<CRef> Refs; 386 387 CTime RecordingTime; 388 // UInt16 InterchangeLevel; 389 // UInt16 MaxInterchangeLevel; 390 UInt32 FileSetNumber; 391 UInt32 FileSetDescNumber; 392 CDString128 LogicalVolumeId; 393 CDString32 Id; 394 CDString32 CopyrightId; 395 CDString32 AbstractId; 396 397 CLongAllocDesc RootDirICB; 398 CRegId DomainId; 399 // CLongAllocDesc SystemStreamDirICB; 400 }; 401 402 403 /* 8.3 Volume descriptors 404 8.4 405 A Volume Descriptor Sequence: 406 shall contain one or more Primary Volume Descriptors. 407 */ 408 409 // ECMA 3/10.6 410 // UDF 2.2.4 LogicalVolumeDescriptor 411 412 struct CLogVol 413 { 414 CObjectVector<CPartitionMap> PartitionMaps; 415 CObjectVector<CFileSet> FileSets; 416 417 UInt32 BlockSize; 418 CDString128 Id; 419 CRegId DomainId; 420 421 // Byte ContentsUse[16]; 422 CLongAllocDesc FileSetLocation; // UDF 423 424 CRegId ImplId; 425 // Byte ImplUse[128]; 426 // CExtent IntegritySequenceExtent; 427 GetNameCLogVol428 UString GetName() const { return Id.GetString(); } 429 }; 430 431 432 Z7_PURE_INTERFACES_BEGIN 433 struct Z7_DECLSPEC_NOVTABLE CProgressVirt 434 { 435 virtual HRESULT SetTotal(UInt64 numBytes) =0; \ 436 virtual HRESULT SetCompleted(UInt64 numFiles, UInt64 numBytes) =0; \ 437 virtual HRESULT SetCompleted() =0; \ 438 }; 439 Z7_PURE_INTERFACES_END 440 441 class CInArchive 442 { 443 public: 444 CObjectVector<CLogVol> LogVols; 445 CObjectVector<CItem> Items; 446 CObjectVector<CFile> Files; 447 CObjectVector<CPartition> Partitions; 448 449 unsigned SecLogSize; 450 UInt64 PhySize; 451 UInt64 FileSize; 452 453 bool IsArc; 454 bool Unsupported; 455 bool UnexpectedEnd; 456 bool NoEndAnchor; 457 458 CObjectVector<CPrimeVol> PrimeVols; 459 460 HRESULT Open(IInStream *inStream, CProgressVirt *progress); 461 void Clear(); 462 463 UString GetComment() const; 464 UString GetItemPath(unsigned volIndex, unsigned fsIndex, unsigned refIndex, 465 bool showVolName, bool showFsName) const; 466 467 bool CheckItemExtents(unsigned volIndex, const CItem &item) const; 468 469 private: 470 IInStream *_stream; 471 CProgressVirt *_progress; 472 473 HRESULT Read(unsigned volIndex, unsigned partitionRef, UInt32 blockPos, UInt32 len, Byte *buf); 474 HRESULT ReadLad(unsigned volIndex, const CLongAllocDesc &lad, Byte *buf); 475 HRESULT ReadFromFile(unsigned volIndex, const CItem &item, CByteBuffer &buf); 476 477 HRESULT ReadFileItem(unsigned volIndex, unsigned fsIndex, const CLongAllocDesc &lad, bool isDir, int numRecurseAllowed); 478 HRESULT ReadItem(unsigned volIndex, int fsIndex, const CLongAllocDesc &lad, bool isDir, int numRecurseAllowed); 479 480 HRESULT Open2(); 481 HRESULT FillRefs(CFileSet &fs, unsigned fileIndex, int parent, int numRecurseAllowed); 482 483 UInt64 _processedProgressBytes; 484 485 UInt64 _fileNameLengthTotal; 486 unsigned _numRefs; 487 UInt32 _numExtents; 488 UInt64 _inlineExtentsSize; 489 bool CheckExtent(unsigned volIndex, unsigned partitionRef, UInt32 blockPos, UInt32 len) const; 490 UpdatePhySize(UInt64 val)491 void UpdatePhySize(UInt64 val) 492 { 493 if (PhySize < val) 494 PhySize = val; 495 } 496 UpdatePhySize(const CExtent & e)497 void UpdatePhySize(const CExtent &e) 498 { 499 UpdatePhySize(((UInt64)e.Pos << SecLogSize) + e.Len); 500 } 501 }; 502 503 API_FUNC_IsArc IsArc_Udf(const Byte *p, size_t size); 504 505 }} 506 507 #endif 508