diff options
Diffstat (limited to 'src/libs/7zip/unix/CPP/7zip/Archive/Udf/UdfIn.cpp')
-rw-r--r-- | src/libs/7zip/unix/CPP/7zip/Archive/Udf/UdfIn.cpp | 876 |
1 files changed, 876 insertions, 0 deletions
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Udf/UdfIn.cpp b/src/libs/7zip/unix/CPP/7zip/Archive/Udf/UdfIn.cpp new file mode 100644 index 000000000..60d5fc2ad --- /dev/null +++ b/src/libs/7zip/unix/CPP/7zip/Archive/Udf/UdfIn.cpp @@ -0,0 +1,876 @@ +// Archive/UdfIn.cpp + +#include "StdAfx.h" + +#include "../../../../C/CpuArch.h" + +#include "../../Common/StreamUtils.h" + +#include "UdfIn.h" + +#define Get16(p) GetUi16(p) +#define Get32(p) GetUi32(p) +#define Get64(p) GetUi64(p) + +namespace NArchive { +namespace NUdf { + +const int kNumPartitionsMax = 64; +const int kNumLogVolumesMax = 64; +const int kNumRecureseLevelsMax = 1 << 10; +const int kNumItemsMax = 1 << 27; +const int kNumFilesMax = 1 << 28; +const int kNumRefsMax = 1 << 28; +const UInt32 kNumExtentsMax = (UInt32)1 << 30; +const UInt64 kFileNameLengthTotalMax = (UInt64)1 << 33; +const UInt64 kInlineExtentsSizeMax = (UInt64)1 << 33; + +void MY_FAST_CALL Crc16GenerateTable(void); + +#define CRC16_INIT_VAL 0 +#define CRC16_GET_DIGEST(crc) (crc) +#define CRC16_UPDATE_BYTE(crc, b) (g_Crc16Table[(((crc) >> 8) ^ (b)) & 0xFF] ^ ((crc) << 8)) + +#define kCrc16Poly 0x1021 +UInt16 g_Crc16Table[256]; + +void MY_FAST_CALL Crc16GenerateTable(void) +{ + UInt32 i; + for (i = 0; i < 256; i++) + { + UInt32 r = (i << 8); + for (int j = 8; j > 0; j--) + r = ((r & 0x8000) ? ((r << 1) ^ kCrc16Poly) : (r << 1)) & 0xFFFF; + g_Crc16Table[i] = (UInt16)r; + } +} + +UInt16 MY_FAST_CALL Crc16_Update(UInt16 v, const void *data, size_t size) +{ + const Byte *p = (const Byte *)data; + for (; size > 0 ; size--, p++) + v = CRC16_UPDATE_BYTE(v, *p); + return v; +} + +UInt16 MY_FAST_CALL Crc16Calc(const void *data, size_t size) +{ + return Crc16_Update(CRC16_INIT_VAL, data, size); +} + +struct CCrc16TableInit { CCrc16TableInit() { Crc16GenerateTable(); } } g_Crc16TableInit; + +void CDString128::Parse(const Byte *buf) { memcpy(Data, buf, sizeof(Data)); } + +void CDString::Parse(const Byte *p, unsigned size) +{ + Data.SetCapacity(size); + memcpy(Data, p, size); +} + +static UString ParseDString(const Byte *data, int size) +{ + UString res; + wchar_t *p; + if (size > 0) + { + Byte type = data[0]; + if (type == 8) + { + p = res.GetBuffer((int)size + 1); + for (int i = 1; i < size; i++) + { + wchar_t c = data[i]; + if (c == 0) + break; + *p++ = c; + } + } + else if (type == 16) + { + p = res.GetBuffer((int)size / 2 + 1); + for (int i = 1; i + 2 <= size; i += 2) + { + wchar_t c = ((wchar_t)data[i] << 8) | data[i + 1]; + if (c == 0) + break; + *p++ = c; + } + } + else + return L"[unknow]"; + *p++ = 0; + res.ReleaseBuffer(); + } + return res; +} + +UString CDString:: GetString() const { return ParseDString(Data, (int)Data.GetCapacity()); } +UString CDString128::GetString() const +{ + int size = Data[sizeof(Data) - 1]; + return ParseDString(Data, MyMin(size, (int)(sizeof(Data) - 1))); +} + +void CTime::Parse(const Byte *buf) { memcpy(Data, buf, sizeof(Data)); } + +/* +void CRegId::Parse(const Byte *buf) +{ + Flags = buf[0]; + memcpy(Id, buf + 1, sizeof(Id)); + memcpy(Suffix, buf + 24, sizeof(Suffix)); +} +*/ + +// ECMA 3/7.1 + +struct CExtent +{ + UInt32 Len; + UInt32 Pos; + + void Parse(const Byte *buf); +}; + +void CExtent::Parse(const Byte *buf) +{ + Len = Get32(buf); + Pos = Get32(buf + 4); +} + +// ECMA 3/7.2 + +struct CTag +{ + UInt16 Id; + UInt16 Version; + // Byte Checksum; + // UInt16 SerialNumber; + // UInt16 Crc; + // UInt16 CrcLen; + // UInt32 TagLocation; + + HRESULT Parse(const Byte *buf, size_t size); +}; + +HRESULT CTag::Parse(const Byte *buf, size_t size) +{ + if (size < 16) + return S_FALSE; + Byte sum = 0; + int i; + for (i = 0; i < 4; i++) sum = sum + buf[i]; + for (i = 5; i < 16; i++) sum = sum + buf[i]; + if (sum != buf[4] || buf[5] != 0) return S_FALSE; + + Id = Get16(buf); + Version = Get16(buf + 2); + // SerialNumber = Get16(buf + 6); + UInt16 crc = Get16(buf + 8); + UInt16 crcLen = Get16(buf + 10); + // TagLocation = Get32(buf + 12); + + if (size >= 16 + (size_t)crcLen) + if (crc == Crc16Calc(buf + 16, crcLen)) + return S_OK; + return S_FALSE; +} + +// ECMA 3/7.2.1 + +enum EDescriptorType +{ + DESC_TYPE_SpoaringTable = 0, // UDF + DESC_TYPE_PrimVol = 1, + DESC_TYPE_AnchorVolPtr = 2, + DESC_TYPE_VolPtr = 3, + DESC_TYPE_ImplUseVol = 4, + DESC_TYPE_Partition = 5, + DESC_TYPE_LogicalVol = 6, + DESC_TYPE_UnallocSpace = 7, + DESC_TYPE_Terminating = 8, + DESC_TYPE_LogicalVolIntegrity = 9, + DESC_TYPE_FileSet = 256, + DESC_TYPE_FileId = 257, + DESC_TYPE_AllocationExtent = 258, + DESC_TYPE_Indirect = 259, + DESC_TYPE_Terminal = 260, + DESC_TYPE_File = 261, + DESC_TYPE_ExtendedAttrHeader = 262, + DESC_TYPE_UnallocatedSpace = 263, + DESC_TYPE_SpaceBitmap = 264, + DESC_TYPE_PartitionIntegrity = 265, + DESC_TYPE_ExtendedFile = 266 +}; + + +void CLogBlockAddr::Parse(const Byte *buf) +{ + Pos = Get32(buf); + PartitionRef = Get16(buf + 4); +} + +void CShortAllocDesc::Parse(const Byte *buf) +{ + Len = Get32(buf); + Pos = Get32(buf + 4); +} + +/* +void CADImpUse::Parse(const Byte *buf) +{ + Flags = Get16(buf); + UdfUniqueId = Get32(buf + 2); +} +*/ + +void CLongAllocDesc::Parse(const Byte *buf) +{ + Len = Get32(buf); + Location.Parse(buf + 4); + // memcpy(ImplUse, buf + 10, sizeof(ImplUse)); + // adImpUse.Parse(ImplUse); +} + +bool CInArchive::CheckExtent(int volIndex, int partitionRef, UInt32 blockPos, UInt32 len) const +{ + const CLogVol &vol = LogVols[volIndex]; + const CPartition &partition = Partitions[vol.PartitionMaps[partitionRef].PartitionIndex]; + UInt64 offset = ((UInt64)partition.Pos << SecLogSize) + (UInt64)blockPos * vol.BlockSize; + return (offset + len) <= (((UInt64)partition.Pos + partition.Len) << SecLogSize); +} + +bool CInArchive::CheckItemExtents(int volIndex, const CItem &item) const +{ + for (int i = 0; i < item.Extents.Size(); i++) + { + const CMyExtent &e = item.Extents[i]; + if (!CheckExtent(volIndex, e.PartitionRef, e.Pos, e.GetLen())) + return false; + } + return true; +} + +HRESULT CInArchive::Read(int volIndex, int partitionRef, UInt32 blockPos, UInt32 len, Byte *buf) +{ + if (!CheckExtent(volIndex, partitionRef, blockPos, len)) + return S_FALSE; + const CLogVol &vol = LogVols[volIndex]; + const CPartition &partition = Partitions[vol.PartitionMaps[partitionRef].PartitionIndex]; + RINOK(_stream->Seek(((UInt64)partition.Pos << SecLogSize) + + (UInt64)blockPos * vol.BlockSize, STREAM_SEEK_SET, NULL)); + return ReadStream_FALSE(_stream, buf, len); +} + +HRESULT CInArchive::Read(int volIndex, const CLongAllocDesc &lad, Byte *buf) +{ + return Read(volIndex, lad.Location.PartitionRef, lad.Location.Pos, lad.GetLen(), (Byte *)buf); +} + +HRESULT CInArchive::ReadFromFile(int volIndex, const CItem &item, CByteBuffer &buf) +{ + if (item.Size >= (UInt32)1 << 30) + return S_FALSE; + if (item.IsInline) + { + buf = item.InlineData; + return S_OK; + } + buf.SetCapacity((size_t)item.Size); + size_t pos = 0; + for (int i = 0; i < item.Extents.Size(); i++) + { + const CMyExtent &e = item.Extents[i]; + UInt32 len = e.GetLen(); + RINOK(Read(volIndex, e.PartitionRef, e.Pos, len, (Byte *)buf + pos)); + pos += len; + } + return S_OK; +} + + +void CIcbTag::Parse(const Byte *p) +{ + // PriorDirectNum = Get32(p); + // StrategyType = Get16(p + 4); + // StrategyParam = Get16(p + 6); + // MaxNumOfEntries = Get16(p + 8); + FileType = p[11]; + // ParentIcb.Parse(p + 12); + Flags = Get16(p + 18); +} + +void CItem::Parse(const Byte *p) +{ + // Uid = Get32(p + 36); + // Gid = Get32(p + 40); + // Permissions = Get32(p + 44); + // FileLinkCount = Get16(p + 48); + // RecordFormat = p[50]; + // RecordDisplayAttr = p[51]; + // RecordLen = Get32(p + 52); + Size = Get64(p + 56); + NumLogBlockRecorded = Get64(p + 64); + ATime.Parse(p + 72); + MTime.Parse(p + 84); + // AttrtTime.Parse(p + 96); + // CheckPoint = Get32(p + 108); + // ExtendedAttrIcb.Parse(p + 112); + // ImplId.Parse(p + 128); + // UniqueId = Get64(p + 160); +} + +// 4/14.4 +struct CFileId +{ + // UInt16 FileVersion; + Byte FileCharacteristics; + // CByteBuffer ImplUse; + CDString Id; + CLongAllocDesc Icb; + + bool IsItLinkParent() const { return (FileCharacteristics & FILEID_CHARACS_Parent) != 0; } + HRESULT Parse(const Byte *p, size_t size, size_t &processed); +}; + +HRESULT CFileId::Parse(const Byte *p, size_t size, size_t &processed) +{ + processed = 0; + if (size < 38) + return S_FALSE; + CTag tag; + RINOK(tag.Parse(p, size)); + if (tag.Id != DESC_TYPE_FileId) + return S_FALSE; + // FileVersion = Get16(p + 16); + FileCharacteristics = p[18]; + unsigned idLen = p[19]; + Icb.Parse(p + 20); + unsigned impLen = Get16(p + 36); + if (size < 38 + idLen + impLen) + return S_FALSE; + // ImplUse.SetCapacity(impLen); + processed = 38; + // memcpy(ImplUse, p + processed, impLen); + processed += impLen; + Id.Parse(p + processed, idLen); + processed += idLen; + for (;(processed & 3) != 0; processed++) + if (p[processed] != 0) + return S_FALSE; + return (processed <= size) ? S_OK : S_FALSE; +} + +HRESULT CInArchive::ReadFileItem(int volIndex, int fsIndex, const CLongAllocDesc &lad, int numRecurseAllowed) +{ + if (Files.Size() % 100 == 0) + RINOK(_progress->SetCompleted(Files.Size(), _processedProgressBytes)); + if (numRecurseAllowed-- == 0) + return S_FALSE; + CFile &file = Files.Back(); + const CLogVol &vol = LogVols[volIndex]; + CPartition &partition = Partitions[vol.PartitionMaps[lad.Location.PartitionRef].PartitionIndex]; + + UInt32 key = lad.Location.Pos; + UInt32 value; + const UInt32 kRecursedErrorValue = (UInt32)(Int32)-1; + if (partition.Map.Find(key, value)) + { + if (value == kRecursedErrorValue) + return S_FALSE; + file.ItemIndex = value; + } + else + { + value = Items.Size(); + file.ItemIndex = (int)value; + if (partition.Map.Set(key, kRecursedErrorValue)) + return S_FALSE; + RINOK(ReadItem(volIndex, fsIndex, lad, numRecurseAllowed)); + if (!partition.Map.Set(key, value)) + return S_FALSE; + } + return S_OK; +} + +HRESULT CInArchive::ReadItem(int volIndex, int fsIndex, const CLongAllocDesc &lad, int numRecurseAllowed) +{ + if (Items.Size() > kNumItemsMax) + return S_FALSE; + Items.Add(CItem()); + CItem &item = Items.Back(); + + const CLogVol &vol = LogVols[volIndex]; + + if (lad.GetLen() != vol.BlockSize) + return S_FALSE; + + CByteBuffer buf; + size_t size = lad.GetLen(); + buf.SetCapacity(size); + RINOK(Read(volIndex, lad, buf)); + + CTag tag; + const Byte *p = buf; + RINOK(tag.Parse(p, size)); + if (tag.Id != DESC_TYPE_File) + return S_FALSE; + + item.IcbTag.Parse(p + 16); + if (item.IcbTag.FileType != ICB_FILE_TYPE_DIR && + item.IcbTag.FileType != ICB_FILE_TYPE_FILE) + return S_FALSE; + + item.Parse(p); + + _processedProgressBytes += (UInt64)item.NumLogBlockRecorded * vol.BlockSize + size; + + UInt32 extendedAttrLen = Get32(p + 168); + UInt32 allocDescriptorsLen = Get32(p + 172); + + if ((extendedAttrLen & 3) != 0) + return S_FALSE; + int pos = 176; + if (extendedAttrLen > size - pos) + return S_FALSE; + /* + if (extendedAttrLen != 16) + { + if (extendedAttrLen < 24) + return S_FALSE; + CTag attrTag; + RINOK(attrTag.Parse(p + pos, size)); + if (attrTag.Id != DESC_TYPE_ExtendedAttrHeader) + return S_FALSE; + // UInt32 implAttrLocation = Get32(p + pos + 16); + // UInt32 applicationlAttrLocation = Get32(p + pos + 20); + } + */ + pos += extendedAttrLen; + + int desctType = item.IcbTag.GetDescriptorType(); + if (allocDescriptorsLen > size - pos) + return S_FALSE; + if (desctType == ICB_DESC_TYPE_INLINE) + { + item.IsInline = true; + item.InlineData.SetCapacity(allocDescriptorsLen); + memcpy(item.InlineData, p + pos, allocDescriptorsLen); + } + else + { + item.IsInline = false; + if (desctType != ICB_DESC_TYPE_SHORT && desctType != ICB_DESC_TYPE_LONG) + return S_FALSE; + for (UInt32 i = 0; i < allocDescriptorsLen;) + { + CMyExtent e; + if (desctType == ICB_DESC_TYPE_SHORT) + { + if (i + 8 > allocDescriptorsLen) + return S_FALSE; + CShortAllocDesc sad; + sad.Parse(p + pos + i); + e.Pos = sad.Pos; + e.Len = sad.Len; + e.PartitionRef = lad.Location.PartitionRef; + i += 8; + } + else + { + if (i + 16 > allocDescriptorsLen) + return S_FALSE; + CLongAllocDesc ladNew; + ladNew.Parse(p + pos + i); + e.Pos = ladNew.Location.Pos; + e.PartitionRef = ladNew.Location.PartitionRef; + e.Len = ladNew.Len; + i += 16; + } + item.Extents.Add(e); + } + } + + if (item.IcbTag.IsDir()) + { + if (!item.CheckChunkSizes() || !CheckItemExtents(volIndex, item)) + return S_FALSE; + CByteBuffer buf; + RINOK(ReadFromFile(volIndex, item, buf)); + item.Size = 0; + item.Extents.ClearAndFree(); + item.InlineData.Free(); + + const Byte *p = buf; + size = buf.GetCapacity(); + size_t processedTotal = 0; + for (; processedTotal < size;) + { + size_t processedCur; + CFileId fileId; + RINOK(fileId.Parse(p + processedTotal, size - processedTotal, processedCur)); + if (!fileId.IsItLinkParent()) + { + CFile file; + // file.FileVersion = fileId.FileVersion; + // file.FileCharacteristics = fileId.FileCharacteristics; + // file.ImplUse = fileId.ImplUse; + file.Id = fileId.Id; + + _fileNameLengthTotal += file.Id.Data.GetCapacity(); + if (_fileNameLengthTotal > kFileNameLengthTotalMax) + return S_FALSE; + + item.SubFiles.Add(Files.Size()); + if (Files.Size() > kNumFilesMax) + return S_FALSE; + Files.Add(file); + RINOK(ReadFileItem(volIndex, fsIndex, fileId.Icb, numRecurseAllowed)); + } + processedTotal += processedCur; + } + } + else + { + if ((UInt32)item.Extents.Size() > kNumExtentsMax - _numExtents) + return S_FALSE; + _numExtents += item.Extents.Size(); + + if (item.InlineData.GetCapacity() > kInlineExtentsSizeMax - _inlineExtentsSize) + return S_FALSE; + _inlineExtentsSize += item.InlineData.GetCapacity(); + } + + return S_OK; +} + +HRESULT CInArchive::FillRefs(CFileSet &fs, int fileIndex, int parent, int numRecurseAllowed) +{ + if (_numRefs % 10000 == 0) + { + RINOK(_progress->SetCompleted()); + } + if (numRecurseAllowed-- == 0) + return S_FALSE; + if (_numRefs >= kNumRefsMax) + return S_FALSE; + _numRefs++; + CRef ref; + ref.FileIndex = fileIndex; + ref.Parent = parent; + parent = fs.Refs.Size(); + fs.Refs.Add(ref); + const CItem &item = Items[Files[fileIndex].ItemIndex]; + for (int i = 0; i < item.SubFiles.Size(); i++) + { + RINOK(FillRefs(fs, item.SubFiles[i], parent, numRecurseAllowed)); + } + return S_OK; +} + +HRESULT CInArchive::Open2() +{ + Clear(); + + UInt64 fileSize; + RINOK(_stream->Seek(0, STREAM_SEEK_END, &fileSize)); + + // Some UDFs contain additional 2 KB of zeros, so we also check 12, corrected to 11. + const int kSecLogSizeMax = 12; + Byte buf[1 << kSecLogSizeMax]; + Byte kSizesLog[] = { 11, 8, 12 }; + + for (int i = 0;; i++) + { + if (i == sizeof(kSizesLog) / sizeof(kSizesLog[0])) + return S_FALSE; + SecLogSize = kSizesLog[i]; + Int32 bufSize = 1 << SecLogSize; + if (bufSize > fileSize) + return S_FALSE; + RINOK(_stream->Seek(-bufSize, STREAM_SEEK_END, NULL)); + RINOK(ReadStream_FALSE(_stream, buf, bufSize)); + CTag tag; + if (tag.Parse(buf, bufSize) == S_OK) + if (tag.Id == DESC_TYPE_AnchorVolPtr) + break; + } + if (SecLogSize == 12) + SecLogSize = 11; + + CExtent extentVDS; + extentVDS.Parse(buf + 16); + + for (UInt32 location = extentVDS.Pos; ; location++) + { + size_t bufSize = 1 << SecLogSize; + size_t pos = 0; + RINOK(_stream->Seek((UInt64)location << SecLogSize, STREAM_SEEK_SET, NULL)); + RINOK(ReadStream_FALSE(_stream, buf, bufSize)); + CTag tag; + RINOK(tag.Parse(buf + pos, bufSize - pos)); + if (tag.Id == DESC_TYPE_Terminating) + break; + if (tag.Id == DESC_TYPE_Partition) + { + if (Partitions.Size() >= kNumPartitionsMax) + return S_FALSE; + CPartition partition; + // UInt32 volDescSeqNumer = Get32(buf + 16); + // partition.Flags = Get16(buf + 20); + partition.Number = Get16(buf + 22); + // partition.ContentsId.Parse(buf + 24); + + // memcpy(partition.ContentsUse, buf + 56, sizeof(partition.ContentsUse)); + // ContentsUse is Partition Header Description. + + // partition.AccessType = Get32(buf + 184); + partition.Pos = Get32(buf + 188); + partition.Len = Get32(buf + 192); + // partition.ImplId.Parse(buf + 196); + // memcpy(partition.ImplUse, buf + 228, sizeof(partition.ImplUse)); + + Partitions.Add(partition); + } + else if (tag.Id == DESC_TYPE_LogicalVol) + { + if (LogVols.Size() >= kNumLogVolumesMax) + return S_FALSE; + CLogVol vol; + vol.Id.Parse(buf + 84); + vol.BlockSize = Get32(buf + 212); + // vol.DomainId.Parse(buf + 216); + + if (vol.BlockSize < 512 || vol.BlockSize > ((UInt32)1 << 30)) + return S_FALSE; + + // memcpy(vol.ContentsUse, buf + 248, sizeof(vol.ContentsUse)); + vol.FileSetLocation.Parse(buf + 248); + + // UInt32 mapTableLength = Get32(buf + 264); + UInt32 numPartitionMaps = Get32(buf + 268); + if (numPartitionMaps > kNumPartitionsMax) + return S_FALSE; + // vol.ImplId.Parse(buf + 272); + // memcpy(vol.ImplUse, buf + 128, sizeof(vol.ImplUse)); + size_t pos = 440; + for (UInt32 i = 0; i < numPartitionMaps; i++) + { + if (pos + 2 > bufSize) + return S_FALSE; + CPartitionMap pm; + pm.Type = buf[pos]; + // pm.Length = buf[pos + 1]; + Byte len = buf[pos + 1]; + + if (pos + len > bufSize) + return S_FALSE; + + // memcpy(pm.Data, buf + pos + 2, pm.Length - 2); + if (pm.Type == 1) + { + if (pos + 6 > bufSize) + return S_FALSE; + // pm.VolSeqNumber = Get16(buf + pos + 2); + pm.PartitionNumber = Get16(buf + pos + 4); + } + else + return S_FALSE; + pos += len; + vol.PartitionMaps.Add(pm); + } + LogVols.Add(vol); + } + } + + UInt64 totalSize = 0; + + int volIndex; + for (volIndex = 0; volIndex < LogVols.Size(); volIndex++) + { + CLogVol &vol = LogVols[volIndex]; + for (int pmIndex = 0; pmIndex < vol.PartitionMaps.Size(); pmIndex++) + { + CPartitionMap &pm = vol.PartitionMaps[pmIndex]; + int i; + for (i = 0; i < Partitions.Size(); i++) + { + CPartition &part = Partitions[i]; + if (part.Number == pm.PartitionNumber) + { + if (part.VolIndex >= 0) + return S_FALSE; + pm.PartitionIndex = i; + part.VolIndex = volIndex; + + totalSize += (UInt64)part.Len << SecLogSize; + break; + } + } + if (i == Partitions.Size()) + return S_FALSE; + } + } + + RINOK(_progress->SetTotal(totalSize)); + + for (volIndex = 0; volIndex < LogVols.Size(); volIndex++) + { + CLogVol &vol = LogVols[volIndex]; + + CLongAllocDesc nextExtent = vol.FileSetLocation; + // while (nextExtent.ExtentLen != 0) + // for (int i = 0; i < 1; i++) + { + if (nextExtent.GetLen() < 512) + return S_FALSE; + CByteBuffer buf; + buf.SetCapacity(nextExtent.GetLen()); + RINOK(Read(volIndex, nextExtent, buf)); + const Byte *p = buf; + size_t size = nextExtent.GetLen(); + + CTag tag; + RINOK(tag.Parse(p, size)); + if (tag.Id != DESC_TYPE_FileSet) + return S_FALSE; + + CFileSet fs; + fs.RecodringTime.Parse(p + 16); + // fs.InterchangeLevel = Get16(p + 18); + // fs.MaxInterchangeLevel = Get16(p + 20); + // fs.FileSetNumber = Get32(p + 40); + // fs.FileSetDescNumber = Get32(p + 44); + + // fs.Id.Parse(p + 304); + // fs.CopyrightId.Parse(p + 336); + // fs.AbstractId.Parse(p + 368); + + fs.RootDirICB.Parse(p + 400); + // fs.DomainId.Parse(p + 416); + + // fs.SystemStreamDirICB.Parse(p + 464); + + vol.FileSets.Add(fs); + + // nextExtent.Parse(p + 448); + } + + for (int fsIndex = 0; fsIndex < vol.FileSets.Size(); fsIndex++) + { + CFileSet &fs = vol.FileSets[fsIndex]; + int fileIndex = Files.Size(); + Files.Add(CFile()); + RINOK(ReadFileItem(volIndex, fsIndex, fs.RootDirICB, kNumRecureseLevelsMax)); + RINOK(FillRefs(fs, fileIndex, -1, kNumRecureseLevelsMax)); + } + } + + return S_OK; +} + +HRESULT CInArchive::Open(IInStream *inStream, CProgressVirt *progress) +{ + _progress = progress; + _stream = inStream; + HRESULT res; + try { res = Open2(); } + catch(...) { Clear(); res = S_FALSE; } + _stream.Release(); + return res; +} + +void CInArchive::Clear() +{ + Partitions.Clear(); + LogVols.Clear(); + Items.Clear(); + Files.Clear(); + _fileNameLengthTotal = 0; + _numRefs = 0; + _numExtents = 0; + _inlineExtentsSize = 0; + _processedProgressBytes = 0; +} + +UString CInArchive::GetComment() const +{ + UString res; + for (int i = 0; i < LogVols.Size(); i++) + { + if (i > 0) + res += L" "; + res += LogVols[i].GetName(); + } + return res; +} + +static UString GetSpecName(const UString &name) +{ + UString name2 = name; + name2.Trim(); + if (name2.IsEmpty()) + { + /* + wchar_t s[32]; + ConvertUInt64ToString(id, s); + return L"[" + (UString)s + L"]"; + */ + return L"[]"; + } + return name; +} + +static void UpdateWithName(UString &res, const UString &addString) +{ + if (res.IsEmpty()) + res = addString; + else + res = addString + WCHAR_PATH_SEPARATOR + res; +} + +UString CInArchive::GetItemPath(int volIndex, int fsIndex, int refIndex, + bool showVolName, bool showFsName) const +{ + // showVolName = true; + const CLogVol &vol = LogVols[volIndex]; + const CFileSet &fs = vol.FileSets[fsIndex]; + + UString name; + + for (;;) + { + const CRef &ref = fs.Refs[refIndex]; + refIndex = ref.Parent; + if (refIndex < 0) + break; + UpdateWithName(name, GetSpecName(Files[ref.FileIndex].GetName())); + } + + if (showFsName) + { + wchar_t s[32]; + ConvertUInt64ToString(fsIndex, s); + UString newName = L"File Set "; + newName += s; + UpdateWithName(name, newName); + } + + if (showVolName) + { + wchar_t s[32]; + ConvertUInt64ToString(volIndex, s); + UString newName = s; + UString newName2 = vol.GetName(); + if (newName2.IsEmpty()) + newName2 = L"Volume"; + newName += L'-'; + newName += newName2; + UpdateWithName(name, newName); + } + return name; +} + +}} |