From 93be7d4abfd4233228f58ee1fbbcd76d91be66a4 Mon Sep 17 00:00:00 2001 From: Igor Pavlov <87184205+ip7z@users.noreply.github.com> Date: Sat, 16 Jul 2022 00:00:00 +0000 Subject: 22.01 --- CPP/7zip/7zip_gcc.mak | 39 +- CPP/7zip/Archive/ApfsHandler.cpp | 447 ++++++++++--- CPP/7zip/Archive/Chm/ChmIn.h | 1 + CPP/7zip/Archive/DmgHandler.cpp | 2 + CPP/7zip/Archive/HfsHandler.cpp | 933 ++++++++++++++++++-------- CPP/7zip/Archive/HfsHandler.h | 85 +++ CPP/7zip/Archive/Udf/UdfHandler.cpp | 48 +- CPP/7zip/Archive/Udf/UdfHandler.h | 2 +- CPP/7zip/Archive/Udf/UdfIn.cpp | 994 ++++++++++++++++++++++------ CPP/7zip/Archive/Udf/UdfIn.h | 260 +++++--- CPP/7zip/Bundles/Alone/makefile.gcc | 13 +- CPP/7zip/Bundles/Alone2/makefile.gcc | 9 + CPP/7zip/Bundles/Alone7z/makefile.gcc | 13 +- CPP/7zip/Bundles/Format7zF/Arc_gcc.mak | 10 +- CPP/7zip/Bundles/Format7zF/Format7z.dsp | 4 + CPP/7zip/Bundles/Format7zF/makefile.gcc | 10 + CPP/7zip/Bundles/LzmaCon/makefile.gcc | 11 +- CPP/7zip/Bundles/SFXCon/makefile.gcc | 13 +- CPP/7zip/Common/FileStreams.cpp | 7 +- CPP/7zip/Compress/LzfseDecoder.cpp | 22 +- CPP/7zip/Compress/LzfseDecoder.h | 11 +- CPP/7zip/UI/Client7z/makefile.gcc | 10 + CPP/7zip/UI/Common/EnumDirItems.cpp | 3 +- CPP/7zip/UI/Common/UpdateCallback.cpp | 8 +- CPP/7zip/UI/Console/Console.dsp | 4 + CPP/7zip/UI/Console/makefile.gcc | 13 +- CPP/7zip/UI/Explorer/resource.rc | 2 +- CPP/7zip/UI/FileManager/FSFolder.cpp | 9 +- CPP/7zip/UI/FileManager/FSFolderCopy.cpp | 7 +- CPP/7zip/UI/FileManager/MyCom2.h | 5 +- CPP/7zip/UI/FileManager/PanelOperations.cpp | 10 +- CPP/7zip/UI/FileManager/SysIconUtils.cpp | 12 +- CPP/7zip/UI/FileManager/TextPairs.cpp | 17 +- CPP/7zip/UI/GUI/CompressDialog.cpp | 8 +- CPP/Windows/MemoryLock.cpp | 2 +- CPP/Windows/SecurityUtils.cpp | 13 +- CPP/Windows/SecurityUtils.h | 83 +-- CPP/Windows/Shell.cpp | 19 +- 38 files changed, 2395 insertions(+), 764 deletions(-) create mode 100644 CPP/7zip/Archive/HfsHandler.h (limited to 'CPP') diff --git a/CPP/7zip/7zip_gcc.mak b/CPP/7zip/7zip_gcc.mak index b242459..f65cff2 100644 --- a/CPP/7zip/7zip_gcc.mak +++ b/CPP/7zip/7zip_gcc.mak @@ -33,6 +33,11 @@ CFLAGS_BASE = -O2 $(CFLAGS_BASE_LIST) $(CFLAGS_WARN_WALL) $(CFLAGS_WARN) \ ifdef SystemDrive IS_MINGW = 1 +else +ifdef SYSTEMDRIVE +# ifdef OS +IS_MINGW = 1 +endif endif ifdef IS_MINGW @@ -97,20 +102,30 @@ PROGPATH_STATIC = $(O)/$(PROG)s$(SHARED_EXT) ifdef IS_MINGW +ifdef MSYSTEM +RM = rm -f +MY_MKDIR=mkdir -p +DEL_OBJ_EXE = -$(RM) $(PROGPATH) $(PROGPATH_STATIC) $(OBJS) +LIB_HTMLHELP=-lhtmlhelp +else RM = del MY_MKDIR=mkdir -LIB2_GUI = -lOle32 -lGdi32 -lComctl32 -lComdlg32 +DEL_OBJ_EXE = -$(RM) $(O)\*.o $(O)\$(PROG).exe $(O)\$(PROG).dll +endif + +LIB2_GUI = -lOle32 -lGdi32 -lComctl32 -lComdlg32 $(LIB_HTMLHELP) LIB2 = -loleaut32 -luuid -ladvapi32 -lUser32 $(LIB2_GUI) CXXFLAGS_EXTRA = -DUNICODE -D_UNICODE # -Wno-delete-non-virtual-dtor -DEL_OBJ_EXE = -$(RM) $(O)\*.o $(O)\$(PROG).exe $(O)\$(PROG).dll else RM = rm -f MY_MKDIR=mkdir -p +DEL_OBJ_EXE = -$(RM) $(PROGPATH) $(PROGPATH_STATIC) $(OBJS) + # CFLAGS_BASE := $(CFLAGS_BASE) -D_7ZIP_ST # CXXFLAGS_EXTRA = -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE @@ -119,9 +134,6 @@ MY_MKDIR=mkdir -p LIB2 = -lpthread -ldl - -DEL_OBJ_EXE = -$(RM) $(PROGPATH) $(PROGPATH_STATIC) $(OBJS) - endif @@ -130,9 +142,19 @@ CFLAGS = $(MY_ARCH_2) $(LOCAL_FLAGS) $(CFLAGS_BASE2) $(CFLAGS_BASE) $(CC_SHARED) ifdef IS_MINGW + +ifdef IS_X64 +AFLAGS_ABI = -win64 +else AFLAGS_ABI = -coff -DABI_CDECL +# -DABI_CDECL +# -DABI_LINUX +# -DABI_CDECL +endif AFLAGS = -nologo $(AFLAGS_ABI) -Fo$(O)/$(basename $( Extents; CObjectVector Attrs; unsigned SymLinkIndex; // index in Attrs + unsigned DecmpfsIndex; // index in Attrs + unsigned ResourceIndex; // index in Attrs + + NHfs::CCompressHeader CompressHeader; CNode(): ItemIndex(VI_MINUS1), @@ -1262,11 +1289,16 @@ struct CNode // NumItems(0), dstream_defined(false), refcnt_defined(false), - SymLinkIndex(VI_MINUS1) + SymLinkIndex(VI_MINUS1), + DecmpfsIndex(VI_MINUS1), + ResourceIndex(VI_MINUS1) {} bool IsDir() const { return MY_LIN_S_ISDIR(mode); } bool IsSymLink() const { return MY_LIN_S_ISLNK(mode); } + + bool Has_UNCOMPRESSED_SIZE() const { return (internal_flags & INODE_HAS_UNCOMPRESSED_SIZE) != 0; } + unsigned Get_Type_From_mode() const { return mode >> 12; } bool GetSize(unsigned attrIndex, UInt64 &size) const @@ -1278,6 +1310,12 @@ struct CNode size = dstream.size; return true; } + size = 0; + if (Has_UNCOMPRESSED_SIZE()) + { + size = uncompressed_size; + return true; + } if (!IsSymLink()) return false; attrIndex = SymLinkIndex; @@ -1301,9 +1339,23 @@ struct CNode size = dstream.alloced_size; return true; } - if (!IsSymLink()) - return false; - attrIndex = SymLinkIndex; + size = 0; + + if (IsSymLink()) + attrIndex = SymLinkIndex; + else + { + if (!CompressHeader.IsCorrect || + !CompressHeader.IsSupported) + return false; + const CAttr &attr = Attrs[DecmpfsIndex]; + if (!CompressHeader.IsMethod_Resource()) + { + size = attr.Data.Size() - CompressHeader.DataPos; + return true; + } + attrIndex = ResourceIndex; + } if (IsViNotDef(attrIndex)) return false; } @@ -1339,17 +1391,17 @@ void CNode::Parse(const Byte *p) G64 (0x28, access_time); G64 (0x30, internal_flags); { - G32(0x38, nchildren); - // G32(0x38, nlink); - } - // G32(0x3c, default_protection_class); - G32(0x40, write_generation_counter); - G32(0x44, bsd_flags); - G32(0x48, owner); - G32(0x4c, group); - G16(0x50, mode); - // G16(0x52, pad1); - // G64 (0x54, uncompressed_size); + G32 (0x38, nchildren); + // G32 (0x38, nlink); + } + // G32 (0x3c, default_protection_class); + G32 (0x40, write_generation_counter); + G32 (0x44, bsd_flags); + G32 (0x48, owner); + G32 (0x4c, group); + G16 (0x50, mode); + // G16 (0x52, pad1); + G64 (0x54, uncompressed_size); } @@ -1364,6 +1416,7 @@ struct CRef bool IsAltStream() const { return IsViDef(AttrIndex); } unsigned GetAttrIndex() const { return AttrIndex; }; #else + // bool IsAltStream() const { return false; } unsigned GetAttrIndex() const { return VI_MINUS1; }; #endif }; @@ -1667,6 +1720,7 @@ struct CDatabase UInt64 ProgressVal_NumFilesTotal; CObjectVector Buffers; + UInt32 MethodsMask; UInt64 GetSize(const UInt32 index) const; void Clear() @@ -1678,6 +1732,8 @@ struct CDatabase ProgressVal_Cur = 0; ProgressVal_Prev = 0; ProgressVal_NumFilesTotal = 0; + + MethodsMask = 0; Vols.Clear(); Refs2.Clear(); @@ -1691,6 +1747,12 @@ struct CDatabase HRESULT OpenVolume(const CObjectMap &omap, const oid_t fs_oid); HRESULT Open2(); + HRESULT GetAttrStream(IInStream *apfsInStream, const CVol &vol, + const CAttr &attr, ISequentialInStream **stream); + + HRESULT GetAttrStream_dstream(IInStream *apfsInStream, const CVol &vol, + const CAttr &attr, ISequentialInStream **stream); + HRESULT GetStream2( IInStream *apfsInStream, const CRecordVector *extents, UInt64 rem, @@ -2070,7 +2132,7 @@ HRESULT CDatabase::OpenVolume(const CObjectMap &omap, const oid_t fs_oid) RINOK(ReadMap(ov.paddr, map, 0)); } - bool NeedReadSymLink = false; + bool needParseAttr = false; { const bool isHashed = apfs.IsHashedName(); @@ -2094,6 +2156,9 @@ HRESULT CDatabase::OpenVolume(const CObjectMap &omap, const oid_t fs_oid) } } + CAttr attr; + CItem item; + FOR_VECTOR (i, map.Pairs) { if (OpenCallback && (i & 0xffff) == 1) @@ -2232,7 +2297,7 @@ HRESULT CDatabase::OpenVolume(const CObjectMap &omap, const oid_t fs_oid) if (nameOffset + len != pair.Key.Size()) return S_FALSE; - CAttr attr; + attr.Clear(); attr.Name.SetFrom_CalcLen((const char *)p + nameOffset, len); if (attr.Name.Len() != len - 1) return S_FALSE; @@ -2287,15 +2352,25 @@ HRESULT CDatabase::OpenVolume(const CObjectMap &omap, const oid_t fs_oid) // UnsupportedFeature = true; // continue; } + CNode &inode = vol.Nodes.Back(); + if (attr.Name.IsEqualTo("com.apple.fs.symlink")) { inode.SymLinkIndex = inode.Attrs.Size(); if (attr.Is_dstream_OK_for_SymLink()) - NeedReadSymLink = true; + needParseAttr = true; + } + else if (attr.Name.IsEqualTo("com.apple.decmpfs")) + { + inode.DecmpfsIndex = inode.Attrs.Size(); + // if (attr.dstream_defined) + needParseAttr = true; + } + else if (attr.Name.IsEqualTo("com.apple.ResourceFork")) + { + inode.ResourceIndex = inode.Attrs.Size(); } - else - vol.NumAltStreams++; inode.Attrs.Add(attr); continue; } @@ -2431,7 +2506,10 @@ HRESULT CDatabase::OpenVolume(const CObjectMap &omap, const oid_t fs_oid) } if (nameOffset + len != pair.Key.Size()) return S_FALSE; - CItem item; + + // CItem item; + item.Clear(); + item.ParentId = id; item.Name.SetFrom_CalcLen((const char *)p + nameOffset, len); if (item.Name.Len() != len - 1) @@ -2471,39 +2549,86 @@ HRESULT CDatabase::OpenVolume(const CObjectMap &omap, const oid_t fs_oid) ProgressVal_NumFilesTotal += vol.Items.Size(); } - if (NeedReadSymLink) + + if (needParseAttr) { - /* we read external streams for SymLinks to CAttr.Data + /* we read external streams for attributes So we can get SymLink for GetProperty(kpidSymLink) later */ FOR_VECTOR (i, vol.Nodes) { CNode &node = vol.Nodes[i]; - if (IsViNotDef(node.SymLinkIndex)) - continue; - CAttr &attr = node.Attrs[(unsigned)node.SymLinkIndex]; - // FOR_VECTOR (k, node.Attrs) { CAttr &attr = node.Attrs[(unsigned)k]; // for debug - if (attr.Data.Size() != 0 - || !attr.Is_dstream_OK_for_SymLink()) - continue; - const UInt32 size = (UInt32)attr.dstream.size; - const int idIndex = vol.SmallNodeIDs.FindInSorted(attr.Id); - if (idIndex == -1) - continue; - CMyComPtr inStream; - const HRESULT res = GetStream2( - OpenInStream, - &vol.SmallNodes[(unsigned)idIndex].Extents, - size, &inStream); - if (res == S_OK && inStream) + + FOR_VECTOR (a, node.Attrs) + { + CAttr &attr = node.Attrs[a]; + if (attr.Data.Size() != 0 || !attr.dstream_defined) + continue; + if (a == node.SymLinkIndex) + { + if (!attr.Is_dstream_OK_for_SymLink()) + continue; + } + else + { + if (a != node.DecmpfsIndex + // && a != node.ResourceIndex + ) + continue; + } + // we don't expect big streams here + // largest dstream for Decmpfs attribute is (2Kib+17) + if (attr.dstream.size > ((UInt32)1 << 16)) + continue; + CMyComPtr inStream; + const HRESULT res = GetAttrStream_dstream(OpenInStream, vol, attr, &inStream); + if (res == S_OK && inStream) + { + CByteBuffer buf2; + const size_t size = (size_t)attr.dstream.size; + buf2.Alloc(size); + if (ReadStream_FAIL(inStream, buf2, size) == S_OK) + attr.Data = buf2; + + ProgressVal_Cur += size; + if (OpenCallback) + if (ProgressVal_Cur - ProgressVal_Prev >= (1 << 22)) + { + + RINOK(OpenCallback->SetCompleted( + &ProgressVal_NumFilesTotal, + &ProgressVal_Cur)); + ProgressVal_Prev = ProgressVal_Cur; + } + } + } + + if (node.Has_UNCOMPRESSED_SIZE()) + if (IsViDef(node.DecmpfsIndex)) { - CByteBuffer buf2; - buf2.Alloc(size); - if (ReadStream_FAIL(inStream, buf2, size) == S_OK) - attr.Data = buf2; + CAttr &attr = node.Attrs[node.DecmpfsIndex]; + node.CompressHeader.Parse(attr.Data, attr.Data.Size()); + + if (node.CompressHeader.IsCorrect) + if (node.CompressHeader.Method < sizeof(MethodsMask) * 8) + MethodsMask |= ((UInt32)1 << node.CompressHeader.Method); + + if (node.CompressHeader.IsCorrect + && node.CompressHeader.IsSupported + && node.CompressHeader.UnpackSize == node.uncompressed_size) + { + attr.NeedShow = false; + if (node.CompressHeader.IsMethod_Resource() + && IsViDef(node.ResourceIndex)) + node.Attrs[node.ResourceIndex].NeedShow = false; + } + else + { + vol.UnsupportedFeature = true; + } } } } - + const HRESULT res = vol.FillRefs(); if (vol.ThereAreErrors()) @@ -2521,9 +2646,10 @@ HRESULT CDatabase::OpenVolume(const CObjectMap &omap, const oid_t fs_oid) HRESULT CVol::FillRefs() { { + Refs.Reserve(Items.Size()); // we fill Refs[*] // we - // and set Nodes[*].ItemIndex for Nodes that are dictories; + // and set Nodes[*].ItemIndex for Nodes that are directories; FOR_VECTOR (i, Items) { CItem &item = Items[i]; @@ -2593,12 +2719,17 @@ HRESULT CVol::FillRefs() ref.ParentRefIndex = item.RefIndex; for (unsigned k = 0; k < numAttrs; k++) { + // comment it for debug + const CAttr &attr = inode.Attrs[k]; + if (!attr.NeedShow) + continue; + if (k == inode.SymLinkIndex) continue; ref.AttrIndex = k; + NumAltStreams++; Refs.Add(ref); /* - const CAttr &attr = inode.Attrs[k]; if (attr.dstream_defined) { const int idIndex = SmallNodeIDs.FindInSorted(attr.Id); @@ -2780,6 +2911,7 @@ enum kpidAddTime, kpidGeneration, kpidBsdFlags + // kpidUncompressedSize }; static const CStatProp kProps[] = @@ -2793,11 +2925,13 @@ static const CStatProp kProps[] = { NULL, kpidATime, VT_FILETIME }, { NULL, kpidChangeTime, VT_FILETIME }, { "Added Time", kpidAddTime, VT_FILETIME }, + { NULL, kpidMethod, VT_BSTR }, { NULL, kpidINode, VT_UI8 }, { NULL, kpidLinks, VT_UI4 }, { NULL, kpidSymLink, VT_BSTR }, { NULL, kpidUserId, VT_UI4 }, { NULL, kpidGroupId, VT_UI4 }, + { NULL, kpidCharacts, VT_BSTR }, #ifdef APFS_SHOW_ALT_STREAMS { NULL, kpidIsAltStream, VT_BOOL }, #endif @@ -2807,12 +2941,14 @@ static const CStatProp kProps[] = { "Written Size", kpidBytesWritten, VT_UI8 }, { "Read Size", kpidBytesRead, VT_UI8 }, { "BSD Flags", kpidBsdFlags, VT_UI4 } + // , { "Uncompressed Size", kpidUncompressedSize, VT_UI8 } }; static const Byte kArcProps[] = { kpidName, + kpidCharacts, kpidId, kpidClusterSize, kpidCTime, @@ -2848,6 +2984,7 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) prop = (UInt64)sb.block_count << sb.block_size_Log; break; case kpidClusterSize: prop = (UInt32)(sb.block_size); break; + case kpidCharacts: NHfs::MethodsMaskToProp(MethodsMask, prop); break; case kpidMTime: if (apfs) ApfsTimeToProp(apfs->modified_by[0].timestamp, prop); @@ -2953,7 +3090,6 @@ STDMETHODIMP CHandler::GetParent(UInt32 index, UInt32 *parent, UInt32 *parentTyp const CRef2 &ref2 = Refs2[index]; const CVol &vol = Vols[ref2.VolIndex]; UInt32 parentIndex = (UInt32)(Int32)-1; - *parentType = NParentType::kDir; if (IsViDef(ref2.RefIndex)) { @@ -3017,6 +3153,7 @@ void CDatabase::GetItemPath(unsigned index, const CNode *inode, NWindows::NCOM:: { const CRef &ref = vol.Refs[ref2.RefIndex]; unsigned cur = ref.ItemIndex; + UString s2; if (IsViNotDef(cur)) { if (inode) @@ -3032,14 +3169,13 @@ void CDatabase::GetItemPath(unsigned index, const CNode *inode, NWindows::NCOM:: break; } const CItem &item = vol.Items[(unsigned)cur]; - UString s2; Utf8Name_to_InterName(item.Name, s2); // s2 += "a\\b"; // for debug s.Insert(0, s2); cur = item.ParentItemIndex; if (IsViNotDef(cur)) break; - // ParentItemIndex was not set for sch items + // ParentItemIndex was not set for such items // if (item.ParentId == ROOT_DIR_INO_NUM) break; s.InsertAtFront(WCHAR_PATH_SEPARATOR); } @@ -3049,7 +3185,6 @@ void CDatabase::GetItemPath(unsigned index, const CNode *inode, NWindows::NCOM:: if (IsViDef(ref.AttrIndex) && inode) { s += ':'; - UString s2; Utf8Name_to_InterName(inode->Attrs[(unsigned)ref.AttrIndex].Name, s2); // s2 += "a\\b"; // for debug s += s2; @@ -3110,11 +3245,10 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val break; case kpidPrimeName: { - if (inode - #ifdef APFS_SHOW_ALT_STREAMS - && !ref.IsAltStream() - #endif - && !inode->PrimaryName.IsEmpty()) + #ifdef APFS_SHOW_ALT_STREAMS + if (!ref.IsAltStream()) + #endif + if (inode && !inode->PrimaryName.IsEmpty()) { UString s; ConvertUTF8ToUnicode(inode->PrimaryName, s); @@ -3155,6 +3289,9 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val } case kpidSymLink: + #ifdef APFS_SHOW_ALT_STREAMS + if (!ref.IsAltStream()) + #endif if (inode) { if (inode->IsSymLink() && IsViDef(inode->SymLinkIndex)) @@ -3178,8 +3315,9 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val case kpidSize: if (inode) { - UInt64 size; - if (inode->GetSize(ref.GetAttrIndex(), size)) + UInt64 size = 0; + if (inode->GetSize(ref.GetAttrIndex(), size) || + !inode->IsDir()) prop = size; } break; @@ -3188,18 +3326,53 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val if (inode) { UInt64 size; - if (inode->GetPackSize(ref.GetAttrIndex(), size)) + if (inode->GetPackSize(ref.GetAttrIndex(), size) || + !inode->IsDir()) prop = size; } break; + case kpidMethod: + #ifdef APFS_SHOW_ALT_STREAMS + if (!ref.IsAltStream()) + #endif + if (inode) + { + if (inode->CompressHeader.IsCorrect) + inode->CompressHeader.MethodToProp(prop); + else if (IsViDef(inode->DecmpfsIndex)) + prop = "decmpfs"; + else if (!inode->IsDir() && !inode->dstream_defined) + { + if (inode->IsSymLink()) + { + if (IsViDef(inode->SymLinkIndex)) + prop = "symlink"; + } + // else prop = "no_dstream"; + } + } + break; + + /* + case kpidUncompressedSize: + if (inode && inode->Has_UNCOMPRESSED_SIZE()) + prop = inode->uncompressed_size; + break; + */ + case kpidIsDir: { bool isDir = false; - if (inode) - isDir = inode->IsDir(); - else if (item) - isDir = item->Val.IsFlags_Dir(); + #ifdef APFS_SHOW_ALT_STREAMS + if (!ref.IsAltStream()) + #endif + { + if (inode) + isDir = inode->IsDir(); + else if (item) + isDir = item->Val.IsFlags_Dir(); + } prop = isDir; break; } @@ -3251,6 +3424,9 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val #endif case kpidCharacts: + #ifdef APFS_SHOW_ALT_STREAMS + if (!ref.IsAltStream()) + #endif if (inode) { FLAGS_TO_PROP(g_INODE_Flags, (UInt32)inode->internal_flags, prop); @@ -3258,6 +3434,9 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val break; case kpidBsdFlags: + #ifdef APFS_SHOW_ALT_STREAMS + if (!ref.IsAltStream()) + #endif if (inode) { FLAGS_TO_PROP(g_INODE_BSD_Flags, inode->bsd_flags, prop); @@ -3265,6 +3444,9 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val break; case kpidGeneration: + #ifdef APFS_SHOW_ALT_STREAMS + // if (!ref.IsAltStream()) + #endif if (inode) prop = inode->write_generation_counter; break; @@ -3280,6 +3462,9 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val break; case kpidLinks: + #ifdef APFS_SHOW_ALT_STREAMS + if (!ref.IsAltStream()) + #endif if (inode && !inode->IsDir()) prop = (UInt32)inode->nlink; break; @@ -3287,13 +3472,16 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val case kpidINode: #ifdef APFS_SHOW_ALT_STREAMS // here we can disable iNode for alt stream. - // if (!ref.IsAltStream()) + if (!ref.IsAltStream()) #endif if (IsViDef(ref.NodeIndex)) prop = (UInt32)vol.NodeIDs[ref.NodeIndex]; break; case kpidParentINode: + #ifdef APFS_SHOW_ALT_STREAMS + if (!ref.IsAltStream()) + #endif if (inode) prop = (UInt32)inode->parent_id; break; @@ -3351,6 +3539,8 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder(); CMyComPtr copyCoder = copyCoderSpec; + NHfs::CDecoder decoder; + for (i = 0; i < numItems; i++, currentTotalSize += currentItemSize) { lps->InSize = currentTotalSize; @@ -3399,15 +3589,68 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, RINOK(extractCallback->PrepareOperation(askMode)); int opRes = NExtract::NOperationResult::kDataError; - CMyComPtr inStream; - if (GetStream(index, &inStream) == S_OK && inStream) + if (IsViDef(ref.NodeIndex)) { - RINOK(copyCoder->Code(inStream, realOutStream, NULL, NULL, progress)); - opRes = NExtract::NOperationResult::kDataError; - if (copyCoderSpec->TotalSize == currentItemSize) - opRes = NExtract::NOperationResult::kOK; - else if (copyCoderSpec->TotalSize < currentItemSize) - opRes = NExtract::NOperationResult::kUnexpectedEnd; + const CNode &inode = vol.Nodes[ref.NodeIndex]; + if ( + #ifdef APFS_SHOW_ALT_STREAMS + !ref.IsAltStream() && + #endif + !inode.dstream_defined + && inode.Extents.IsEmpty() + && inode.Has_UNCOMPRESSED_SIZE() + && inode.uncompressed_size == inode.CompressHeader.UnpackSize) + { + if (inode.CompressHeader.IsSupported) + { + CMyComPtr inStreamFork; + UInt64 forkSize = 0; + const CByteBuffer *decmpfs_Data = NULL; + + if (inode.CompressHeader.IsMethod_Resource()) + { + if (IsViDef(inode.ResourceIndex)) + { + const CAttr &attr = inode.Attrs[inode.ResourceIndex]; + forkSize = attr.GetSize(); + GetAttrStream(_stream, vol, attr, &inStreamFork); + } + } + else + { + const CAttr &attr = inode.Attrs[inode.DecmpfsIndex]; + decmpfs_Data = &attr.Data; + } + + if (inStreamFork || decmpfs_Data) + { + const HRESULT hres = decoder.Extract( + inStreamFork, realOutStream, + forkSize, + inode.CompressHeader, + decmpfs_Data, + currentTotalSize, extractCallback, + opRes); + if (hres != S_FALSE && hres != S_OK) + return hres; + } + } + else + opRes = NExtract::NOperationResult::kUnsupportedMethod; + } + else + { + CMyComPtr inStream; + if (GetStream(index, &inStream) == S_OK && inStream) + { + RINOK(copyCoder->Code(inStream, realOutStream, NULL, NULL, progress)); + opRes = NExtract::NOperationResult::kDataError; + if (copyCoderSpec->TotalSize == currentItemSize) + opRes = NExtract::NOperationResult::kOK; + else if (copyCoderSpec->TotalSize < currentItemSize) + opRes = NExtract::NOperationResult::kUnexpectedEnd; + } + } } realOutStream.Release(); @@ -3478,7 +3721,14 @@ STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) if (inode.IsDir()) return S_FALSE; if (inode.dstream_defined) + { rem = inode.dstream.size; + } + else + { + // return S_FALSE; // check it !!! How zero size files are stored with dstream_defined? + } + extents = &inode.Extents; } return GetStream2(_stream, extents, rem, stream); @@ -3486,6 +3736,35 @@ STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) +HRESULT CDatabase::GetAttrStream(IInStream *apfsInStream, const CVol &vol, + const CAttr &attr, ISequentialInStream **stream) +{ + *stream = NULL; + if (!attr.dstream_defined) + { + CBufInStream *streamSpec = new CBufInStream; + CMyComPtr streamTemp = streamSpec; + streamSpec->Init(attr.Data, attr.Data.Size(), (IInArchive *)this); + *stream = streamTemp.Detach(); + return S_OK; + } + return GetAttrStream_dstream(apfsInStream, vol, attr, stream); +} + + +HRESULT CDatabase::GetAttrStream_dstream( IInStream *apfsInStream, const CVol &vol, + const CAttr &attr, ISequentialInStream **stream) +{ + const int idIndex = vol.SmallNodeIDs.FindInSorted(attr.Id); + if (idIndex == -1) + return S_FALSE; + return GetStream2(apfsInStream, + &vol.SmallNodes[(unsigned)idIndex].Extents, + attr.dstream.size, + stream); +} + + HRESULT CDatabase::GetStream2( IInStream *apfsInStream, const CRecordVector *extents, UInt64 rem, diff --git a/CPP/7zip/Archive/Chm/ChmIn.h b/CPP/7zip/Archive/Chm/ChmIn.h index 7cba0c7..2d77366 100644 --- a/CPP/7zip/Archive/Chm/ChmIn.h +++ b/CPP/7zip/Archive/Chm/ChmIn.h @@ -126,6 +126,7 @@ struct CLzxInfo CLzxInfo(): Version(0), ResetIntervalBits(0), + WindowSizeBits(0), CacheSize(0) {} diff --git a/CPP/7zip/Archive/DmgHandler.cpp b/CPP/7zip/Archive/DmgHandler.cpp index 1f2ca26..e6166f1 100644 --- a/CPP/7zip/Archive/DmgHandler.cpp +++ b/CPP/7zip/Archive/DmgHandler.cpp @@ -1063,6 +1063,8 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val subName.DeleteFrom(pos1); } } + else + subName = item.Name; // new apfs dmg can be without braces subName.Trim(); if (!subName.IsEmpty()) { diff --git a/CPP/7zip/Archive/HfsHandler.cpp b/CPP/7zip/Archive/HfsHandler.cpp index f0a85f1..fa96b73 100644 --- a/CPP/7zip/Archive/HfsHandler.cpp +++ b/CPP/7zip/Archive/HfsHandler.cpp @@ -7,19 +7,19 @@ #include "../../Common/ComTry.h" #include "../../Common/MyString.h" -#include "../../Windows/PropVariant.h" +#include "../../Windows/PropVariantUtils.h" #include "../Common/LimitedStreams.h" #include "../Common/RegisterArc.h" #include "../Common/StreamObjects.h" #include "../Common/StreamUtils.h" -#include "../Compress/ZlibDecoder.h" +#include "HfsHandler.h" /* if HFS_SHOW_ALT_STREAMS is defined, the handler will show attribute files and resource forks. In most cases it looks useless. So we disable it. */ -// #define HFS_SHOW_ALT_STREAMS +#define HFS_SHOW_ALT_STREAMS #define Get16(p) GetBe16(p) #define Get32(p) GetBe32(p) @@ -80,6 +80,8 @@ struct CFork }; static const unsigned kNumFixedExtents = 8; +static const unsigned kForkRecSize = 16 + kNumFixedExtents * 8; + void CFork::Parse(const Byte *p) { @@ -227,6 +229,121 @@ enum ERecordType RECORD_TYPE_FILE_THREAD }; + + +// static const UInt32 kMethod_1_NO_COMPRESSION = 1; // in xattr +static const UInt32 kMethod_ZLIB_ATTR = 3; +static const UInt32 kMethod_ZLIB_RSRC = 4; +// static const UInt32 kMethod_DEDUP = 5; // de-dup within the generation store +// macos 10.10 +static const UInt32 kMethod_LZVN_ATTR = 7; +static const UInt32 kMethod_LZVN_RSRC = 8; +static const UInt32 kMethod_COPY_ATTR = 9; +static const UInt32 kMethod_COPY_RSRC = 10; +// macos 10.11 +// static const UInt32 kMethod_LZFSE_ATTR = 11; +static const UInt32 kMethod_LZFSE_RSRC = 12; + +static const char * const g_Methods[] = +{ + NULL + , NULL + , NULL + , "ZLIB-attr" + , "ZLIB-rsrc" + , NULL + , NULL + , "LZVN-attr" + , "LZVN-rsrc" + , "COPY-attr" + , "COPY-rsrc" + , "LZFSE-attr" + , "LZFSE-rsrc" +}; + + +static const Byte k_COPY_Uncompressed_Marker = 0xcc; +static const Byte k_LZVN_Uncompressed_Marker = 6; + +void CCompressHeader::Parse(const Byte *p, size_t dataSize) +{ + Clear(); + + if (dataSize < k_decmpfs_HeaderSize) + return; + if (GetUi32(p) != 0x636D7066) // magic == "fpmc" + return; + Method = GetUi32(p + 4); + UnpackSize = GetUi64(p + 8); + dataSize -= k_decmpfs_HeaderSize; + IsCorrect = true; + + if ( Method == kMethod_ZLIB_RSRC + || Method == kMethod_COPY_RSRC + || Method == kMethod_LZVN_RSRC + || Method == kMethod_LZFSE_RSRC) + { + IsResource = true; + if (dataSize == 0) + IsSupported = ( + Method != kMethod_LZFSE_RSRC && + Method != kMethod_COPY_RSRC); + return; + } + + if ( Method == kMethod_ZLIB_ATTR + || Method == kMethod_COPY_ATTR + || Method == kMethod_LZVN_ATTR + // || Method == kMethod_LZFSE_ATTR + ) + { + if (dataSize == 0) + return; + const Byte b = p[k_decmpfs_HeaderSize]; + if ( (Method == kMethod_ZLIB_ATTR && (b & 0xf) == 0xf) + || (Method == kMethod_COPY_ATTR && b == k_COPY_Uncompressed_Marker) + || (Method == kMethod_LZVN_ATTR && b == k_LZVN_Uncompressed_Marker)) + { + dataSize--; + // if (UnpackSize > dataSize) + if (UnpackSize != dataSize) + return; + DataPos = k_decmpfs_HeaderSize + 1; + IsSupported = true; + } + else + { + if (Method != kMethod_COPY_ATTR) + IsSupported = true; + DataPos = k_decmpfs_HeaderSize; + } + } +} + + +void CCompressHeader::MethodToProp(NWindows::NCOM::CPropVariant &prop) const +{ + if (!IsCorrect) + return; + const UInt32 method = Method; + const char *p = NULL; + if (method < ARRAY_SIZE(g_Methods)) + p = g_Methods[method]; + AString s; + if (p) + s = p; + else + s.Add_UInt32(method); + // if (!IsSupported) s += "-unsuported"; + prop = s; +} + +void MethodsMaskToProp(UInt32 methodsMask, NWindows::NCOM::CPropVariant &prop) +{ + FLAGS_TO_PROP(g_Methods, methodsMask, prop); +} + + struct CItem { UString Name; @@ -265,54 +382,79 @@ struct CItem CFork DataFork; CFork ResourceFork; - // for compressed attribute - UInt64 UnpackSize; - size_t DataPos; - UInt32 PackSize; - unsigned Method; - bool UseAttr; - bool UseInlineData; + // for compressed attribute (decmpfs) + int decmpfs_AttrIndex; + CCompressHeader CompressHeader; - CItem(): UseAttr(false), UseInlineData(false) {} + CItem(): + decmpfs_AttrIndex(-1) + {} bool IsDir() const { return Type == RECORD_TYPE_FOLDER; } - const CFork &GetFork(bool isResource) const { return (const CFork & )*(isResource ? &ResourceFork: &DataFork ); } + // const CFork *GetFork(bool isResource) const { return (isResource ? &ResourceFork: &DataFork); } }; + struct CAttr { UInt32 ID; - UInt32 Size; - size_t Pos; + bool Fork_defined; + + // UInt32 Size; // for (Fork_defined == false) case + // size_t DataPos; // for (Fork_defined == false) case + CByteBuffer Data; + + CFork Fork; + UString Name; + + UInt64 GetSize() const + { + if (Fork_defined) + return Fork.Size; + return Data.Size(); + } + + CAttr(): + Fork_defined(false) + // Size(0), + // DataPos(0), + {} }; + +static const int kAttrIndex_Item = -1; +static const int kAttrIndex_Resource = -2; + struct CRef { unsigned ItemIndex; int AttrIndex; int Parent; - bool IsResource; - bool IsAltStream() const { return IsResource || AttrIndex >= 0; } - CRef(): AttrIndex(-1), Parent(-1), IsResource(false) {} + CRef(): AttrIndex(kAttrIndex_Item), Parent(-1) {} + bool IsResource() const { return AttrIndex == kAttrIndex_Resource; } + bool IsAltStream() const { return AttrIndex != kAttrIndex_Item; } + bool IsItem() const { return AttrIndex == kAttrIndex_Item; } }; + class CDatabase { HRESULT ReadFile(const CFork &fork, CByteBuffer &buf, IInStream *inStream); HRESULT LoadExtentFile(const CFork &fork, IInStream *inStream, CObjectVector *overflowExtentsArray); HRESULT LoadAttrs(const CFork &fork, IInStream *inStream, IArchiveOpenCallback *progress); HRESULT LoadCatalog(const CFork &fork, const CObjectVector *overflowExtentsArray, IInStream *inStream, IArchiveOpenCallback *progress); - bool Parse_decmpgfs(const CAttr &attr, CItem &item, bool &skip); + bool Parse_decmpgfs(unsigned attrIndex, CItem &item, bool &skip); public: CRecordVector Refs; CObjectVector Items; CObjectVector Attrs; - CByteBuffer AttrBuf; + // CByteBuffer AttrBuf; CVolHeader Header; bool HeadersError; + bool UnsupportedFeature; bool ThereAreAltStreams; // bool CaseSensetive; UString ResFileName; @@ -321,6 +463,7 @@ public: UInt64 PhySize; UInt64 PhySize2; UInt64 ArcFileSize; + UInt32 MethodsMask; void Clear() { @@ -328,25 +471,30 @@ public: PhySize = 0; PhySize2 = 0; ArcFileSize = 0; + MethodsMask = 0; HeadersError = false; + UnsupportedFeature = false; ThereAreAltStreams = false; // CaseSensetive = false; + Refs.Clear(); Items.Clear(); Attrs.Clear(); - AttrBuf.Free(); + // AttrBuf.Free(); } UInt64 Get_UnpackSize_of_Ref(const CRef &ref) const { if (ref.AttrIndex >= 0) - return Attrs[ref.AttrIndex].Size; + return Attrs[ref.AttrIndex].GetSize(); const CItem &item = Items[ref.ItemIndex]; + if (ref.IsResource()) + return item.ResourceFork.Size; if (item.IsDir()) return 0; - if (item.UseAttr) - return item.UnpackSize; - return item.GetFork(ref.IsResource).Size; + else if (item.CompressHeader.IsCorrect) + return item.CompressHeader.UnpackSize; + return item.DataFork.Size; } void GetItemPath(unsigned index, NWindows::NCOM::CPropVariant &path) const; @@ -380,7 +528,7 @@ void CDatabase::GetItemPath(unsigned index, NWindows::NCOM::CPropVariant &path) const CRef &ref = Refs[cur]; const UString *s; - if (ref.IsResource) + if (ref.IsResource()) s = &ResFileName; else if (ref.AttrIndex >= 0) s = &Attrs[ref.AttrIndex].Name; @@ -405,7 +553,7 @@ void CDatabase::GetItemPath(unsigned index, NWindows::NCOM::CPropVariant &path) const UString *s; wchar_t delimChar = L':'; - if (ref.IsResource) + if (ref.IsResource()) s = &ResFileName; else if (ref.AttrIndex >= 0) s = &Attrs[ref.AttrIndex].Name; @@ -596,6 +744,8 @@ HRESULT CDatabase::LoadExtentFile(const CFork &fork, IInStream *inStream, CObjec UInt32 node = hr.FirstLeafNode; if (node == 0) return S_OK; + if (hr.TotalNodes == 0) + return S_FALSE; CByteArr usedBuf(hr.TotalNodes); memset(usedBuf, 0, hr.TotalNodes); @@ -617,7 +767,7 @@ HRESULT CDatabase::LoadExtentFile(const CFork &fork, IInStream *inStream, CObjec for (unsigned i = 0; i < desc.NumRecords; i++) { - const UInt32 nodeSize = (1 << hr.NodeSizeLog); + const UInt32 nodeSize = ((UInt32)1 << hr.NodeSizeLog); const Byte *r = p + nodeOffset + nodeSize - i * 2; const UInt32 offs = Get16(r - 2); UInt32 recSize = Get16(r - 4) - offs; @@ -630,7 +780,7 @@ HRESULT CDatabase::LoadExtentFile(const CFork &fork, IInStream *inStream, CObjec if (Get16(r) != kKeyLen) return S_FALSE; - Byte forkType = r[2]; + const Byte forkType = r[2]; unsigned forkTypeIndex; if (forkType == kExtentForkType_Data) forkTypeIndex = 0; @@ -640,8 +790,8 @@ HRESULT CDatabase::LoadExtentFile(const CFork &fork, IInStream *inStream, CObjec continue; CObjectVector &overflowExtents = overflowExtentsArray[forkTypeIndex]; - UInt32 id = Get32(r + 4); - UInt32 startBlock = Get32(r + 8); + const UInt32 id = Get32(r + 4); + const UInt32 startBlock = Get32(r + 8); r += 2 + kKeyLen; bool needNew = true; @@ -691,7 +841,7 @@ static void LoadName(const Byte *data, unsigned len, UString &dest) unsigned i; for (i = 0; i < len; i++) { - wchar_t c = Get16(data + i * 2); + const wchar_t c = Get16(data + i * 2); if (c == 0) break; p[i] = c; @@ -704,7 +854,7 @@ static bool IsNameEqualTo(const Byte *data, const char *name) { for (unsigned i = 0;; i++) { - char c = name[i]; + const char c = name[i]; if (c == 0) return true; if (Get16(data + i * 2) != (Byte)c) @@ -713,7 +863,7 @@ static bool IsNameEqualTo(const Byte *data, const char *name) } static const UInt32 kAttrRecordType_Inline = 0x10; -// static const UInt32 kAttrRecordType_Fork = 0x20; +static const UInt32 kAttrRecordType_Fork = 0x20; // static const UInt32 kAttrRecordType_Extents = 0x30; HRESULT CDatabase::LoadAttrs(const CFork &fork, IInStream *inStream, IArchiveOpenCallback *progress) @@ -721,6 +871,7 @@ HRESULT CDatabase::LoadAttrs(const CFork &fork, IInStream *inStream, IArchiveOpe if (fork.NumBlocks == 0) return S_OK; + CByteBuffer AttrBuf; RINOK(ReadFile(fork, AttrBuf, inStream)); const Byte *p = (const Byte *)AttrBuf; @@ -734,7 +885,9 @@ HRESULT CDatabase::LoadAttrs(const CFork &fork, IInStream *inStream, IArchiveOpe UInt32 node = hr.FirstLeafNode; if (node == 0) return S_OK; - + if (hr.TotalNodes == 0) + return S_FALSE; + CByteArr usedBuf(hr.TotalNodes); memset(usedBuf, 0, hr.TotalNodes); @@ -755,7 +908,7 @@ HRESULT CDatabase::LoadAttrs(const CFork &fork, IInStream *inStream, IArchiveOpe for (unsigned i = 0; i < desc.NumRecords; i++) { - const UInt32 nodeSize = (1 << hr.NodeSizeLog); + const UInt32 nodeSize = ((UInt32)1 << hr.NodeSizeLog); const Byte *r = p + nodeOffset + nodeSize - i * 2; const UInt32 offs = Get16(r - 2); UInt32 recSize = Get16(r - 4) - offs; @@ -764,18 +917,18 @@ HRESULT CDatabase::LoadAttrs(const CFork &fork, IInStream *inStream, IArchiveOpe return S_FALSE; r = p + nodeOffset + offs; - UInt32 keyLen = Get16(r); + const UInt32 keyLen = Get16(r); // UInt16 pad = Get16(r + 2); - UInt32 fileID = Get32(r + 4); - unsigned startBlock = Get32(r + 8); + const UInt32 fileID = Get32(r + 4); + const unsigned startBlock = Get32(r + 8); if (startBlock != 0) { // that case is still unsupported - HeadersError = true; + UnsupportedFeature = true; continue; } - unsigned nameLen = Get16(r + 12); + const unsigned nameLen = Get16(r + 12); if (keyLen + 2 > recSize || keyLen != kHeadSize - 2 + nameLen * 2) @@ -790,36 +943,56 @@ HRESULT CDatabase::LoadAttrs(const CFork &fork, IInStream *inStream, IArchiveOpe if (recSize < 4) return S_FALSE; - UInt32 recordType = Get32(r); - if (recordType != kAttrRecordType_Inline) + const UInt32 recordType = Get32(r); + + if (progress && (Attrs.Size() & 0xFFF) == 0) { - // Probably only kAttrRecordType_Inline now is used in real HFS files - HeadersError = true; - continue; + const UInt64 numFiles = 0; + RINOK(progress->SetCompleted(&numFiles, NULL)); } - const UInt32 kRecordHeaderSize = 16; - if (recSize < kRecordHeaderSize) - return S_FALSE; - UInt32 dataSize = Get32(r + 12); - - r += kRecordHeaderSize; - recSize -= kRecordHeaderSize; - - if (recSize < dataSize) + if (Attrs.Size() >= ((UInt32)1 << 31)) return S_FALSE; CAttr &attr = Attrs.AddNew(); attr.ID = fileID; - attr.Pos = nodeOffset + offs + 2 + keyLen + kRecordHeaderSize; - attr.Size = dataSize; LoadName(name, nameLen, attr.Name); - if (progress && (i & 0xFFF) == 0) + if (recordType == kAttrRecordType_Fork) { - const UInt64 numFiles = 0; - RINOK(progress->SetCompleted(&numFiles, NULL)); + // 22.00 : some hfs files contain it; + /* spec: If the attribute has more than 8 extents, there will be additional + records (of type kAttrRecordType_Extents) for this attribute. */ + if (recSize != 8 + kForkRecSize) + return S_FALSE; + if (Get32(r + 4) != 0) // reserved + return S_FALSE; + attr.Fork.Parse(r + 8); + attr.Fork_defined = true; + continue; + } + else if (recordType != kAttrRecordType_Inline) + { + UnsupportedFeature = true; + continue; } + + const unsigned kRecordHeaderSize = 16; + if (recSize < kRecordHeaderSize) + return S_FALSE; + if (Get32(r + 4) != 0 || Get32(r + 8) != 0) // reserved + return S_FALSE; + const UInt32 dataSize = Get32(r + 12); + + r += kRecordHeaderSize; + recSize -= kRecordHeaderSize; + + if (recSize < dataSize) + return S_FALSE; + + attr.Data.CopyFrom(r, dataSize); + // attr.DataPos = nodeOffset + offs + 2 + keyLen + kRecordHeaderSize; + // attr.Size = dataSize; } node = desc.fLink; @@ -827,62 +1000,28 @@ HRESULT CDatabase::LoadAttrs(const CFork &fork, IInStream *inStream, IArchiveOpe return S_OK; } -static const UInt32 kMethod_Attr = 3; // data stored in attribute file -static const UInt32 kMethod_Resource = 4; // data stored in resource fork -bool CDatabase::Parse_decmpgfs(const CAttr &attr, CItem &item, bool &skip) +bool CDatabase::Parse_decmpgfs(unsigned attrIndex, CItem &item, bool &skip) { + const CAttr &attr = Attrs[attrIndex]; skip = false; - if (!attr.Name.IsEqualTo("com.apple.decmpfs")) - return true; - if (item.UseAttr || !item.DataFork.IsEmpty()) + if (item.CompressHeader.IsCorrect || !item.DataFork.IsEmpty()) return false; - const UInt32 k_decmpfs_headerSize = 16; - UInt32 dataSize = attr.Size; - if (dataSize < k_decmpfs_headerSize) - return false; - const Byte *r = AttrBuf + attr.Pos; - if (GetUi32(r) != 0x636D7066) // magic == "fpmc" - return false; - item.Method = GetUi32(r + 4); - item.UnpackSize = GetUi64(r + 8); - dataSize -= k_decmpfs_headerSize; - r += k_decmpfs_headerSize; - if (item.Method == kMethod_Resource) + item.CompressHeader.Parse(attr.Data, attr.Data.Size()); + + if (item.CompressHeader.IsCorrect) { - if (dataSize != 0) - return false; - item.UseAttr = true; + item.decmpfs_AttrIndex = attrIndex; + skip = true; + if (item.CompressHeader.Method < sizeof(MethodsMask) * 8) + MethodsMask |= ((UInt32)1 << item.CompressHeader.Method); } - else if (item.Method == kMethod_Attr) - { - if (dataSize == 0) - return false; - Byte b = r[0]; - if ((b & 0xF) == 0xF) - { - dataSize--; - if (item.UnpackSize > dataSize) - return false; - item.DataPos = attr.Pos + k_decmpfs_headerSize + 1; - item.PackSize = dataSize; - item.UseAttr = true; - item.UseInlineData = true; - } - else - { - item.DataPos = attr.Pos + k_decmpfs_headerSize; - item.PackSize = dataSize; - item.UseAttr = true; - } - } - else - return false; - skip = true; + return true; } + HRESULT CDatabase::LoadCatalog(const CFork &fork, const CObjectVector *overflowExtentsArray, IInStream *inStream, IArchiveOpenCallback *progress) { CByteBuffer buf; @@ -911,7 +1050,8 @@ HRESULT CDatabase::LoadCatalog(const CFork &fork, const CObjectVector= 0) { @@ -1158,13 +1301,15 @@ HRESULT CDatabase::LoadCatalog(const CFork &fork, const CObjectVector= 0) s = &Attrs[ref.AttrIndex].Name; @@ -1536,8 +1685,9 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val { case kpidPath: GetItemPath(index, prop); break; case kpidName: + { const UString *s; - if (ref.IsResource) + if (ref.IsResource()) s = &ResFileName; else if (ref.AttrIndex >= 0) s = &Attrs[ref.AttrIndex].Name; @@ -1545,22 +1695,31 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val s = &item.Name; prop = *s; break; + } case kpidPackSize: { UInt64 size; if (ref.AttrIndex >= 0) - size = Attrs[ref.AttrIndex].Size; + size = Attrs[ref.AttrIndex].GetSize(); + else if (ref.IsResource()) + size = (UInt64)item.ResourceFork.NumBlocks << Header.BlockSizeLog; else if (item.IsDir()) break; - else if (item.UseAttr) + else if (item.CompressHeader.IsCorrect) { - if (item.Method == kMethod_Resource) - size = item.ResourceFork.NumBlocks << Header.BlockSizeLog; + if (item.CompressHeader.IsMethod_Resource()) + size = (UInt64)item.ResourceFork.NumBlocks << Header.BlockSizeLog; + else if (item.decmpfs_AttrIndex >= 0) + { + // size = item.PackSize; + const CAttr &attr = Attrs[item.decmpfs_AttrIndex]; + size = attr.Data.Size() - item.CompressHeader.DataPos; + } else - size = item.PackSize; + size = 0; } else - size = item.GetFork(ref.IsResource).NumBlocks << Header.BlockSizeLog; + size = (UInt64)item.DataFork.NumBlocks << Header.BlockSizeLog; prop = size; break; } @@ -1568,25 +1727,34 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val { UInt64 size; if (ref.AttrIndex >= 0) - size = Attrs[ref.AttrIndex].Size; + size = Attrs[ref.AttrIndex].GetSize(); + else if (ref.IsResource()) + size = item.ResourceFork.Size; else if (item.IsDir()) break; - else if (item.UseAttr) - size = item.UnpackSize; + else if (item.CompressHeader.IsCorrect) + size = item.CompressHeader.UnpackSize; else - size = item.GetFork(ref.IsResource).Size; + size = item.DataFork.Size; prop = size; break; } - case kpidIsDir: prop = item.IsDir(); break; + case kpidIsDir: prop = (ref.IsItem() && item.IsDir()); break; case kpidIsAltStream: prop = ref.IsAltStream(); break; - case kpidCTime: HfsTimeToProp(item.CTime, prop); break; case kpidMTime: HfsTimeToProp(item.MTime, prop); break; case kpidATime: HfsTimeToProp(item.ATime, prop); break; case kpidChangeTime: HfsTimeToProp(item.AttrMTime, prop); break; + case kpidPosixAttrib: if (ref.IsItem()) prop = (UInt32)item.FileMode; break; + /* + case kpidUserId: prop = (UInt32)item.OwnerID; break; + case kpidGroupId: prop = (UInt32)item.GroupID; break; + */ - case kpidPosixAttrib: if (ref.AttrIndex < 0) prop = (UInt32)item.FileMode; break; + case kpidMethod: + if (ref.IsItem()) + item.CompressHeader.MethodToProp(prop); + break; } prop.Detach(value); return S_OK; @@ -1614,65 +1782,77 @@ STDMETHODIMP CHandler::Close() static const UInt32 kCompressionBlockSize = 1 << 16; -HRESULT CHandler::ExtractZlibFile( - ISequentialOutStream *outStream, - const CItem &item, - NCompress::NZlib::CDecoder *_zlibDecoderSpec, - CByteBuffer &buf, - UInt64 progressStart, - IArchiveExtractCallback *extractCallback) +CDecoder::CDecoder() +{ + _zlibDecoderSpec = new NCompress::NZlib::CDecoder(); + _zlibDecoder = _zlibDecoderSpec; + + _lzfseDecoderSpec = new NCompress::NLzfse::CDecoder(); + _lzfseDecoder = _lzfseDecoderSpec; + _lzfseDecoderSpec->LzvnMode = true; +} + +HRESULT CDecoder::ExtractResourceFork_ZLIB( + ISequentialInStream *inStream, ISequentialOutStream *outStream, + UInt64 forkSize, UInt64 unpackSize, + UInt64 progressStart, IArchiveExtractCallback *extractCallback) { - CMyComPtr inStream; - const CFork &fork = item.ResourceFork; - RINOK(GetForkStream(fork, &inStream)); const unsigned kHeaderSize = 0x100 + 8; - RINOK(ReadStream_FALSE(inStream, buf, kHeaderSize)); - UInt32 dataPos = Get32(buf); - UInt32 mapPos = Get32(buf + 4); - UInt32 dataSize = Get32(buf + 8); - UInt32 mapSize = Get32(buf + 12); + + const size_t kBufSize = kCompressionBlockSize; + _buf.Alloc(kBufSize + 0x10); // we need 1 additional bytes for uncompressed chunk header + + RINOK(ReadStream_FALSE(inStream, _buf, kHeaderSize)); + Byte *buf = _buf; + const UInt32 dataPos = Get32(buf); + const UInt32 mapPos = Get32(buf + 4); + const UInt32 dataSize = Get32(buf + 8); + const UInt32 mapSize = Get32(buf + 12); const UInt32 kResMapSize = 50; if (mapSize != kResMapSize - || dataPos + dataSize != mapPos - || mapPos + mapSize != fork.Size) + || dataPos > mapPos + || dataSize != mapPos - dataPos + || mapSize > forkSize + || mapPos != forkSize - mapSize) return S_FALSE; - UInt32 dataSize2 = Get32(buf + 0x100); - if (4 + dataSize2 != dataSize || dataSize2 < 8) + const UInt32 dataSize2 = Get32(buf + 0x100); + if (4 + dataSize2 != dataSize + || dataSize2 < 8 + || dataSize2 > dataSize) return S_FALSE; - UInt32 numBlocks = GetUi32(buf + 0x100 + 4); + const UInt32 numBlocks = GetUi32(buf + 0x100 + 4); if (((dataSize2 - 4) >> 3) < numBlocks) return S_FALSE; - if (item.UnpackSize > (UInt64)numBlocks * kCompressionBlockSize) - return S_FALSE; - - if (item.UnpackSize + kCompressionBlockSize < (UInt64)numBlocks * kCompressionBlockSize) - return S_FALSE; + { + const UInt64 up = unpackSize + kCompressionBlockSize - 1; + if (up < unpackSize || up / kCompressionBlockSize != numBlocks) + return S_FALSE; + } - UInt32 tableSize = (numBlocks << 3); + const UInt32 tableSize = (numBlocks << 3); - CByteBuffer tableBuf(tableSize); + _tableBuf.AllocAtLeast(tableSize); - RINOK(ReadStream_FALSE(inStream, tableBuf, tableSize)); + RINOK(ReadStream_FALSE(inStream, _tableBuf, tableSize)); + const Byte *tableBuf = _tableBuf; UInt32 prev = 4 + tableSize; UInt32 i; for (i = 0; i < numBlocks; i++) { - UInt32 offset = GetUi32(tableBuf + i * 8); - UInt32 size = GetUi32(tableBuf + i * 8 + 4); - if (size == 0) - return S_FALSE; - if (prev != offset) + const UInt32 offs = GetUi32(tableBuf + i * 8); + const UInt32 size = GetUi32(tableBuf + i * 8 + 4); + if (size == 0 + || prev != offs + || offs > dataSize2 + || size > dataSize2 - offs) return S_FALSE; - if (offset > dataSize2 || - size > dataSize2 - offset) - return S_FALSE; - prev = offset + size; + prev = offs + size; } if (prev != dataSize2) @@ -1681,26 +1861,29 @@ HRESULT CHandler::ExtractZlibFile( CBufInStream *bufInStreamSpec = new CBufInStream; CMyComPtr bufInStream = bufInStreamSpec; + // bool padError = false; UInt64 outPos = 0; + for (i = 0; i < numBlocks; i++) { - UInt64 rem = item.UnpackSize - outPos; + const UInt64 rem = unpackSize - outPos; if (rem == 0) return S_FALSE; UInt32 blockSize = kCompressionBlockSize; if (rem < kCompressionBlockSize) blockSize = (UInt32)rem; - UInt32 size = GetUi32(tableBuf + i * 8 + 4); + const UInt32 size = GetUi32(tableBuf + i * 8 + 4); - if (size > buf.Size() || size > kCompressionBlockSize + 1) + if (size > kCompressionBlockSize + 1) return S_FALSE; RINOK(ReadStream_FALSE(inStream, buf, size)); if ((buf[0] & 0xF) == 0xF) { - // that code was not tested. Are there HFS archives with uncompressed block + // (buf[0] = 0xff) is marker of uncompressed block in APFS + // that code was not tested in HFS if (size - 1 != blockSize) return S_FALSE; @@ -1711,54 +1894,251 @@ HRESULT CHandler::ExtractZlibFile( } else { - UInt64 blockSize64 = blockSize; + const UInt64 blockSize64 = blockSize; bufInStreamSpec->Init(buf, size); RINOK(_zlibDecoderSpec->Code(bufInStream, outStream, NULL, &blockSize64, NULL)); - if (_zlibDecoderSpec->GetOutputProcessedSize() != blockSize || - _zlibDecoderSpec->GetInputProcessedSize() != size) + if (_zlibDecoderSpec->GetOutputProcessedSize() != blockSize) return S_FALSE; + const UInt64 inSize = _zlibDecoderSpec->GetInputProcessedSize(); + if (inSize != size) + { + if (inSize > size) + return S_FALSE; + // apfs file can contain junk (non-zeros) after data block. + /* + if (!padError) + { + const Byte *p = buf + (UInt32)inSize; + const Byte *e = p + (size - (UInt32)inSize); + do + { + if (*p != 0) + { + padError = true; + break; + } + } + while (++p != e); + } + */ + } } outPos += blockSize; - const UInt64 progressPos = progressStart + outPos; - RINOK(extractCallback->SetCompleted(&progressPos)); + if ((i & 0xFF) == 0) + { + const UInt64 progressPos = progressStart + outPos; + RINOK(extractCallback->SetCompleted(&progressPos)); + } } - if (outPos != item.UnpackSize) + if (outPos != unpackSize) return S_FALSE; + // if (padError) return S_FALSE; + /* We check Resource Map Are there HFS files with another values in Resource Map ??? */ RINOK(ReadStream_FALSE(inStream, buf, mapSize)); - UInt32 types = Get16(buf + 24); - UInt32 names = Get16(buf + 26); - UInt32 numTypes = Get16(buf + 28); + const UInt32 types = Get16(buf + 24); + const UInt32 names = Get16(buf + 26); + const UInt32 numTypes = Get16(buf + 28); if (numTypes != 0 || types != 28 || names != kResMapSize) return S_FALSE; - UInt32 resType = Get32(buf + 30); - UInt32 numResources = Get16(buf + 34); - UInt32 resListOffset = Get16(buf + 36); + const UInt32 resType = Get32(buf + 30); + const UInt32 numResources = Get16(buf + 34); + const UInt32 resListOffset = Get16(buf + 36); if (resType != 0x636D7066) // cmpf return S_FALSE; if (numResources != 0 || resListOffset != 10) return S_FALSE; - UInt32 entryId = Get16(buf + 38); - UInt32 nameOffset = Get16(buf + 40); + const UInt32 entryId = Get16(buf + 38); + const UInt32 nameOffset = Get16(buf + 40); // Byte attrib = buf[42]; - UInt32 resourceOffset = Get32(buf + 42) & 0xFFFFFF; + const UInt32 resourceOffset = Get32(buf + 42) & 0xFFFFFF; if (entryId != 1 || nameOffset != 0xFFFF || resourceOffset != 0) return S_FALSE; return S_OK; } + + +HRESULT CDecoder::ExtractResourceFork_LZFSE( + ISequentialInStream *inStream, ISequentialOutStream *outStream, + UInt64 forkSize, UInt64 unpackSize, + UInt64 progressStart, IArchiveExtractCallback *extractCallback) +{ + const UInt32 kNumBlocksMax = (UInt32)1 << 29; + if (unpackSize >= (UInt64)kNumBlocksMax * kCompressionBlockSize) + return S_FALSE; + const UInt32 numBlocks = (UInt32)((unpackSize + kCompressionBlockSize - 1) / kCompressionBlockSize); + const UInt32 numBlocks2 = numBlocks + 1; + const UInt32 tableSize = (numBlocks2 << 2); + if (tableSize > forkSize) + return S_FALSE; + _tableBuf.AllocAtLeast(tableSize); + RINOK(ReadStream_FALSE(inStream, _tableBuf, tableSize)); + const Byte *tableBuf = _tableBuf; + + { + UInt32 prev = GetUi32(tableBuf); + if (prev != tableSize) + return S_FALSE; + for (UInt32 i = 1; i < numBlocks2; i++) + { + const UInt32 offs = GetUi32(tableBuf + i * 4); + if (offs <= prev) + return S_FALSE; + prev = offs; + } + if (prev != forkSize) + return S_FALSE; + } + + const size_t kBufSize = kCompressionBlockSize; + _buf.Alloc(kBufSize + 0x10); // we need 1 additional bytes for uncompressed chunk header + + CBufInStream *bufInStreamSpec = new CBufInStream; + CMyComPtr bufInStream = bufInStreamSpec; + + UInt64 outPos = 0; + + for (UInt32 i = 0; i < numBlocks; i++) + { + const UInt64 rem = unpackSize - outPos; + if (rem == 0) + return S_FALSE; + UInt32 blockSize = kCompressionBlockSize; + if (rem < kCompressionBlockSize) + blockSize = (UInt32)rem; + + const UInt32 size = + GetUi32(tableBuf + i * 4 + 4) - + GetUi32(tableBuf + i * 4); + + if (size > kCompressionBlockSize + 1) + return S_FALSE; + + RINOK(ReadStream_FALSE(inStream, _buf, size)); + const Byte *buf = _buf; + + if (buf[0] == k_LZVN_Uncompressed_Marker) + { + if (size - 1 != blockSize) + return S_FALSE; + if (outStream) + { + RINOK(WriteStream(outStream, buf, blockSize)); + } + } + else + { + const UInt64 blockSize64 = blockSize; + const UInt64 packSize64 = size; + bufInStreamSpec->Init(buf, size); + RINOK(_lzfseDecoderSpec->Code(bufInStream, outStream, &packSize64, &blockSize64, NULL)); + // in/out sizes were checked in Code() + } + + outPos += blockSize; + if ((i & 0xFF) == 0) + { + const UInt64 progressPos = progressStart + outPos; + RINOK(extractCallback->SetCompleted(&progressPos)); + } + } + + return S_OK; +} + + +HRESULT CDecoder::Extract( + ISequentialInStream *inStreamFork, ISequentialOutStream *realOutStream, + UInt64 forkSize, + const CCompressHeader &compressHeader, + const CByteBuffer *data, + UInt64 progressStart, IArchiveExtractCallback *extractCallback, + int &opRes) +{ + opRes = NExtract::NOperationResult::kDataError; + + if (compressHeader.IsMethod_Uncompressed_Inline()) + { + const size_t packSize = data->Size() - compressHeader.DataPos; + if (realOutStream) + { + RINOK(WriteStream(realOutStream, *data + compressHeader.DataPos, packSize)); + } + opRes = NExtract::NOperationResult::kOK; + return S_OK; + } + + if (compressHeader.Method == kMethod_ZLIB_ATTR || + compressHeader.Method == kMethod_LZVN_ATTR) + { + CBufInStream *bufInStreamSpec = new CBufInStream; + CMyComPtr bufInStream = bufInStreamSpec; + const size_t packSize = data->Size() - compressHeader.DataPos; + bufInStreamSpec->Init(*data + compressHeader.DataPos, packSize); + + if (compressHeader.Method == kMethod_ZLIB_ATTR) + { + const HRESULT hres = _zlibDecoder->Code(bufInStream, realOutStream, + NULL, &compressHeader.UnpackSize, NULL); + if (hres == S_OK) + if (_zlibDecoderSpec->GetOutputProcessedSize() == compressHeader.UnpackSize + && _zlibDecoderSpec->GetInputProcessedSize() == packSize) + opRes = NExtract::NOperationResult::kOK; + return hres; + } + { + const UInt64 packSize64 = packSize; + const HRESULT hres = _lzfseDecoder->Code(bufInStream, realOutStream, + &packSize64, &compressHeader.UnpackSize, NULL); + if (hres == S_OK) + { + // in/out sizes were checked in Code() + opRes = NExtract::NOperationResult::kOK; + } + return hres; + } + } + + HRESULT hres; + if (compressHeader.Method == NHfs::kMethod_ZLIB_RSRC) + { + hres = ExtractResourceFork_ZLIB( + inStreamFork, realOutStream, + forkSize, compressHeader.UnpackSize, + progressStart, extractCallback); + } + else if (compressHeader.Method == NHfs::kMethod_LZVN_RSRC) + { + hres = ExtractResourceFork_LZFSE( + inStreamFork, realOutStream, + forkSize, compressHeader.UnpackSize, + progressStart, extractCallback); + } + else + { + opRes = NExtract::NOperationResult::kUnsupportedMethod; + hres = S_FALSE; + } + + if (hres == S_OK) + opRes = NExtract::NOperationResult::kOK; + return hres; +} + + STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, Int32 testMode, IArchiveExtractCallback *extractCallback) { COM_TRY_BEGIN - bool allFilesMode = (numItems == (UInt32)(Int32)-1); + const bool allFilesMode = (numItems == (UInt32)(Int32)-1); if (allFilesMode) numItems = Refs.Size(); if (numItems == 0) @@ -1777,12 +2157,13 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, const size_t kBufSize = kCompressionBlockSize; CByteBuffer buf(kBufSize + 0x10); // we need 1 additional bytes for uncompressed chunk header - NCompress::NZlib::CDecoder *_zlibDecoderSpec = NULL; - CMyComPtr _zlibDecoder; + CDecoder decoder; - for (i = 0; i < numItems; i++, currentTotalSize += currentItemSize) + for (i = 0;; i++, currentTotalSize += currentItemSize) { RINOK(extractCallback->SetCompleted(¤tTotalSize)); + if (i == numItems) + break; UInt32 index = allFilesMode ? i : indices[i]; const CRef &ref = Refs[index]; const CItem &item = Items[ref.ItemIndex]; @@ -1794,7 +2175,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, NExtract::NAskMode::kExtract; RINOK(extractCallback->GetStream(index, &realOutStream, askMode)); - if (ref.AttrIndex < 0 && item.IsDir()) + if (ref.IsItem() && item.IsDir()) { RINOK(extractCallback->PrepareOperation(askMode)); RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)); @@ -1802,89 +2183,91 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, } if (!testMode && !realOutStream) continue; + RINOK(extractCallback->PrepareOperation(askMode)); + UInt64 pos = 0; - int res = NExtract::NOperationResult::kDataError; + int opRes = NExtract::NOperationResult::kDataError; + const CFork *fork = NULL; + if (ref.AttrIndex >= 0) { - res = NExtract::NOperationResult::kOK; - if (realOutStream) + const CAttr &attr = Attrs[ref.AttrIndex]; + if (attr.Fork_defined && attr.Data.Size() == 0) + fork = &attr.Fork; + else { - const CAttr &attr = Attrs[ref.AttrIndex]; - RINOK(WriteStream(realOutStream, AttrBuf + attr.Pos, attr.Size)); + opRes = NExtract::NOperationResult::kOK; + if (realOutStream) + { + RINOK(WriteStream(realOutStream, + // AttrBuf + attr.Pos, attr.Size + attr.Data, attr.Data.Size() + )); + } } } - else if (item.UseAttr) + else if (ref.IsResource()) + fork = &item.ResourceFork; + else if (item.CompressHeader.IsSupported) { - if (item.UseInlineData) + CMyComPtr inStreamFork; + UInt64 forkSize = 0; + const CByteBuffer *decmpfs_Data = NULL; + + if (item.CompressHeader.IsMethod_Resource()) { - res = NExtract::NOperationResult::kOK; - if (realOutStream) - { - RINOK(WriteStream(realOutStream, AttrBuf + item.DataPos, (size_t)item.UnpackSize)); - } + const CFork &resourceFork = item.ResourceFork; + forkSize = resourceFork.Size; + GetForkStream(resourceFork, &inStreamFork); } else { - if (!_zlibDecoder) - { - _zlibDecoderSpec = new NCompress::NZlib::CDecoder(); - _zlibDecoder = _zlibDecoderSpec; - } - - if (item.Method == kMethod_Attr) - { - CBufInStream *bufInStreamSpec = new CBufInStream; - CMyComPtr bufInStream = bufInStreamSpec; - bufInStreamSpec->Init(AttrBuf + item.DataPos, item.PackSize); - - HRESULT hres = _zlibDecoder->Code(bufInStream, realOutStream, NULL, &item.UnpackSize, NULL); - if (hres != S_FALSE) - { - if (hres != S_OK) - return hres; - if (_zlibDecoderSpec->GetOutputProcessedSize() == item.UnpackSize && - _zlibDecoderSpec->GetInputProcessedSize() == item.PackSize) - res = NExtract::NOperationResult::kOK; - } - } - else - { - HRESULT hres = ExtractZlibFile(realOutStream, item, _zlibDecoderSpec, buf, - currentTotalSize, extractCallback); - if (hres != S_FALSE) - { - if (hres != S_OK) - return hres; - res = NExtract::NOperationResult::kOK; - } - } + const CAttr &attr = Attrs[item.decmpfs_AttrIndex]; + decmpfs_Data = &attr.Data; + } + + if (inStreamFork || decmpfs_Data) + { + const HRESULT hres = decoder.Extract( + inStreamFork, realOutStream, + forkSize, + item.CompressHeader, + decmpfs_Data, + currentTotalSize, extractCallback, + opRes); + if (hres != S_FALSE && hres != S_OK) + return hres; } } + else if (item.CompressHeader.IsCorrect) + opRes = NExtract::NOperationResult::kUnsupportedMethod; else + fork = &item.DataFork; + + if (fork) { - const CFork &fork = item.GetFork(ref.IsResource); - if (fork.IsOk(Header.BlockSizeLog)) + if (fork->IsOk(Header.BlockSizeLog)) { - res = NExtract::NOperationResult::kOK; + opRes = NExtract::NOperationResult::kOK; unsigned extentIndex; - for (extentIndex = 0; extentIndex < fork.Extents.Size(); extentIndex++) + for (extentIndex = 0; extentIndex < fork->Extents.Size(); extentIndex++) { - if (res != NExtract::NOperationResult::kOK) + if (opRes != NExtract::NOperationResult::kOK) break; - if (fork.Size == pos) + if (fork->Size == pos) break; - const CExtent &e = fork.Extents[extentIndex]; + const CExtent &e = fork->Extents[extentIndex]; RINOK(_stream->Seek(SpecOffset + ((UInt64)e.Pos << Header.BlockSizeLog), STREAM_SEEK_SET, NULL)); UInt64 extentRem = (UInt64)e.NumBlocks << Header.BlockSizeLog; while (extentRem != 0) { - UInt64 rem = fork.Size - pos; + const UInt64 rem = fork->Size - pos; if (rem == 0) { // Here we check that there are no extra (empty) blocks in last extent. if (extentRem >= ((UInt64)1 << Header.BlockSizeLog)) - res = NExtract::NOperationResult::kDataError; + opRes = NExtract::NOperationResult::kDataError; break; } size_t cur = kBufSize; @@ -1895,7 +2278,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, RINOK(ReadStream(_stream, buf, &cur)); if (cur == 0) { - res = NExtract::NOperationResult::kDataError; + opRes = NExtract::NOperationResult::kDataError; break; } if (realOutStream) @@ -1908,12 +2291,12 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, RINOK(extractCallback->SetCompleted(&processed)); } } - if (extentIndex != fork.Extents.Size() || fork.Size != pos) - res = NExtract::NOperationResult::kDataError; + if (extentIndex != fork->Extents.Size() || fork->Size != pos) + opRes = NExtract::NOperationResult::kDataError; } } realOutStream.Release(); - RINOK(extractCallback->SetOperationResult(res)); + RINOK(extractCallback->SetOperationResult(opRes)); } return S_OK; COM_TRY_END @@ -1976,13 +2359,27 @@ STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) *stream = 0; const CRef &ref = Refs[index]; + const CFork *fork = NULL; if (ref.AttrIndex >= 0) - return S_FALSE; - const CItem &item = Items[ref.ItemIndex]; - if (item.IsDir() || item.UseAttr) - return S_FALSE; - - return GetForkStream(item.GetFork(ref.IsResource), stream); + { + const CAttr &attr = Attrs[ref.AttrIndex]; + if (!attr.Fork_defined || attr.Data.Size() != 0) + return S_FALSE; + fork = &attr.Fork; + } + else + { + const CItem &item = Items[ref.ItemIndex]; + if (ref.IsResource()) + fork = &item.ResourceFork; + else if (item.IsDir()) + return S_FALSE; + else if (item.CompressHeader.IsCorrect) + return S_FALSE; + else + fork = &item.DataFork; + } + return GetForkStream(*fork, stream); } static const Byte k_Signature[] = { diff --git a/CPP/7zip/Archive/HfsHandler.h b/CPP/7zip/Archive/HfsHandler.h new file mode 100644 index 0000000..2461f6b --- /dev/null +++ b/CPP/7zip/Archive/HfsHandler.h @@ -0,0 +1,85 @@ +// HfsHandler.h + +#ifndef __HFS_HANDLER_H +#define __HFS_HANDLER_H + +#include "../../Windows/PropVariant.h" + +#include "../Compress/LzfseDecoder.h" +#include "../Compress/ZlibDecoder.h" + +namespace NArchive { +namespace NHfs { + +static const UInt32 k_decmpfs_HeaderSize = 16; + +struct CCompressHeader +{ + UInt64 UnpackSize; + UInt32 Method; + Byte DataPos; + bool IsCorrect; + bool IsSupported; + bool IsResource; + + bool IsMethod_Compressed_Inline() const { return DataPos == k_decmpfs_HeaderSize; } + bool IsMethod_Uncompressed_Inline() const { return DataPos == k_decmpfs_HeaderSize + 1; } + bool IsMethod_Resource() const { return IsResource; } + + void Parse(const Byte *p, size_t size); + + void Clear() + { + UnpackSize = 0; + Method = 0; + DataPos = 0; + IsCorrect = false; + IsSupported = false; + IsResource = false; + } + + CCompressHeader() { Clear(); } + + void MethodToProp(NWindows::NCOM::CPropVariant &prop) const; +}; + +void MethodsMaskToProp(UInt32 methodsMask, NWindows::NCOM::CPropVariant &prop); + + +class CDecoder +{ + NCompress::NZlib::CDecoder *_zlibDecoderSpec; + CMyComPtr _zlibDecoder; + + NCompress::NLzfse::CDecoder *_lzfseDecoderSpec; + CMyComPtr _lzfseDecoder; + + CByteBuffer _tableBuf; + CByteBuffer _buf; + + HRESULT ExtractResourceFork_ZLIB( + ISequentialInStream *inStream, ISequentialOutStream *realOutStream, + UInt64 forkSize, UInt64 unpackSize, + UInt64 progressStart, IArchiveExtractCallback *extractCallback); + + HRESULT ExtractResourceFork_LZFSE( + ISequentialInStream *inStream, ISequentialOutStream *realOutStream, + UInt64 forkSize, UInt64 unpackSize, + UInt64 progressStart, IArchiveExtractCallback *extractCallback); + +public: + + HRESULT Extract( + ISequentialInStream *inStreamFork, ISequentialOutStream *realOutStream, + UInt64 forkSize, + const CCompressHeader &compressHeader, + const CByteBuffer *data, + UInt64 progressStart, IArchiveExtractCallback *extractCallback, + int &opRes); + + CDecoder(); +}; + +}} + +#endif diff --git a/CPP/7zip/Archive/Udf/UdfHandler.cpp b/CPP/7zip/Archive/Udf/UdfHandler.cpp index 2232c64..691199e 100644 --- a/CPP/7zip/Archive/Udf/UdfHandler.cpp +++ b/CPP/7zip/Archive/Udf/UdfHandler.cpp @@ -48,14 +48,22 @@ static const Byte kProps[] = kpidPackSize, kpidMTime, kpidATime, - kpidChangeTime + kpidCTime, + kpidChangeTime, + // kpidUserId, + // kpidGroupId, + // kpidPosixAttrib, + kpidLinks }; static const Byte kArcProps[] = { - kpidComment, + kpidUnpackVer, kpidClusterSize, - kpidCTime + kpidSectorSize, + kpidCTime, + kpidMTime, + kpidComment }; IMP_IInArchive_Props @@ -69,6 +77,18 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) { case kpidPhySize: prop = _archive.PhySize; break; + case kpidUnpackVer: + { + if (_archive.LogVols.Size() == 1) + { + UString s; + const CLogVol &vol = _archive.LogVols[0]; + vol.DomainId.AddUdfVersionTo(s); + if (!s.IsEmpty()) + prop = s; + } + break; + } case kpidComment: { UString comment = _archive.GetComment(); @@ -90,12 +110,21 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) } break; + case kpidSectorSize: prop = ((UInt32)1 << _archive.SecLogSize); break; + case kpidCTime: if (_archive.LogVols.Size() == 1) { const CLogVol &vol = _archive.LogVols[0]; if (vol.FileSets.Size() >= 1) - UdfTimeToFileTime(vol.FileSets[0].RecodringTime, prop); + UdfTimeToFileTime(vol.FileSets[0].RecordingTime, prop); + } + break; + case kpidMTime: + if (_archive.PrimeVols.Size() == 1) + { + const CPrimeVol &pv = _archive.PrimeVols[0]; + UdfTimeToFileTime(pv.RecordingTime, prop); } break; @@ -160,6 +189,7 @@ STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallb { const CLogVol &vol = _archive.LogVols[volIndex]; bool showFileSetName = (vol.FileSets.Size() > 1); + // showFileSetName = true; // for debug FOR_VECTOR (fsIndex, vol.FileSets) { const CFileSet &fs = vol.FileSets[fsIndex]; @@ -212,7 +242,15 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val case kpidPackSize: if (!item.IsDir()) prop = (UInt64)item.NumLogBlockRecorded * vol.BlockSize; break; case kpidMTime: UdfTimeToFileTime(item.MTime, prop); break; case kpidATime: UdfTimeToFileTime(item.ATime, prop); break; + case kpidCTime: + if (item.IsExtended) + UdfTimeToFileTime(item.CreateTime, prop); + break; case kpidChangeTime: UdfTimeToFileTime(item.AttribTime, prop); break; + // case kpidUserId: prop = item.Uid; break; + // case kpidGroupId: prop = item.Gid; break; + // case kpidPosixAttrib: prop = (UInt32)item.Permissions; break; + case kpidLinks: prop = (UInt32)item.FileLinkCount; break; } } prop.Detach(value); @@ -255,7 +293,7 @@ STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) if (size < len) return S_FALSE; - int partitionIndex = vol.PartitionMaps[extent.PartitionRef].PartitionIndex; + const unsigned partitionIndex = vol.PartitionMaps[extent.PartitionRef].PartitionIndex; UInt32 logBlockNumber = extent.Pos; const CPartition &partition = _archive.Partitions[partitionIndex]; UInt64 offset = ((UInt64)partition.Pos << _archive.SecLogSize) + diff --git a/CPP/7zip/Archive/Udf/UdfHandler.h b/CPP/7zip/Archive/Udf/UdfHandler.h index da44b23..462faee 100644 --- a/CPP/7zip/Archive/Udf/UdfHandler.h +++ b/CPP/7zip/Archive/Udf/UdfHandler.h @@ -24,9 +24,9 @@ class CHandler: public IInArchiveGetStream, public CMyUnknownImp { + CRecordVector _refs2; CMyComPtr _inStream; CInArchive _archive; - CRecordVector _refs2; public: MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream) INTERFACE_IInArchive(;) diff --git a/CPP/7zip/Archive/Udf/UdfIn.cpp b/CPP/7zip/Archive/Udf/UdfIn.cpp index d2d2b20..70496e4 100644 --- a/CPP/7zip/Archive/Udf/UdfIn.cpp +++ b/CPP/7zip/Archive/Udf/UdfIn.cpp @@ -10,6 +10,8 @@ #include "../../../../C/CpuArch.h" +#include "../../../Windows/PropVariantUtils.h" + #include "../../Common/RegisterArc.h" #include "../../Common/StreamUtils.h" @@ -25,6 +27,10 @@ #define Get32(p) GetUi32(p) #define Get64(p) GetUi64(p) +#define G16(_offs_, dest) dest = Get16(p + (_offs_)); +#define G32(_offs_, dest) dest = Get32(p + (_offs_)); +#define G64(_offs_, dest) dest = Get64(p + (_offs_)); + namespace NArchive { namespace NUdf { @@ -39,7 +45,6 @@ static const UInt64 kFileNameLengthTotalMax = (UInt64)1 << 33; static const UInt64 kInlineExtentsSizeMax = (UInt64)1 << 33; #define CRC16_INIT_VAL 0 -// #define CRC16_GET_DIGEST(crc) (crc) #define CRC16_UPDATE_BYTE(crc, b) ((UInt16)(g_Crc16Table[(((crc) >> 8) ^ (b)) & 0xFF] ^ ((crc) << 8))) #define kCrc16Poly 0x1021 @@ -57,22 +62,20 @@ static void MY_FAST_CALL Crc16GenerateTable(void) } } -static UInt32 MY_FAST_CALL Crc16_Update(UInt32 v, const void *data, size_t size) +static UInt32 MY_FAST_CALL Crc16Calc(const void *data, size_t size) { + UInt32 v = CRC16_INIT_VAL; const Byte *p = (const Byte *)data; - for (; size > 0 ; size--, p++) + const Byte *pEnd = p + size; + for (; p != pEnd; p++) v = CRC16_UPDATE_BYTE(v, *p); return v; } -static UInt32 MY_FAST_CALL Crc16Calc(const void *data, size_t size) -{ - return Crc16_Update(CRC16_INIT_VAL, data, size); -} - static struct CCrc16TableInit { CCrc16TableInit() { Crc16GenerateTable(); } } g_Crc16TableInit; +// ---------- ECMA Part 1 ---------- void CDString::Parse(const Byte *p, unsigned size) { @@ -82,16 +85,17 @@ void CDString::Parse(const Byte *p, unsigned size) static UString ParseDString(const Byte *data, unsigned size) { UString res; - if (size > 0) + if (size != 0) { wchar_t *p; - Byte type = data[0]; + const Byte type = *data++; + size--; if (type == 8) { p = res.GetBuf(size); - for (unsigned i = 1; i < size; i++) + for (unsigned i = 0; i < size; i++) { - wchar_t c = data[i]; + const wchar_t c = data[i]; if (c == 0) break; *p++ = c; @@ -99,10 +103,11 @@ static UString ParseDString(const Byte *data, unsigned size) } else if (type == 16) { + size &= ~(unsigned)1; p = res.GetBuf(size / 2); - for (unsigned i = 1; i + 2 <= size; i += 2) + for (unsigned i = 0; i < size; i += 2) { - wchar_t c = GetBe16(data + i); + const wchar_t c = GetBe16(data + i); if (c == 0) break; *p++ = c; @@ -116,75 +121,117 @@ static UString ParseDString(const Byte *data, unsigned size) return res; } +UString CDString32::GetString() const +{ + const unsigned size = Data[sizeof(Data) - 1]; + return ParseDString(Data, MyMin(size, (unsigned)(sizeof(Data) - 1))); +} + UString CDString128::GetString() const { - unsigned size = Data[sizeof(Data) - 1]; + const unsigned size = Data[sizeof(Data) - 1]; return ParseDString(Data, MyMin(size, (unsigned)(sizeof(Data) - 1))); } UString CDString::GetString() const { return ParseDString(Data, (unsigned)Data.Size()); } -void CTime::Parse(const Byte *buf) { memcpy(Data, buf, sizeof(Data)); } +void CTime::Parse(const Byte *p) { memcpy(Data, p, sizeof(Data)); } -/* -void CRegId::Parse(const Byte *buf) + +static void AddCommentChars(UString &dest, const char *s, size_t size) { - Flags = buf[0]; - memcpy(Id, buf + 1, sizeof(Id)); - memcpy(Suffix, buf + 24, sizeof(Suffix)); + for (size_t i = 0; i < size; i++) + { + char c = s[i]; + if (c == 0) + break; + if (c < 0x20) + c = '_'; + dest += (wchar_t)c; + } } -*/ -// ECMA 3/7.1 -struct CExtent +void CRegId::Parse(const Byte *p) { - UInt32 Len; - UInt32 Pos; + Flags = p[0]; + memcpy(Id, p + 1, sizeof(Id)); + memcpy(Suffix, p + 24, sizeof(Suffix)); +} - void Parse(const Byte *buf); -}; +void CRegId::AddCommentTo(UString &s) const +{ + AddCommentChars(s, Id, sizeof(Id)); +} -void CExtent::Parse(const Byte *buf) +void CRegId::AddUdfVersionTo(UString &s) const { - Len = Get32(buf); - Pos = Get32(buf + 4); + // use it only for "Domain Identifier Suffix" and "UDF Identifier Suffix" + // UDF 2.1.5.3 + // Revision in hex (3 digits) + const Byte minor = Suffix[0]; + const Byte major = Suffix[1]; + if (major != 0 || minor != 0) + { + char temp[16]; + ConvertUInt32ToHex(major, temp); + s += temp; + s += '.'; + ConvertUInt32ToHex8Digits(minor, temp); + s += &temp[8 - 2]; + } } + +// ---------- ECMA Part 3: Volume Structure ---------- + +void CExtent::Parse(const Byte *p) +{ + /* Len shall be less than < 2^30. + Unless otherwise specified, the length shall be an integral multiple of the logical sector size. + If (Len == 0), no extent is specified and (Pos) shall contain 0 */ + G32 (0, Len); + G32 (4, Pos); +} + + // ECMA 3/7.2 struct CTag { UInt16 Id; - UInt16 Version; + // UInt16 Version; // Byte Checksum; // UInt16 SerialNumber; // UInt16 Crc; - // UInt16 CrcLen; - // UInt32 TagLocation; + UInt16 CrcLen; + // UInt32 TagLocation; // the number of the logical sector - HRESULT Parse(const Byte *buf, size_t size); + HRESULT Parse(const Byte *p, size_t size); }; -HRESULT CTag::Parse(const Byte *buf, size_t size) +HRESULT CTag::Parse(const Byte *p, size_t size) { if (size < 16) return S_FALSE; - Byte sum = 0; - int i; - for (i = 0; i < 4; i++) sum = (Byte)(sum + buf[i]); - for (i = 5; i < 16; i++) sum = (Byte)(sum + buf[i]); - if (sum != buf[4] || buf[5] != 0) return S_FALSE; - - Id = Get16(buf); - Version = Get16(buf + 2); - // SerialNumber = Get16(buf + 6); - UInt32 crc = Get16(buf + 8); - UInt32 crcLen = Get16(buf + 10); - // TagLocation = Get32(buf + 12); - - if (size >= 16 + crcLen) - if (crc == Crc16Calc(buf + 16, (size_t)crcLen)) + { + unsigned sum = 0; + for (unsigned i = 0; i < 16; i++) + sum = sum + p[i]; + if ((Byte)(sum - p[4]) != p[4] || p[5] != 0) + return S_FALSE; + } + Id = Get16(p); + const UInt16 Version = Get16(p + 2); + if (Version != 2 && Version != 3) + return S_FALSE; + // SerialNumber = Get16(p + 6); + const UInt32 crc = Get16(p + 8); + CrcLen = Get16(p + 10); + // TagLocation = Get32(p + 12); + + if (size >= 16 + (size_t)CrcLen) + if (crc == Crc16Calc(p + 16, (size_t)CrcLen)) return S_OK; return S_FALSE; } @@ -210,52 +257,78 @@ enum EDescriptorType DESC_TYPE_Terminal = 260, DESC_TYPE_File = 261, DESC_TYPE_ExtendedAttrHeader = 262, - DESC_TYPE_UnallocatedSpace = 263, + DESC_TYPE_UnallocatedSpaceEntry = 263, DESC_TYPE_SpaceBitmap = 264, DESC_TYPE_PartitionIntegrity = 265, DESC_TYPE_ExtendedFile = 266 }; -void CLogBlockAddr::Parse(const Byte *buf) +void CLogBlockAddr::Parse(const Byte *p) { - Pos = Get32(buf); - PartitionRef = Get16(buf + 4); + G32 (0, Pos); + G16 (4, PartitionRef); } -void CShortAllocDesc::Parse(const Byte *buf) +void CShortAllocDesc::Parse(const Byte *p) { - Len = Get32(buf); - Pos = Get32(buf + 4); + G32 (0, Len); + G32 (4, Pos); } /* -void CADImpUse::Parse(const Byte *buf) +void CADImpUse::Parse(const Byte *p) { - Flags = Get16(buf); - UdfUniqueId = Get32(buf + 2); + G16 (0, Flags); + G32 (2, UdfUniqueId); } */ -void CLongAllocDesc::Parse(const Byte *buf) +void CLongAllocDesc::Parse(const Byte *p) { - Len = Get32(buf); - Location.Parse(buf + 4); - // memcpy(ImplUse, buf + 10, sizeof(ImplUse)); + G32 (0, Len); + Location.Parse(p + 4); + // memcpy(ImplUse, p + 10, sizeof(ImplUse)); // adImpUse.Parse(ImplUse); } -bool CInArchive::CheckExtent(int volIndex, int partitionRef, UInt32 blockPos, UInt32 len) const + +void CPrimeVol::Parse(const Byte *p) +{ + // G32 (16, VolumeDescriptorSequenceNumber); + G32 (20, PrimaryVolumeDescriptorNumber); + VolumeId.Parse(p + 24); + G16 (56, VolumeSequenceNumber); + G16 (58, MaximumVolumeSequenceNumber); + // G16 (60, InterchangeLevel); + // G16 (62, MaximumInterchangeLevel); + // G32 (64, CharacterSetList) + // G32 (68, MaximumCharacterSetList) + VolumeSetId.Parse(p + 72); + // 200 64 Descriptor Character Set charspec (1/7.2.1) + // 264 64 Explanatory Character Set charspec (1/7.2.1) + // VolumeAbstract.Parse(p + 328); + // VolumeCopyrightNotice.Parse(p + 336); + ApplicationId.Parse(p + 344); + RecordingTime.Parse(p + 376); + ImplId.Parse(p + 388); + // 420 64 Implementation Use bytes + // G32 (484, PredecessorVolumeDescriptorSequenceLocation); + // G16 (488, Flags); +} + + + +bool CInArchive::CheckExtent(unsigned volIndex, unsigned partitionRef, UInt32 blockPos, UInt32 len) const { const CLogVol &vol = LogVols[volIndex]; - if (partitionRef >= (int)vol.PartitionMaps.Size()) + if (partitionRef >= vol.PartitionMaps.Size()) return false; 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); + return ((UInt64)blockPos * vol.BlockSize + len) <= ((UInt64)partition.Len << SecLogSize); } -bool CInArchive::CheckItemExtents(int volIndex, const CItem &item) const +bool CInArchive::CheckItemExtents(unsigned volIndex, const CItem &item) const { FOR_VECTOR (i, item.Extents) { @@ -266,7 +339,7 @@ bool CInArchive::CheckItemExtents(int volIndex, const CItem &item) const return true; } -HRESULT CInArchive::Read(int volIndex, int partitionRef, UInt32 blockPos, UInt32 len, Byte *buf) +HRESULT CInArchive::Read(unsigned volIndex, unsigned partitionRef, UInt32 blockPos, UInt32 len, Byte *buf) { if (!CheckExtent(volIndex, partitionRef, blockPos, len)) return S_FALSE; @@ -274,20 +347,20 @@ HRESULT CInArchive::Read(int volIndex, int partitionRef, UInt32 blockPos, UInt32 const CPartition &partition = Partitions[vol.PartitionMaps[partitionRef].PartitionIndex]; UInt64 offset = ((UInt64)partition.Pos << SecLogSize) + (UInt64)blockPos * vol.BlockSize; RINOK(_stream->Seek(offset, STREAM_SEEK_SET, NULL)); - HRESULT res = ReadStream_FALSE(_stream, buf, len); - if (res == S_FALSE && offset + len > FileSize) + offset += len; + UpdatePhySize(offset); + const HRESULT res = ReadStream_FALSE(_stream, buf, len); + if (res == S_FALSE && offset > FileSize) UnexpectedEnd = true; - RINOK(res); - UpdatePhySize(offset + len); - return S_OK; + return res; } -HRESULT CInArchive::Read(int volIndex, const CLongAllocDesc &lad, Byte *buf) +HRESULT CInArchive::ReadLad(unsigned 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) +HRESULT CInArchive::ReadFromFile(unsigned volIndex, const CItem &item, CByteBuffer &buf) { if (item.Size >= (UInt32)1 << 30) return S_FALSE; @@ -301,7 +374,7 @@ HRESULT CInArchive::ReadFromFile(int volIndex, const CItem &item, CByteBuffer &b FOR_VECTOR (i, item.Extents) { const CMyExtent &e = item.Extents[i]; - UInt32 len = e.GetLen(); + const UInt32 len = e.GetLen(); RINOK(Read(volIndex, e.PartitionRef, e.Pos, len, (Byte *)buf + pos)); pos += len; } @@ -311,36 +384,70 @@ HRESULT CInArchive::ReadFromFile(int volIndex, const CItem &item, CByteBuffer &b void CIcbTag::Parse(const Byte *p) { - // PriorDirectNum = Get32(p); - // StrategyType = Get16(p + 4); - // StrategyParam = Get16(p + 6); - // MaxNumOfEntries = Get16(p + 8); + // G32 (0, PriorDirectNum); + // G16 (4, StrategyType); + // G16 (6, StrategyParam); + // G16 (8, MaxNumOfEntries); FileType = p[11]; // ParentIcb.Parse(p + 12); - Flags = Get16(p + 18); + G16 (18, Flags); } + +// ECMA 4/14.9 File Entry +// UDF FileEntry 2.3.6 + +// ECMA 4/14.17 Extended File Entry + void CItem::Parse(const Byte *p) { - // Uid = Get32(p + 36); - // Gid = Get32(p + 40); - // Permissions = Get32(p + 44); - // FileLinkCount = Get16(p + 48); + // (-1) can be stored in Uid/Gid. + // G32 (36, Uid); + // G32 (40, Gid); + // G32 (44, Permissions); + G16 (48, FileLinkCount); // RecordFormat = p[50]; // RecordDisplayAttr = p[51]; - // RecordLen = Get32(p + 52); - Size = Get64(p + 56); - NumLogBlockRecorded = Get64(p + 64); + // G32 (52, RecordLen); + G64 (56, Size); + if (IsExtended) + { + // The sum of all Information Length fields for all streams of a file (including the default stream). If this file has no + // streams, the Object Size shall be equal to the Information Length. + // G64 (64, ObjectSize); + p += 8; + } + G64 (64, NumLogBlockRecorded); ATime.Parse(p + 72); MTime.Parse(p + 84); + if (IsExtended) + { + CreateTime.Parse(p + 96); + p += 12; + } AttribTime.Parse(p + 96); - // CheckPoint = Get32(p + 108); + // G32 (108, CheckPoint); + /* + if (IsExtended) + { + // Get32(p + 112); // reserved + p += 4; + } // ExtendedAttrIcb.Parse(p + 112); + if (IsExtended) + { + StreamDirectoryIcb.Parse(p + 128); + p += 16; + } + */ + // ImplId.Parse(p + 128); - // UniqueId = Get64(p + 160); + // G64 (160, UniqueId); } -// 4/14.4 + +// ECMA 4/14.4 + struct CFileId { // UInt16 FileVersion; @@ -350,38 +457,40 @@ struct CFileId CLongAllocDesc Icb; bool IsItLinkParent() const { return (FileCharacteristics & FILEID_CHARACS_Parent) != 0; } - HRESULT Parse(const Byte *p, size_t size, size_t &processed); + size_t Parse(const Byte *p, size_t size); }; -HRESULT CFileId::Parse(const Byte *p, size_t size, size_t &processed) +size_t CFileId::Parse(const Byte *p, size_t size) { - processed = 0; + size_t processed = 0; if (size < 38) - return S_FALSE; + return 0; CTag tag; RINOK(tag.Parse(p, size)); if (tag.Id != DESC_TYPE_FileId) - return S_FALSE; + return 0; // FileVersion = Get16(p + 16); FileCharacteristics = p[18]; - unsigned idLen = p[19]; + const unsigned idLen = p[19]; Icb.Parse(p + 20); - unsigned impLen = Get16(p + 36); + const unsigned impLen = Get16(p + 36); if (size < 38 + idLen + impLen) - return S_FALSE; - // ImplUse.SetCapacity(impLen); + return 0; processed = 38; - // memcpy(ImplUse, p + processed, impLen); + // ImplUse.CopyFrom(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; + return 0; + if ((size_t)tag.CrcLen + 16 != processed) return 0; + return (processed <= size) ? processed : 0; } -HRESULT CInArchive::ReadFileItem(int volIndex, int fsIndex, const CLongAllocDesc &lad, int numRecurseAllowed) + + +HRESULT CInArchive::ReadFileItem(unsigned volIndex, unsigned fsIndex, const CLongAllocDesc &lad, int numRecurseAllowed) { if (Files.Size() % 100 == 0) RINOK(_progress->SetCompleted(Files.Size(), _processedProgressBytes)); @@ -389,12 +498,12 @@ HRESULT CInArchive::ReadFileItem(int volIndex, int fsIndex, const CLongAllocDesc return S_FALSE; CFile &file = Files.Back(); const CLogVol &vol = LogVols[volIndex]; - unsigned partitionRef = lad.Location.PartitionRef; + const unsigned partitionRef = lad.Location.PartitionRef; if (partitionRef >= vol.PartitionMaps.Size()) return S_FALSE; CPartition &partition = Partitions[vol.PartitionMaps[partitionRef].PartitionIndex]; - UInt32 key = lad.Location.Pos; + const UInt32 key = lad.Location.Pos; UInt32 value; const UInt32 kRecursedErrorValue = (UInt32)(Int32)-1; if (partition.Map.Find(key, value)) @@ -416,32 +525,47 @@ HRESULT CInArchive::ReadFileItem(int volIndex, int fsIndex, const CLongAllocDesc return S_OK; } -HRESULT CInArchive::ReadItem(int volIndex, int fsIndex, const CLongAllocDesc &lad, int numRecurseAllowed) + +// (fsIndex = -1) means that it's metadata file + +HRESULT CInArchive::ReadItem(unsigned volIndex, int fsIndex, const CLongAllocDesc &lad, int numRecurseAllowed) { - if (Items.Size() > kNumItemsMax) + if (Items.Size() >= kNumItemsMax) return S_FALSE; - Items.Add(CItem()); - CItem &item = Items.Back(); + CItem &item = Items.AddNew(); const CLogVol &vol = LogVols[volIndex]; - if (lad.GetLen() != vol.BlockSize) + const size_t size = lad.GetLen(); + if (size != vol.BlockSize) return S_FALSE; - const size_t size = lad.GetLen(); CByteBuffer buf(size); - RINOK(Read(volIndex, lad, buf)); + RINOK(ReadLad(volIndex, lad, buf)); CTag tag; const Byte *p = buf; RINOK(tag.Parse(p, size)); - if (size < 176) + + item.IsExtended = (tag.Id == DESC_TYPE_ExtendedFile); + const size_t kExtendOffset = item.IsExtended ? 40 : 0; + + if (size < kExtendOffset + 176) return S_FALSE; - if (tag.Id != DESC_TYPE_File) + if (tag.Id != DESC_TYPE_File && + tag.Id != DESC_TYPE_ExtendedFile) return S_FALSE; item.IcbTag.Parse(p + 16); - if (item.IcbTag.FileType != ICB_FILE_TYPE_DIR && + + if (fsIndex < 0) + { + if (item.IcbTag.FileType != ICB_FILE_TYPE_METADATA && + item.IcbTag.FileType != ICB_FILE_TYPE_METADATA_MIRROR) + return S_FALSE; + } + else if ( + item.IcbTag.FileType != ICB_FILE_TYPE_DIR && item.IcbTag.FileType != ICB_FILE_TYPE_FILE) return S_FALSE; @@ -449,12 +573,12 @@ HRESULT CInArchive::ReadItem(int volIndex, int fsIndex, const CLongAllocDesc &la _processedProgressBytes += (UInt64)item.NumLogBlockRecorded * vol.BlockSize + size; - UInt32 extendedAttrLen = Get32(p + 168); - UInt32 allocDescriptorsLen = Get32(p + 172); + const UInt32 extendedAttrLen = Get32(p + 168 + kExtendOffset); + const UInt32 allocDescriptorsLen = Get32(p + 172 + kExtendOffset); if ((extendedAttrLen & 3) != 0) return S_FALSE; - size_t pos = 176; + size_t pos = 176 + kExtendOffset; if (extendedAttrLen > size - pos) return S_FALSE; /* @@ -472,10 +596,10 @@ HRESULT CInArchive::ReadItem(int volIndex, int fsIndex, const CLongAllocDesc &la */ pos += extendedAttrLen; - int desctType = item.IcbTag.GetDescriptorType(); + const int descType = item.IcbTag.GetDescriptorType(); if (allocDescriptorsLen > size - pos) return S_FALSE; - if (desctType == ICB_DESC_TYPE_INLINE) + if (descType == ICB_DESC_TYPE_INLINE) { item.IsInline = true; item.InlineData.CopyFrom(p + pos, allocDescriptorsLen); @@ -483,12 +607,12 @@ HRESULT CInArchive::ReadItem(int volIndex, int fsIndex, const CLongAllocDesc &la else { item.IsInline = false; - if (desctType != ICB_DESC_TYPE_SHORT && desctType != ICB_DESC_TYPE_LONG) + if (descType != ICB_DESC_TYPE_SHORT && descType != ICB_DESC_TYPE_LONG) return S_FALSE; for (UInt32 i = 0; i < allocDescriptorsLen;) { CMyExtent e; - if (desctType == ICB_DESC_TYPE_SHORT) + if (descType == ICB_DESC_TYPE_SHORT) { if (i + 8 > allocDescriptorsLen) return S_FALSE; @@ -516,6 +640,9 @@ HRESULT CInArchive::ReadItem(int volIndex, int fsIndex, const CLongAllocDesc &la if (item.IcbTag.IsDir()) { + if (fsIndex < 0) + return S_FALSE; + if (!item.CheckChunkSizes() || !CheckItemExtents(volIndex, item)) return S_FALSE; CByteBuffer buf2; @@ -525,13 +652,17 @@ HRESULT CInArchive::ReadItem(int volIndex, int fsIndex, const CLongAllocDesc &la item.InlineData.Free(); const Byte *p2 = buf2; - const size_t size2 = buf2.Size(); - size_t processedTotal = 0; - for (; processedTotal < size2;) + size_t size2 = buf2.Size(); + while (size2 != 0) { - size_t processedCur; CFileId fileId; - RINOK(fileId.Parse(p2 + processedTotal, size2 - processedTotal, processedCur)); + { + const size_t cur = fileId.Parse(p2, size2); + if (cur == 0) + return S_FALSE; + p2 += cur; + size2 -= cur; + } if (!fileId.IsItLinkParent()) { CFile file; @@ -545,12 +676,11 @@ HRESULT CInArchive::ReadItem(int volIndex, int fsIndex, const CLongAllocDesc &la return S_FALSE; item.SubFiles.Add(Files.Size()); - if (Files.Size() > kNumFilesMax) + if (Files.Size() >= kNumFilesMax) return S_FALSE; Files.Add(file); RINOK(ReadFileItem(volIndex, fsIndex, fileId.Icb, numRecurseAllowed)); } - processedTotal += processedCur; } } else @@ -567,6 +697,7 @@ HRESULT CInArchive::ReadItem(int volIndex, int fsIndex, const CLongAllocDesc &la return S_OK; } + HRESULT CInArchive::FillRefs(CFileSet &fs, unsigned fileIndex, int parent, int numRecurseAllowed) { if ((_numRefs & 0xFFF) == 0) @@ -591,6 +722,7 @@ HRESULT CInArchive::FillRefs(CFileSet &fs, unsigned fileIndex, int parent, int n return S_OK; } + API_FUNC_IsArc IsArc_Udf(const Byte *p, size_t size) { UInt32 res = k_IsArc_Res_NO; @@ -608,7 +740,11 @@ API_FUNC_IsArc IsArc_Udf(const Byte *p, size_t size) CTag tag; if (tag.Parse(p + offset, bufSize) == S_OK) if (tag.Id == DESC_TYPE_AnchorVolPtr) - return k_IsArc_Res_YES; + { + if (Get32(p + offset + 12) == 256 && // TagLocation + tag.CrcLen >= 16) + return k_IsArc_Res_YES; + } } } } @@ -656,7 +792,7 @@ HRESULT CInArchive::Open2() { if (SecLogSize < 8) return S_FALSE; - UInt32 offset = (UInt32)256 << SecLogSize; + const UInt32 offset = (UInt32)256 << SecLogSize; if (offset >= fileSize) continue; RINOK(_stream->Seek(offset, STREAM_SEEK_SET, NULL)); @@ -668,71 +804,86 @@ HRESULT CInArchive::Open2() CTag tag; if (tag.Parse(buf, readSize) == S_OK) if (tag.Id == DESC_TYPE_AnchorVolPtr) - break; + { + if (Get32(buf + 12) == 256 && + tag.CrcLen >= 16) // TagLocation + break; + } } } PhySize = (UInt32)(256 + 1) << SecLogSize; IsArc = true; + // UDF 2.2.3 AnchorVolumeDescriptorPointer + CExtent extentVDS; extentVDS.Parse(buf + 16); { CExtent extentVDS2; extentVDS2.Parse(buf + 24); - UpdatePhySize(((UInt64)extentVDS.Pos << SecLogSize) + extentVDS.Len); - UpdatePhySize(((UInt64)extentVDS2.Pos << SecLogSize) + extentVDS2.Len); + UpdatePhySize(extentVDS); + UpdatePhySize(extentVDS2); } for (UInt32 location = 0; ; location++) { - const size_t bufSize = (size_t)1 << SecLogSize; - if (((UInt64)(location + 1) << SecLogSize) > extentVDS.Len) + if (location >= (extentVDS.Len >> SecLogSize)) return S_FALSE; - UInt64 offs = (UInt64)(extentVDS.Pos + location) << SecLogSize; - RINOK(_stream->Seek(offs, STREAM_SEEK_SET, NULL)); - HRESULT res = ReadStream_FALSE(_stream, buf, bufSize); - if (res == S_FALSE && offs + bufSize > FileSize) - UnexpectedEnd = true; - RINOK(res); - - - CTag tag; + const size_t bufSize = (size_t)1 << SecLogSize; { - const size_t pos = 0; - RINOK(tag.Parse(buf + pos, bufSize - pos)); + const UInt64 offs = ((UInt64)extentVDS.Pos + location) << SecLogSize; + RINOK(_stream->Seek(offs, STREAM_SEEK_SET, NULL)); + const HRESULT res = ReadStream_FALSE(_stream, buf, bufSize); + if (res == S_FALSE && offs + bufSize > FileSize) + UnexpectedEnd = true; + RINOK(res); } + + CTag tag; + RINOK(tag.Parse(buf, bufSize)); + if (tag.Id == DESC_TYPE_Terminating) break; - + + if (tag.Id == DESC_TYPE_PrimVol) + { + CPrimeVol &pm = PrimeVols.AddNew(); + pm.Parse(buf); + continue; + } + if (tag.Id == DESC_TYPE_Partition) { // Partition Descriptor - // ECMA 167 3/10.5 - // UDF / 2.2.14 - + // ECMA 3/10.5 + // UDF 2.2.14 if (Partitions.Size() >= kNumPartitionsMax) return S_FALSE; CPartition partition; - // UInt32 volDescSeqNumer = Get32(buf + 16); - // partition.Flags = Get16(buf + 20); + // const UInt32 volDescSeqNumer = Get32(buf + 16); + partition.Flags = Get16(buf + 20); partition.Number = Get16(buf + 22); - // partition.ContentsId.Parse(buf + 24); + partition.ContentsId.Parse(buf + 24); // memcpy(partition.ContentsUse, buf + 56, sizeof(partition.ContentsUse)); - // ContentsUse is Partition Header Description. + // ContentsUse contains Partition Header Description. + // ECMA 4/14.3 + // UDF PartitionHeaderDescriptor 2.3.3 - // partition.AccessType = Get32(buf + 184); + partition.AccessType = Get32(buf + 184); partition.Pos = Get32(buf + 188); partition.Len = Get32(buf + 192); - // partition.ImplId.Parse(buf + 196); + partition.ImplId.Parse(buf + 196); // memcpy(partition.ImplUse, buf + 228, sizeof(partition.ImplUse)); PRF(printf("\nPartition number = %2d pos = %d len = %d", partition.Number, partition.Pos, partition.Len)); Partitions.Add(partition); + continue; } - else if (tag.Id == DESC_TYPE_LogicalVol) + + if (tag.Id == DESC_TYPE_LogicalVol) { /* Logical Volume Descriptor ECMA 3/10.6 @@ -740,46 +891,65 @@ HRESULT CInArchive::Open2() if (LogVols.Size() >= kNumLogVolumesMax) return S_FALSE; - CLogVol vol; + CLogVol &vol = LogVols.AddNew(); + vol.Id.Parse(buf + 84); vol.BlockSize = Get32(buf + 212); - // vol.DomainId.Parse(buf + 216); - + if (vol.BlockSize != ((UInt32)1 << SecLogSize)) + { + // UDF 2.2.4.2 LogicalBlockSize + // UDF probably doesn't allow different sizes + return S_FALSE; + } + /* 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); + */ + + vol.DomainId.Parse(buf + 216); + + // ECMA 4/3.1 + // UDF 2.2.4.4 LogicalVolumeContentsUse /* the extent in which the first File Set Descriptor Sequence of the logical volume is recorded */ + vol.FileSetLocation.Parse(buf + 248); + // memcpy(vol.ContentsUse, buf + 248, sizeof(vol.ContentsUse)); - // UInt32 mapTableLength = Get32(buf + 264); - UInt32 numPartitionMaps = Get32(buf + 268); + vol.ImplId.Parse(buf + 272); + // memcpy(vol.ImplUse, buf + 304, sizeof(vol.ImplUse)); + // vol.IntegritySequenceExtent.Parse(buf + 432); + + const UInt32 mapTableLen = Get32(buf + 264); + const UInt32 numPartitionMaps = Get32(buf + 268); if (numPartitionMaps > kNumPartitionsMax) return S_FALSE; - // vol.ImplId.Parse(buf + 272); - // memcpy(vol.ImplUse, buf + 128, sizeof(vol.ImplUse)); PRF(printf("\nLogicalVol numPartitionMaps = %2d", numPartitionMaps)); + size_t pos = 440; + if (mapTableLen > bufSize - pos) + return S_FALSE; + const size_t posLimit = pos + mapTableLen; + for (UInt32 i = 0; i < numPartitionMaps; i++) { - if (pos + 2 > bufSize) + // ECMA 3/10.7 Partition maps + if (pos + 2 > posLimit) return S_FALSE; CPartitionMap pm; - pm.Type = buf[pos]; + pm.Type = buf[pos + 0]; // pm.Length = buf[pos + 1]; - Byte len = buf[pos + 1]; - - if (pos + len > bufSize) + const Byte len = buf[pos + 1]; + if (pos + len > posLimit) return S_FALSE; // memcpy(pm.Data, buf + pos + 2, pm.Length - 2); if (pm.Type == 1) { - if (len != 6) // < 6 + // ECMA 3/10.7.2 + if (len != 6) return S_FALSE; - // pm.VolSeqNumber = Get16(buf + pos + 2); + pm.VolumeSequenceNumber = Get16(buf + pos + 2); pm.PartitionNumber = Get16(buf + pos + 4); PRF(printf("\nPartitionMap type 1 PartitionNumber = %2d", pm.PartitionNumber)); } @@ -790,28 +960,60 @@ HRESULT CInArchive::Open2() /* ECMA 10.7.3 / Type 2 Partition Map 62 bytes: Partition Identifier. */ - /* UDF 2.6 - 2.2.8 Virtual Partition Map - This is an extension of ECMA 167 to expand its scope to include - sequentially written media (eg. CD-R). This extension is for a - Partition Map entry to describe a virtual space. */ + /* UDF + 2.2.8 "*UDF Virtual Partition" + 2.2.9 "*UDF Sparable Partition" + 2.2.10 "*UDF Metadata Partition" + */ - // It's not implemented still. - if (Get16(buf + pos + 2) != 0) + if (Get16(buf + pos + 2) != 0) // reserved return S_FALSE; - // pm.VolSeqNumber = Get16(buf + pos + 36); + + pm.PartitionTypeId.Parse(buf + pos + 4); + pm.VolumeSequenceNumber = Get16(buf + pos + 36); pm.PartitionNumber = Get16(buf + pos + 38); + + if (memcmp(pm.PartitionTypeId.Id, "*UDF Metadata Partition", 23) != 0) + return S_FALSE; + + // UDF 2.2.10 Metadata Partition Map + pm.MetadataFileLocation = Get32(buf + pos + 40); + // pm.MetadataMirrorFileLocation = Get32(buf + pos + 44); + // pm.MetadataBitmapFileLocation = Get32(buf + pos + 48); + // pm.AllocationUnitSize = Get32(buf + pos + 52); + // pm.AlignmentUnitSize = Get16(buf + pos + 56); + // pm.Flags = buf[pos + 58]; + PRF(printf("\nPartitionMap type 2 PartitionNumber = %2d", pm.PartitionNumber)); // Unsupported = true; - return S_FALSE; + // return S_FALSE; } else return S_FALSE; pos += len; vol.PartitionMaps.Add(pm); } - LogVols.Add(vol); + continue; + } + + /* + if (tag.Id == DESC_TYPE_UnallocSpace) + { + // UInt32 volDescSeqNumer = Get32(buf + 16); + const UInt32 numAlocDescs = Get32(buf + 20); + // we need examples for (numAlocDescs != 0) case + if (numAlocDescs > (bufSize - 24) / 8) + return S_FALSE; + for (UInt32 i = 0; i < numAlocDescs; i++) + { + CExtent e; + e.Parse(buf + 24 + i * 8); + } + continue; } + else + continue; + */ } UInt64 totalSize = 0; @@ -823,12 +1025,18 @@ HRESULT CInArchive::Open2() FOR_VECTOR (pmIndex, vol.PartitionMaps) { CPartitionMap &pm = vol.PartitionMaps[pmIndex]; - unsigned i; - for (i = 0; i < Partitions.Size(); i++) + for (unsigned i = 0;; i++) { + if (i == Partitions.Size()) + return S_FALSE; CPartition &part = Partitions[i]; if (part.Number == pm.PartitionNumber) { + pm.PartitionIndex = i; + if (pm.Type == 2) + break; + + /* if (part.VolIndex >= 0) { // it's for 2.60. Fix it @@ -836,15 +1044,85 @@ HRESULT CInArchive::Open2() return S_FALSE; // return S_FALSE; } - pm.PartitionIndex = i; part.VolIndex = volIndex; + */ totalSize += (UInt64)part.Len << SecLogSize; break; } } - if (i == Partitions.Size()) + } + } + + for (volIndex = 0; volIndex < LogVols.Size(); volIndex++) + { + CLogVol &vol = LogVols[volIndex]; + FOR_VECTOR (pmIndex, vol.PartitionMaps) + { + CPartitionMap &pm = vol.PartitionMaps[pmIndex]; + if (pm.Type != 2) + continue; + + { + CLongAllocDesc lad; + lad.Len = vol.BlockSize; + lad.Location.Pos = pm.MetadataFileLocation; + // lad.Location.Pos = pm.MetadataMirrorFileLocation; + + lad.Location.PartitionRef = (UInt16)pmIndex; + + /* we need correct PartitionMaps[lad.Location.PartitionRef].PartitionIndex. + so we can use pmIndex or find (Type==1) PartitionMap */ + FOR_VECTOR (pmIndex2, vol.PartitionMaps) + { + const CPartitionMap &pm2 = vol.PartitionMaps[pmIndex2]; + if (pm2.PartitionNumber == pm.PartitionNumber && pm2.Type == 1) + { + lad.Location.PartitionRef = (UInt16)pmIndex2; + break; + } + } + + RINOK(ReadItem(volIndex, + -1, // (fsIndex = -1) means that it's metadata + lad, + 1)); // numRecurseAllowed + } + { + const CItem &item = Items.Back(); + if (!CheckItemExtents(volIndex, item)) + return S_FALSE; + if (item.Extents.Size() != 1) + return S_FALSE; + + const CMyExtent &e = item.Extents[0]; + const CPartition &part = Partitions[pm.PartitionIndex]; + CPartition mp = part; + mp.IsMetadata = true; + // mp.Number = part.Number; + mp.Pos = part.Pos + e.Pos; + mp.Len = e.Len >> SecLogSize; + pm.PartitionIndex = Partitions.Add(mp); + } + // Items.DeleteBack(); // we can delete that metadata item + + /* + // short version of code to read metadata file. + RINOK(CInArchive::Read(volIndex, pmIndex, pm.MetadataFileLocation, 224, buf)); + CTag tag; + RINOK(tag.Parse(buf, 224)); + if (tag.Id != DESC_TYPE_ExtendedFile) return S_FALSE; + CShortAllocDesc sad; + sad.Parse(buf + 216); + const CPartition &part = Partitions[pm.PartitionIndex]; + CPartition mp = part; + mp.IsMetadata = true; + // mp.Number = part.Number; + mp.Pos = part.Pos + sad.Pos; + mp.Len = sad.Len >> SecLogSize; + pm.PartitionIndex = Partitions.Add(mp); + */ } } @@ -865,37 +1143,41 @@ HRESULT CInArchive::Open2() if (nextExtent.GetLen() < 512) return S_FALSE; CByteBuffer buf2(nextExtent.GetLen()); - RINOK(Read(volIndex, nextExtent, buf2)); + RINOK(ReadLad(volIndex, nextExtent, buf2)); const Byte *p = buf2; - size_t size = nextExtent.GetLen(); + const size_t size = nextExtent.GetLen(); CTag tag; RINOK(tag.Parse(p, size)); + /* + // commented in 22.01 if (tag.Id == DESC_TYPE_ExtendedFile) { // ECMA 4 / 14.17 // 2.60 ?? return S_FALSE; } + */ if (tag.Id != DESC_TYPE_FileSet) return S_FALSE; PRF(printf("\n FileSet", volIndex)); CFileSet fs; - fs.RecodringTime.Parse(p + 16); + fs.RecordingTime.Parse(p + 16); // fs.InterchangeLevel = Get16(p + 18); // fs.MaxInterchangeLevel = Get16(p + 20); - // fs.FileSetNumber = Get32(p + 40); - // fs.FileSetDescNumber = Get32(p + 44); + 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.LogicalVolumeId.Parse(p + 112); + 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.DomainId.Parse(p + 416); // fs.SystemStreamDirICB.Parse(p + 464); @@ -907,7 +1189,7 @@ HRESULT CInArchive::Open2() FOR_VECTOR (fsIndex, vol.FileSets) { CFileSet &fs = vol.FileSets[fsIndex]; - unsigned fileIndex = Files.Size(); + const unsigned fileIndex = Files.Size(); Files.AddNew(); RINOK(ReadFileItem(volIndex, fsIndex, fs.RootDirICB, kNumRecursionLevelsMax)); RINOK(FillRefs(fs, fileIndex, -1, kNumRecursionLevelsMax)); @@ -937,16 +1219,16 @@ HRESULT CInArchive::Open2() FOR_VECTOR (extentIndex, item.Extents) { const CMyExtent &extent = item.Extents[extentIndex]; - UInt32 len = extent.GetLen(); + const UInt32 len = extent.GetLen(); if (len == 0) continue; if (size < len) break; - int partitionIndex = vol.PartitionMaps[extent.PartitionRef].PartitionIndex; - UInt32 logBlockNumber = extent.Pos; + const unsigned partitionIndex = vol.PartitionMaps[extent.PartitionRef].PartitionIndex; + const UInt32 logBlockNumber = extent.Pos; const CPartition &partition = Partitions[partitionIndex]; - UInt64 offset = ((UInt64)partition.Pos << SecLogSize) + + const UInt64 offset = ((UInt64)partition.Pos << SecLogSize) + (UInt64)logBlockNumber * vol.BlockSize; UpdatePhySize(offset + len); } @@ -984,7 +1266,8 @@ HRESULT CInArchive::Open2() if (readSize == 0) break; - if (readSize == secSize && NoEndAnchor) + // some udf contain many EndAnchors + if (readSize == secSize /* && NoEndAnchor */) { CTag tag; if (tag.Parse(buf, readSize) == S_OK && @@ -1051,6 +1334,7 @@ void CInArchive::Clear() Partitions.Clear(); LogVols.Clear(); + PrimeVols.Clear(); Items.Clear(); Files.Clear(); _fileNameLengthTotal = 0; @@ -1060,16 +1344,291 @@ void CInArchive::Clear() _processedProgressBytes = 0; } + +static const char * const g_PartitionTypes[] = +{ + "Pseudo-Overwritable" // UDF + , "Read-Only" + , "Write-Once" + , "Rewritable" + , "Overwritable" +}; + + +static void AddComment_Align(UString &s) +{ + s += " "; +} + +static void AddComment_PropName(UString &s, const char *name) +{ + AddComment_Align(s); + s += name; + s += ": "; +} + +static void AddComment_UInt32(UString &s, const char *name, UInt32 val) +{ + AddComment_PropName(s, name); + s.Add_UInt32(val); + s.Add_LF(); +} + +static void AddComment_UInt32_2(UString &s, const char *name, UInt32 val) +{ + AddComment_Align(s); + AddComment_UInt32(s, name, val); +} + + +static void AddComment_UInt64(UString &s, const char *name, UInt64 val) +{ + AddComment_PropName(s, name); + s.Add_UInt64(val); + s.Add_LF(); +} + +static void AddComment_RegId(UString &s, const char *name, const CRegId &ri) +{ + AddComment_PropName(s, name); + ri.AddCommentTo(s); + s.Add_LF(); +} + +static void AddComment_RegId_Domain(UString &s, const char *name, const CRegId &ri) +{ + AddComment_PropName(s, name); + ri.AddCommentTo(s); + { + UString s2; + ri.AddUdfVersionTo(s2); + if (!s2.IsEmpty()) + { + s += "::"; + s += s2; + } + } + s.Add_LF(); +} + + +// UDF 6.3.1 OS Class + +static const char * const g_OsClasses[] = +{ + NULL + , "DOS" + , "OS/2" + , "Macintosh OS" + , "UNIX" + , "Windows 9x" + , "Windows NT" + , "OS/400" + , "BeOS" + , "Windows CE" +}; + +// UDF 6.3.2 OS Identifier + +static const char * const g_OsIds_Unix[] = +{ + NULL // "Generic" + , "AIX" + , "SUN OS / Solaris" + , "HP/UX" + , "Silicon Graphics Irix" + , "Linux" + , "MKLinux" + , "FreeBSD" + , "NetBSD" +}; + +static void AddOs_Class_Id(UString &s, const char *p) +{ + // UDF 2.1.5.3 Implementation Identifier Suffix + // Appendix 6.3 Operating System Identifiers. + const Byte osClass = p[0]; + if (osClass != 0) + { + s += "::"; + s += TypeToString(g_OsClasses, ARRAY_SIZE(g_OsClasses), osClass); + } + const Byte osId = p[1]; + if (osId != 0) + { + s += "::"; + if (osClass == 4) // unix + { + s += TypeToString(g_OsIds_Unix, ARRAY_SIZE(g_OsIds_Unix), osId); + } + else + s.Add_UInt32(osId); + } +} + + +static void AddComment_RegId_Impl(UString &s, const char *name, const CRegId &ri) +{ + AddComment_PropName(s, name); + ri.AddCommentTo(s); + { + AddOs_Class_Id(s, ri.Suffix); + } + s.Add_LF(); +} + + +static void AddComment_RegId_UdfId(UString &s, const char *name, const CRegId &ri) +{ + AddComment_PropName(s, name); + ri.AddCommentTo(s); + { + // UDF 2.1.5.3 + // UDF Identifier Suffix format + UString s2; + ri.AddUdfVersionTo(s2); + if (!s2.IsEmpty()) + { + s += "::"; + s += s2; + } + AddOs_Class_Id(s, &ri.Suffix[2]); + } + s.Add_LF(); +} + +static void AddComment_DString32(UString &s, const char *name, const CDString32 &d) +{ + AddComment_Align(s); + AddComment_PropName(s, name); + s += d.GetString(); + s.Add_LF(); +} + UString CInArchive::GetComment() const { - UString res; - FOR_VECTOR (i, LogVols) + UString s; { - if (i != 0) - res.Add_Space(); - res += LogVols[i].GetName(); + s += "Primary Volumes:"; + s.Add_LF(); + FOR_VECTOR (i, PrimeVols) + { + if (i != 0) + s.Add_LF(); + const CPrimeVol &pv = PrimeVols[i]; + // AddComment_UInt32(s, "VolumeDescriptorSequenceNumber", pv.VolumeDescriptorSequenceNumber); + // if (PrimeVols.Size() != 1 || pv.PrimaryVolumeDescriptorNumber != 0) + AddComment_UInt32(s, "PrimaryVolumeDescriptorNumber", pv.PrimaryVolumeDescriptorNumber); + // if (pv.MaximumVolumeSequenceNumber != 1 || pv.VolumeSequenceNumber != 1) + AddComment_UInt32(s, "VolumeSequenceNumber", pv.VolumeSequenceNumber); + if (pv.MaximumVolumeSequenceNumber != 1) + AddComment_UInt32(s, "MaximumVolumeSequenceNumber", pv.MaximumVolumeSequenceNumber); + AddComment_PropName(s, "VolumeId"); + s += pv.VolumeId.GetString(); + s.Add_LF(); + AddComment_PropName(s, "VolumeSetId"); + s += pv.VolumeSetId.GetString(); + s.Add_LF(); + // AddComment_UInt32(s, "InterchangeLevel", pv.InterchangeLevel); + // AddComment_UInt32(s, "MaximumInterchangeLevel", pv.MaximumInterchangeLevel); + AddComment_RegId(s, "ApplicationId", pv.ApplicationId); + AddComment_RegId_Impl(s, "ImplementationId", pv.ImplId); + } } - return res; + { + s += "Partitions:"; + s.Add_LF(); + FOR_VECTOR (i, Partitions) + { + if (i != 0) + s.Add_LF(); + const CPartition &part = Partitions[i]; + AddComment_UInt32(s, "PartitionIndex", i); + AddComment_UInt32(s, "PartitionNumber", part.Number); + if (part.IsMetadata) + AddComment_UInt32(s, "IsMetadata", 1); + else + { + AddComment_RegId(s, "ContentsId", part.ContentsId); + AddComment_RegId_Impl(s, "ImplementationId", part.ImplId); + AddComment_PropName(s, "AccessType"); + s += TypeToString(g_PartitionTypes, ARRAY_SIZE(g_PartitionTypes), part.AccessType); + s.Add_LF(); + } + AddComment_UInt64(s, "Size", (UInt64)part.Len << SecLogSize); + AddComment_UInt64(s, "Pos", (UInt64)part.Pos << SecLogSize); + } + } + s += "Logical Volumes:"; + s.Add_LF(); + { + FOR_VECTOR (i, LogVols) + { + if (i != 0) + s.Add_LF(); + const CLogVol &vol = LogVols[i]; + if (LogVols.Size() != 1) + AddComment_UInt32(s, "Number", i); + AddComment_PropName(s, "Id"); + s += vol.Id.GetString(); + s.Add_LF(); + AddComment_UInt32(s, "BlockSize", vol.BlockSize); + AddComment_RegId_Domain(s, "DomainId", vol.DomainId); + AddComment_RegId_Impl(s, "ImplementationId", vol.ImplId); + // AddComment_UInt64(s, "IntegritySequenceExtent_Len", vol.IntegritySequenceExtent.Len); + // AddComment_UInt64(s, "IntegritySequenceExtent_Pos", (UInt64)vol.IntegritySequenceExtent.Pos << SecLogSize); + + s += " Partition Maps:"; + s.Add_LF(); + { + FOR_VECTOR (j, vol.PartitionMaps) + { + if (j != 0) + s.Add_LF(); + const CPartitionMap &pm = vol.PartitionMaps[j]; + AddComment_UInt32_2(s, "PartitionMap", j); + AddComment_UInt32_2(s, "Type", pm.Type); + AddComment_UInt32_2(s, "VolumeSequenceNumber", pm.VolumeSequenceNumber); + AddComment_UInt32_2(s, "PartitionNumber", pm.PartitionNumber); + if (pm.Type == 2) + { + AddComment_UInt32_2(s, "MetadataFileLocation", pm.MetadataFileLocation); + // AddComment_UInt32_2(s, "MetadataMirrorFileLocation", pm.MetadataMirrorFileLocation); + // AddComment_UInt32_2(s, "MetadataBitmapFileLocation", pm.MetadataBitmapFileLocation); + // AddComment_UInt32_2(s, "AllocationUnitSize", pm.AllocationUnitSize); + // AddComment_UInt32_2(s, "AlignmentUnitSize", pm.AlignmentUnitSize); + // AddComment_UInt32_2(s, "Flags", pm.Flags); + AddComment_Align(s); AddComment_RegId_UdfId(s, "PartitionTypeId", pm.PartitionTypeId); + } + } + } + s += " File Sets:"; + s.Add_LF(); + { + FOR_VECTOR (j, vol.FileSets) + { + if (j != 0) + s.Add_LF(); + const CFileSet &fs = vol.FileSets[j]; + AddComment_Align(s); AddComment_UInt32(s, "FileSetNumber", fs.FileSetNumber); + AddComment_Align(s); AddComment_UInt32(s, "FileSetDescNumber", fs.FileSetDescNumber); + + AddComment_Align(s); + AddComment_PropName(s, "LogicalVolumeId"); + s += fs.LogicalVolumeId.GetString(); + s.Add_LF(); + + AddComment_DString32(s, "Id", fs.Id); + AddComment_DString32(s, "CopyrightId", fs.CopyrightId); + AddComment_DString32(s, "AbstractId", fs.AbstractId); + + AddComment_Align(s); + AddComment_RegId_Domain(s, "DomainId", fs.DomainId); + } + } + } + } + return s; } static UString GetSpecName(const UString &name) @@ -1089,7 +1648,7 @@ static void UpdateWithName(UString &res, const UString &addString) res.Insert(0, addString + WCHAR_PATH_SEPARATOR); } -UString CInArchive::GetItemPath(int volIndex, int fsIndex, int refIndex, +UString CInArchive::GetItemPath(unsigned volIndex, unsigned fsIndex, unsigned refIndex, bool showVolName, bool showFsName) const { // showVolName = true; @@ -1101,9 +1660,10 @@ UString CInArchive::GetItemPath(int volIndex, int fsIndex, int refIndex, for (;;) { const CRef &ref = fs.Refs[refIndex]; - refIndex = ref.Parent; - if (refIndex < 0) + // we break on root file (that probably has empty name) + if (ref.Parent < 0) break; + refIndex = ref.Parent; UpdateWithName(name, GetSpecName(Files[ref.FileIndex].GetName())); } diff --git a/CPP/7zip/Archive/Udf/UdfIn.h b/CPP/7zip/Archive/Udf/UdfIn.h index 4e7dfa1..d962e7d 100644 --- a/CPP/7zip/Archive/Udf/UdfIn.h +++ b/CPP/7zip/Archive/Udf/UdfIn.h @@ -17,16 +17,15 @@ namespace NUdf { // ---------- ECMA Part 1 ---------- // ECMA 1/7.2.12 +// UDF 2.1.3 -/* struct CDString32 { Byte Data[32]; - void Parse(const Byte *buf); - // UString GetString() const; + void Parse(const Byte *buf) { memcpy(Data, buf, sizeof(Data)); } + UString GetString() const; }; -*/ struct CDString128 { @@ -46,6 +45,7 @@ struct CDString // ECMA 1/7.3 +// UDF 2.1.4 timestamp struct CTime { @@ -65,9 +65,9 @@ struct CTime }; -// ECMA 1/7.4 +// ECMA 1/7.4 regid +// UDF 2.1.5 EntityID -/* struct CRegId { Byte Flags; @@ -75,44 +75,97 @@ struct CRegId char Suffix[8]; void Parse(const Byte *buf); + void AddCommentTo(UString &s) const; + void AddUdfVersionTo(UString &s) const; }; -*/ + + // ---------- ECMA Part 3: Volume Structure ---------- -// ECMA 3/10.5 +// ECMA 3/7.1 -struct CPartition +struct CExtent +{ + UInt32 Len; + UInt32 Pos; // logical sector number + + void Parse(const Byte *p); +}; + + +// ECMA 3/10.1 +// UDF 2.2.2 PrimaryVolumeDescriptor + +struct CPrimeVol { + // UInt32 VolumeDescriptorSequenceNumber; + UInt32 PrimaryVolumeDescriptorNumber; + CDString32 VolumeId; + UInt16 VolumeSequenceNumber; + UInt16 MaximumVolumeSequenceNumber; + // UInt16 InterchangeLevel; + // UInt16 MaximumInterchangeLevel; + // UInt32 CharacterSetList; + // UInt32 MaximumCharacterSetList; + CDString128 VolumeSetId; + // charspec DescriptorCharacterSet; // (1/7.2.1) + // charspec ExplanatoryCharacterSet; // (1/7.2.1) + // CExtent VolumeAbstract; + // CExtent VolumeCopyrightNotice; + CRegId ApplicationId; + CTime RecordingTime; + CRegId ImplId; + // bytes ImplementationUse + // UInt32 PredecessorVolumeDescriptorSequenceLocation; // UInt16 Flags; - UInt16 Number; - // CRegId ContentsId; - // Byte ContentsUse[128]; - // UInt32 AccessType; + void Parse(const Byte *p); +}; + + +// ECMA 3/10.5 +// UDF 2.2.14 PartitionDescriptor + +struct CPartition +{ UInt32 Pos; UInt32 Len; - // CRegId ImplId; + UInt16 Flags; + UInt16 Number; + CRegId ContentsId; + // Byte ContentsUse[128]; + UInt32 AccessType; + + CRegId ImplId; // Byte ImplUse[128]; - int VolIndex; + // int VolIndex; CMap32 Map; - CPartition(): VolIndex(-1) {} + bool IsMetadata; + + CPartition(): + // VolIndex(-1), + IsMetadata(false) {} // bool IsNsr() const { return (strncmp(ContentsId.Id, "+NSR0", 5) == 0); } // bool IsAllocated() const { return ((Flags & 1) != 0); } }; + +// ECMA 4/7.1 lb_addr + struct CLogBlockAddr { UInt32 Pos; UInt16 PartitionRef; - void Parse(const Byte *buf); + void Parse(const Byte *p); }; + enum EShortAllocDescType { SHORT_ALLOC_DESC_TYPE_RecordedAndAllocated = 0, @@ -121,16 +174,18 @@ enum EShortAllocDescType SHORT_ALLOC_DESC_TYPE_NextExtent = 3 }; + +// ECMA 4/14.14.1 short_ad + struct CShortAllocDesc { UInt32 Len; UInt32 Pos; - // 4/14.14.1 // UInt32 GetLen() const { return Len & 0x3FFFFFFF; } // UInt32 GetType() const { return Len >> 30; } // bool IsRecAndAlloc() const { return GetType() == SHORT_ALLOC_DESC_TYPE_RecordedAndAllocated; } - void Parse(const Byte *buf); + void Parse(const Byte *p); }; /* @@ -138,10 +193,13 @@ struct CADImpUse { UInt16 Flags; UInt32 UdfUniqueId; - void Parse(const Byte *buf); + void Parse(const Byte *p); }; */ +// ECMA 4/14.14.2 long_ad +// UDF 2.3.10.1 + struct CLongAllocDesc { UInt32 Len; @@ -153,29 +211,48 @@ struct CLongAllocDesc UInt32 GetLen() const { return Len & 0x3FFFFFFF; } UInt32 GetType() const { return Len >> 30; } bool IsRecAndAlloc() const { return GetType() == SHORT_ALLOC_DESC_TYPE_RecordedAndAllocated; } - void Parse(const Byte *buf); + void Parse(const Byte *p); }; + +// ECMA 3/10.7 Partition maps +// UDF 2.2.8-2.2.10 Partition Maps + struct CPartitionMap { + unsigned PartitionIndex; + Byte Type; // Byte Len; - // Type - 1 - // UInt16 VolSeqNumber; + // ECMA 10.7.2 + UInt16 VolumeSequenceNumber; UInt16 PartitionNumber; + + CRegId PartitionTypeId; - // Byte Data[256]; + // UDF 2.2.10 Metadata Partition Map + UInt32 MetadataFileLocation; + // UInt32 MetadataMirrorFileLocation; + // UInt32 MetadataBitmapFileLocation; + // UInt32 AllocationUnitSize; // (Blocks) + // UInt16 AlignmentUnitSize; // (Blocks) + // Byte Flags; - int PartitionIndex; + // Byte Data[256]; + // CPartitionMap(): PartitionIndex(-1) {} }; -// ECMA 4/14.6 + +// ECMA 4/14.6.6 enum EIcbFileType { ICB_FILE_TYPE_DIR = 4, - ICB_FILE_TYPE_FILE = 5 + ICB_FILE_TYPE_FILE = 5, + + ICB_FILE_TYPE_METADATA = 250, // 2.2.13.1 Metadata File + ICB_FILE_TYPE_METADATA_MIRROR = 251 }; enum EIcbDescriptorType @@ -186,6 +263,9 @@ enum EIcbDescriptorType ICB_DESC_TYPE_INLINE = 3 }; +// ECMA 4/14.6 +// UDF 3.3.2 + struct CIcbTag { // UInt32 PriorDirectNum; @@ -201,33 +281,35 @@ struct CIcbTag void Parse(const Byte *p); }; +// ECMA 4/14.4.3 // const Byte FILEID_CHARACS_Existance = (1 << 0); const Byte FILEID_CHARACS_Parent = (1 << 3); struct CFile { + int ItemIndex; // UInt16 FileVersion; // Byte FileCharacteristics; // CByteBuffer ImplUse; CDString Id; - int ItemIndex; - CFile(): /* FileVersion(0), FileCharacteristics(0), */ ItemIndex(-1) {} UString GetName() const { return Id.GetString(); } }; + struct CMyExtent { UInt32 Pos; UInt32 Len; - unsigned PartitionRef; + unsigned PartitionRef; // index in CLogVol::PartitionMaps UInt32 GetLen() const { return Len & 0x3FFFFFFF; } UInt32 GetType() const { return Len >> 30; } bool IsRecAndAlloc() const { return GetType() == SHORT_ALLOC_DESC_TYPE_RecordedAndAllocated; } }; + struct CItem { CIcbTag IcbTag; @@ -235,26 +317,30 @@ struct CItem // UInt32 Uid; // UInt32 Gid; // UInt32 Permissions; - // UInt16 FileLinkCount; + UInt16 FileLinkCount; // Byte RecordFormat; // Byte RecordDisplayAttr; // UInt32 RecordLen; UInt64 Size; UInt64 NumLogBlockRecorded; + // UInt64 ObjectSize; + CTime ATime; CTime MTime; CTime AttribTime; // Attribute time : most recent date and time of the day of file creation or modification of the attributes of. + CTime CreateTime; // UInt32 CheckPoint; // CLongAllocDesc ExtendedAttrIcb; // CRegId ImplId; // UInt64 UniqueId; + bool IsExtended; bool IsInline; CByteBuffer InlineData; CRecordVector Extents; CUIntVector SubFiles; - void Parse(const Byte *buf); + void Parse(const Byte *p); bool IsRecAndAlloc() const { @@ -279,53 +365,65 @@ struct CItem bool IsDir() const { return IcbTag.IsDir(); } }; + struct CRef { - int Parent; unsigned FileIndex; + int Parent; }; // ECMA 4 / 14.1 struct CFileSet { - CTime RecodringTime; + CRecordVector Refs; + + CTime RecordingTime; // UInt16 InterchangeLevel; // UInt16 MaxInterchangeLevel; - // UInt32 FileSetNumber; - // UInt32 FileSetDescNumber; - // CDString32 Id; - // CDString32 CopyrightId; - // CDString32 AbstractId; + UInt32 FileSetNumber; + UInt32 FileSetDescNumber; + CDString128 LogicalVolumeId; + CDString32 Id; + CDString32 CopyrightId; + CDString32 AbstractId; CLongAllocDesc RootDirICB; - // CRegId DomainId; + CRegId DomainId; // CLongAllocDesc SystemStreamDirICB; - - CRecordVector Refs; }; +/* 8.3 Volume descriptors +8.4 +A Volume Descriptor Sequence: + shall contain one or more Primary Volume Descriptors. +*/ + // ECMA 3/10.6 +// UDF 2.2.4 LogicalVolumeDescriptor struct CLogVol { - CDString128 Id; + CObjectVector PartitionMaps; + CObjectVector FileSets; + UInt32 BlockSize; - // CRegId DomainId; + CDString128 Id; + CRegId DomainId; // Byte ContentsUse[16]; CLongAllocDesc FileSetLocation; // UDF - // CRegId ImplId; + CRegId ImplId; // Byte ImplUse[128]; - - CObjectVector PartitionMaps; - CObjectVector FileSets; + // CExtent IntegritySequenceExtent; UString GetName() const { return Id.GetString(); } }; + + struct CProgressVirt { virtual HRESULT SetTotal(UInt64 numBytes) PURE; @@ -335,15 +433,42 @@ struct CProgressVirt class CInArchive { +public: + CObjectVector LogVols; + CObjectVector Items; + CObjectVector Files; + CObjectVector Partitions; + + unsigned SecLogSize; + UInt64 PhySize; + UInt64 FileSize; + + bool IsArc; + bool Unsupported; + bool UnexpectedEnd; + bool NoEndAnchor; + + CObjectVector PrimeVols; + + HRESULT Open(IInStream *inStream, CProgressVirt *progress); + void Clear(); + + UString GetComment() const; + UString GetItemPath(unsigned volIndex, unsigned fsIndex, unsigned refIndex, + bool showVolName, bool showFsName) const; + + bool CheckItemExtents(unsigned volIndex, const CItem &item) const; + +private: IInStream *_stream; CProgressVirt *_progress; - HRESULT Read(int volIndex, int partitionRef, UInt32 blockPos, UInt32 len, Byte *buf); - HRESULT Read(int volIndex, const CLongAllocDesc &lad, Byte *buf); - HRESULT ReadFromFile(int volIndex, const CItem &item, CByteBuffer &buf); + HRESULT Read(unsigned volIndex, unsigned partitionRef, UInt32 blockPos, UInt32 len, Byte *buf); + HRESULT ReadLad(unsigned volIndex, const CLongAllocDesc &lad, Byte *buf); + HRESULT ReadFromFile(unsigned volIndex, const CItem &item, CByteBuffer &buf); - HRESULT ReadFileItem(int volIndex, int fsIndex, const CLongAllocDesc &lad, int numRecurseAllowed); - HRESULT ReadItem(int volIndex, int fsIndex, const CLongAllocDesc &lad, int numRecurseAllowed); + HRESULT ReadFileItem(unsigned volIndex, unsigned fsIndex, const CLongAllocDesc &lad, int numRecurseAllowed); + HRESULT ReadItem(unsigned volIndex, int fsIndex, const CLongAllocDesc &lad, int numRecurseAllowed); HRESULT Open2(); HRESULT FillRefs(CFileSet &fs, unsigned fileIndex, int parent, int numRecurseAllowed); @@ -354,37 +479,18 @@ class CInArchive unsigned _numRefs; UInt32 _numExtents; UInt64 _inlineExtentsSize; - bool CheckExtent(int volIndex, int partitionRef, UInt32 blockPos, UInt32 len) const; - -public: - CObjectVector Partitions; - CObjectVector LogVols; - - CObjectVector Items; - CObjectVector Files; - - unsigned SecLogSize; - UInt64 PhySize; - UInt64 FileSize; - - bool IsArc; - bool Unsupported; - bool UnexpectedEnd; - bool NoEndAnchor; + bool CheckExtent(unsigned volIndex, unsigned partitionRef, UInt32 blockPos, UInt32 len) const; void UpdatePhySize(UInt64 val) { if (PhySize < val) PhySize = val; } - HRESULT Open(IInStream *inStream, CProgressVirt *progress); - void Clear(); - - UString GetComment() const; - UString GetItemPath(int volIndex, int fsIndex, int refIndex, - bool showVolName, bool showFsName) const; - bool CheckItemExtents(int volIndex, const CItem &item) const; + void UpdatePhySize(const CExtent &e) + { + UpdatePhySize(((UInt64)e.Pos << SecLogSize) + e.Len); + } }; API_FUNC_IsArc IsArc_Udf(const Byte *p, size_t size); diff --git a/CPP/7zip/Bundles/Alone/makefile.gcc b/CPP/7zip/Bundles/Alone/makefile.gcc index 38f8d59..20d6a86 100644 --- a/CPP/7zip/Bundles/Alone/makefile.gcc +++ b/CPP/7zip/Bundles/Alone/makefile.gcc @@ -13,11 +13,20 @@ LOCAL_FLAGS_ST = MT_OBJS = +ifdef SystemDrive +IS_MINGW = 1 +else +ifdef SYSTEMDRIVE +# ifdef OS +IS_MINGW = 1 +endif +endif + ifdef ST_MODE LOCAL_FLAGS_ST = -D_7ZIP_ST -ifdef SystemDrive +ifdef IS_MINGW MT_OBJS = \ $O/Threads.o \ @@ -41,7 +50,7 @@ endif LOCAL_FLAGS_SYS = -ifdef SystemDrive +ifdef IS_MINGW LOCAL_FLAGS_SYS = \ -D_7ZIP_LARGE_PAGES \ diff --git a/CPP/7zip/Bundles/Alone2/makefile.gcc b/CPP/7zip/Bundles/Alone2/makefile.gcc index f8d31db..49f9fd0 100644 --- a/CPP/7zip/Bundles/Alone2/makefile.gcc +++ b/CPP/7zip/Bundles/Alone2/makefile.gcc @@ -9,6 +9,15 @@ CONSOLE_VARIANT_FLAGS=-DPROG_VARIANT_Z include ../Format7zF/Arc_gcc.mak ifdef SystemDrive +IS_MINGW = 1 +else +ifdef SYSTEMDRIVE +# ifdef OS +IS_MINGW = 1 +endif +endif + +ifdef IS_MINGW LOCAL_FLAGS_SYS = \ -D_7ZIP_LARGE_PAGES \ diff --git a/CPP/7zip/Bundles/Alone7z/makefile.gcc b/CPP/7zip/Bundles/Alone7z/makefile.gcc index 8565452..f11fcde 100644 --- a/CPP/7zip/Bundles/Alone7z/makefile.gcc +++ b/CPP/7zip/Bundles/Alone7z/makefile.gcc @@ -6,6 +6,15 @@ CONSOLE_VARIANT_FLAGS=-DPROG_VARIANT_R # USE_ASM = 1 # ST_MODE = 1 +ifdef SystemDrive +IS_MINGW = 1 +else +ifdef SYSTEMDRIVE +# ifdef OS +IS_MINGW = 1 +endif +endif + include ../../LzmaDec_gcc.mak @@ -17,7 +26,7 @@ ifdef ST_MODE LOCAL_FLAGS_ST = -D_7ZIP_ST -ifdef SystemDrive +ifdef IS_MINGW MT_OBJS = \ $O/Threads.o \ @@ -41,7 +50,7 @@ endif LOCAL_FLAGS_SYS = -ifdef SystemDrive +ifdef IS_MINGW LOCAL_FLAGS_SYS = \ -D_7ZIP_LARGE_PAGES \ diff --git a/CPP/7zip/Bundles/Format7zF/Arc_gcc.mak b/CPP/7zip/Bundles/Format7zF/Arc_gcc.mak index e5e1e21..1292dd8 100644 --- a/CPP/7zip/Bundles/Format7zF/Arc_gcc.mak +++ b/CPP/7zip/Bundles/Format7zF/Arc_gcc.mak @@ -3,12 +3,20 @@ include ../../LzmaDec_gcc.mak LOCAL_FLAGS_ST = MT_OBJS = +ifdef SystemDrive +IS_MINGW = 1 +else +ifdef SYSTEMDRIVE +# ifdef OS +IS_MINGW = 1 +endif +endif ifdef ST_MODE LOCAL_FLAGS_ST = -D_7ZIP_ST -ifdef SystemDrive +ifdef IS_MINGW MT_OBJS = \ $O/Threads.o \ diff --git a/CPP/7zip/Bundles/Format7zF/Format7z.dsp b/CPP/7zip/Bundles/Format7zF/Format7z.dsp index cf2d9e8..bd2ed44 100644 --- a/CPP/7zip/Bundles/Format7zF/Format7z.dsp +++ b/CPP/7zip/Bundles/Format7zF/Format7z.dsp @@ -2847,6 +2847,10 @@ SOURCE=..\..\Archive\HfsHandler.cpp # End Source File # Begin Source File +SOURCE=..\..\Archive\HfsHandler.h +# End Source File +# Begin Source File + SOURCE=..\..\Archive\IArchive.h # End Source File # Begin Source File diff --git a/CPP/7zip/Bundles/Format7zF/makefile.gcc b/CPP/7zip/Bundles/Format7zF/makefile.gcc index 1953dd5..e468d7c 100644 --- a/CPP/7zip/Bundles/Format7zF/makefile.gcc +++ b/CPP/7zip/Bundles/Format7zF/makefile.gcc @@ -8,6 +8,16 @@ DEF_FILE = ../../Archive/Archive2.def include Arc_gcc.mak ifdef SystemDrive +IS_MINGW = 1 +else +ifdef SYSTEMDRIVE +# ifdef OS +IS_MINGW = 1 +endif +endif + + +ifdef IS_MINGW LOCAL_FLAGS_WIN = \ -D_7ZIP_LARGE_PAGES \ diff --git a/CPP/7zip/Bundles/LzmaCon/makefile.gcc b/CPP/7zip/Bundles/LzmaCon/makefile.gcc index 58c204a..e45ebb6 100644 --- a/CPP/7zip/Bundles/LzmaCon/makefile.gcc +++ b/CPP/7zip/Bundles/LzmaCon/makefile.gcc @@ -10,6 +10,15 @@ LOCAL_FLAGS_ST = MT_OBJS = +ifdef SystemDrive +IS_MINGW = 1 +else +ifdef SYSTEMDRIVE +# ifdef OS +IS_MINGW = 1 +endif +endif + ifdef ST_MODE LOCAL_FLAGS_ST = -D_7ZIP_ST @@ -30,7 +39,7 @@ endif LOCAL_FLAGS_SYS = -ifdef SystemDrive +ifdef IS_MINGW SYS_OBJS = \ $O/Registry.o \ diff --git a/CPP/7zip/Bundles/SFXCon/makefile.gcc b/CPP/7zip/Bundles/SFXCon/makefile.gcc index 889ec1f..551b3e1 100644 --- a/CPP/7zip/Bundles/SFXCon/makefile.gcc +++ b/CPP/7zip/Bundles/SFXCon/makefile.gcc @@ -11,11 +11,20 @@ LOCAL_FLAGS_ST = MT_OBJS = +ifdef SystemDrive +IS_MINGW = 1 +else +ifdef SYSTEMDRIVE +# ifdef OS +IS_MINGW = 1 +endif +endif + ifdef ST_MODE LOCAL_FLAGS_ST = -D_7ZIP_ST -ifdef SystemDrive +ifdef IS_MINGW MT_OBJS = \ $O/Threads.o \ @@ -35,7 +44,7 @@ endif LOCAL_FLAGS_SYS = -ifdef SystemDrive +ifdef IS_MINGW LOCAL_FLAGS_SYS = \ diff --git a/CPP/7zip/Common/FileStreams.cpp b/CPP/7zip/Common/FileStreams.cpp index 6862a9b..0349e90 100644 --- a/CPP/7zip/Common/FileStreams.cpp +++ b/CPP/7zip/Common/FileStreams.cpp @@ -11,9 +11,12 @@ #include #include -// for major minor -// BSD: +// for major()/minor(): +#if defined(__FreeBSD__) || defined(BSD) +#include +#else #include +#endif #endif diff --git a/CPP/7zip/Compress/LzfseDecoder.cpp b/CPP/7zip/Compress/LzfseDecoder.cpp index 41c7445..0eb10af 100644 --- a/CPP/7zip/Compress/LzfseDecoder.cpp +++ b/CPP/7zip/Compress/LzfseDecoder.cpp @@ -89,11 +89,8 @@ HRESULT CDecoder::DecodeUncompressed(UInt32 unpackSize) -HRESULT CDecoder::DecodeLzvn(UInt32 unpackSize) +HRESULT CDecoder::DecodeLzvn(UInt32 unpackSize, UInt32 packSize) { - UInt32 packSize; - RINOK(GetUInt32(packSize)); - PRF(printf("\nLZVN %7u %7u", unpackSize, packSize)); UInt32 D = 0; @@ -854,6 +851,16 @@ STDMETHODIMP CDecoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStr UInt64 prevOut = 0; UInt64 prevIn = 0; + if (LzvnMode) + { + const UInt64 unpackSize = *outSize; + const UInt64 packSize = *inSize; + if (unpackSize > (UInt32)(Int32)-1 + || packSize > (UInt32)(Int32)-1) + return S_FALSE; + RINOK(DecodeLzvn((UInt32)unpackSize, (UInt32)packSize)); + } + else for (;;) { const UInt64 pos = m_OutWindowStream.GetProcessedSize(); @@ -889,7 +896,12 @@ STDMETHODIMP CDecoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStr if (v == kSignature_LZFSE_V1 || v == kSignature_LZFSE_V2) res = DecodeLzfse(cur, (Byte)v); else if (v == 0x6E) // 'n' - res = DecodeLzvn(cur); + { + UInt32 packSize; + res = GetUInt32(packSize); + if (res == S_OK) + res = DecodeLzvn(cur, packSize); + } else if (v == 0x2D) // '-' res = DecodeUncompressed(cur); else diff --git a/CPP/7zip/Compress/LzfseDecoder.h b/CPP/7zip/Compress/LzfseDecoder.h index 0156a08..401e0ba 100644 --- a/CPP/7zip/Compress/LzfseDecoder.h +++ b/CPP/7zip/Compress/LzfseDecoder.h @@ -41,14 +41,23 @@ class CDecoder: HRESULT GetUInt32(UInt32 &val); HRESULT DecodeUncompressed(UInt32 unpackSize); - HRESULT DecodeLzvn(UInt32 unpackSize); + HRESULT DecodeLzvn(UInt32 unpackSize, UInt32 packSize); HRESULT DecodeLzfse(UInt32 unpackSize, Byte version); STDMETHOD(CodeReal)(ISequentialInStream *inStream, ISequentialOutStream *outStream, const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress); public: + bool LzvnMode; MY_UNKNOWN_IMP + CDecoder(): + LzvnMode(false) + {} + + // sizes are checked in Code() + // UInt64 GetInputProcessedSize() const { return m_InStream.GetProcessedSize(); } + // UInt64 GetOutputProcessedSize() const { return m_OutWindowStream.GetProcessedSize(); } + STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream, const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress); }; diff --git a/CPP/7zip/UI/Client7z/makefile.gcc b/CPP/7zip/UI/Client7z/makefile.gcc index b65095b..3f97205 100644 --- a/CPP/7zip/UI/Client7z/makefile.gcc +++ b/CPP/7zip/UI/Client7z/makefile.gcc @@ -6,6 +6,16 @@ IS_NOT_STANDALONE = 1 ifdef SystemDrive +IS_MINGW = 1 +else +ifdef SYSTEMDRIVE +# ifdef OS +IS_MINGW = 1 +endif +endif + + +ifdef IS_MINGW SYS_OBJS = \ $O/resource.o \ diff --git a/CPP/7zip/UI/Common/EnumDirItems.cpp b/CPP/7zip/UI/Common/EnumDirItems.cpp index a4ac413..dab3725 100644 --- a/CPP/7zip/UI/Common/EnumDirItems.cpp +++ b/CPP/7zip/UI/Common/EnumDirItems.cpp @@ -187,7 +187,7 @@ CDirItems::CDirItems(): , ReadSecure(false) #endif #ifndef _WIN32 - , StoreOwnerName(true) + , StoreOwnerName(false) #endif , Callback(NULL) { @@ -1361,6 +1361,7 @@ HRESULT CDirItems::FillDeviceSizes() // 200K/sec speed u.Empty(); const passwd *pw = getpwuid(OwnerNameMap.Numbers[i]); + // printf("\ngetpwuid=%s\n", pw->pw_name); if (pw) { a = pw->pw_name; diff --git a/CPP/7zip/UI/Common/UpdateCallback.cpp b/CPP/7zip/UI/Common/UpdateCallback.cpp index 926a275..c93bfc7 100644 --- a/CPP/7zip/UI/Common/UpdateCallback.cpp +++ b/CPP/7zip/UI/Common/UpdateCallback.cpp @@ -8,11 +8,15 @@ // #include // #include -// for major minor: -// BSD: +// for major()/minor(): +#if defined(__FreeBSD__) || defined(BSD) +#include +#else #include #endif +#endif + #ifndef _7ZIP_ST #include "../../../Windows/Synchronization.h" #endif diff --git a/CPP/7zip/UI/Console/Console.dsp b/CPP/7zip/UI/Console/Console.dsp index f6a3254..ea336cf 100644 --- a/CPP/7zip/UI/Console/Console.dsp +++ b/CPP/7zip/UI/Console/Console.dsp @@ -345,6 +345,10 @@ SOURCE=..\..\..\Windows\Registry.h # End Source File # Begin Source File +SOURCE=..\..\..\Windows\SecurityUtils.h +# End Source File +# Begin Source File + SOURCE=..\..\..\Windows\Synchronization.h # End Source File # Begin Source File diff --git a/CPP/7zip/UI/Console/makefile.gcc b/CPP/7zip/UI/Console/makefile.gcc index ed05a14..d7e4447 100644 --- a/CPP/7zip/UI/Console/makefile.gcc +++ b/CPP/7zip/UI/Console/makefile.gcc @@ -9,11 +9,20 @@ IS_NOT_STANDALONE = 1 LOCAL_FLAGS_ST = MT_OBJS = +ifdef SystemDrive +IS_MINGW = 1 +else +ifdef SYSTEMDRIVE +# ifdef OS +IS_MINGW = 1 +endif +endif + ifdef ST_MODE LOCAL_FLAGS_ST = -D_7ZIP_ST -ifdef SystemDrive +ifdef IS_MINGW MT_OBJS = \ $O/Threads.o \ @@ -31,7 +40,7 @@ endif LOCAL_FLAGS_WIN= -ifdef SystemDrive +ifdef IS_MINGW LOCAL_FLAGS_WIN = \ -D_7ZIP_LARGE_PAGES \ diff --git a/CPP/7zip/UI/Explorer/resource.rc b/CPP/7zip/UI/Explorer/resource.rc index 6659290..acfa6e5 100644 --- a/CPP/7zip/UI/Explorer/resource.rc +++ b/CPP/7zip/UI/Explorer/resource.rc @@ -7,4 +7,4 @@ MY_VERSION_INFO_DLL("7-Zip Shell Extension", "7-zip") 1 24 MOVEABLE PURE "7-zip.dll.manifest" #endif -IDI_ICON ICON "..\FileManager\FM.ico" +IDI_ICON ICON "../FileManager/FM.ico" diff --git a/CPP/7zip/UI/FileManager/FSFolder.cpp b/CPP/7zip/UI/FileManager/FSFolder.cpp index 72cb0ce..f603061 100644 --- a/CPP/7zip/UI/FileManager/FSFolder.cpp +++ b/CPP/7zip/UI/FileManager/FSFolder.cpp @@ -5,8 +5,13 @@ #if defined(_MSC_VER) #include #else -// mingw -#include +#if defined(__GNUC__) && (__GNUC__ >= 10) + // new mingw: + #include +#else + // old mingw: + #include +#endif #endif #include "../../../Common/ComTry.h" diff --git a/CPP/7zip/UI/FileManager/FSFolderCopy.cpp b/CPP/7zip/UI/FileManager/FSFolderCopy.cpp index ff444b3..4ca931b 100644 --- a/CPP/7zip/UI/FileManager/FSFolderCopy.cpp +++ b/CPP/7zip/UI/FileManager/FSFolderCopy.cpp @@ -29,6 +29,9 @@ using namespace NFind; extern bool g_IsNT; #endif +#define MY_CAST_FUNC (void(*)()) +// #define MY_CAST_FUNC + namespace NFsFolder { HRESULT CCopyStateIO::MyCopyFile(CFSTR inPath, CFSTR outPath, DWORD attrib) @@ -245,7 +248,9 @@ void CCopyState::Prepare() my_CopyFileExA = NULL; if (!g_IsNT) { - my_CopyFileExA = (Func_CopyFileExA)::GetProcAddress(::GetModuleHandleA("kernel32.dll"), "CopyFileExA"); + my_CopyFileExA = (Func_CopyFileExA) + MY_CAST_FUNC + ::GetProcAddress(::GetModuleHandleA("kernel32.dll"), "CopyFileExA"); } else #endif diff --git a/CPP/7zip/UI/FileManager/MyCom2.h b/CPP/7zip/UI/FileManager/MyCom2.h index c45c215..5fe1ef7 100644 --- a/CPP/7zip/UI/FileManager/MyCom2.h +++ b/CPP/7zip/UI/FileManager/MyCom2.h @@ -7,8 +7,9 @@ #define MY_ADDREF_RELEASE_MT \ STDMETHOD_(ULONG, AddRef)() { InterlockedIncrement((LONG *)&__m_RefCount); return __m_RefCount; } \ -STDMETHOD_(ULONG, Release)() { InterlockedDecrement((LONG *)&__m_RefCount); if (__m_RefCount != 0) \ - return __m_RefCount; delete this; return 0; } +STDMETHOD_(ULONG, Release)() { InterlockedDecrement((LONG *)&__m_RefCount); \ + if (__m_RefCount != 0) return __m_RefCount; \ + delete this; return 0; } #define MY_UNKNOWN_IMP_SPEC_MT2(i1, i) \ MY_QUERYINTERFACE_BEGIN \ diff --git a/CPP/7zip/UI/FileManager/PanelOperations.cpp b/CPP/7zip/UI/FileManager/PanelOperations.cpp index e34e74f..a683b5e 100644 --- a/CPP/7zip/UI/FileManager/PanelOperations.cpp +++ b/CPP/7zip/UI/FileManager/PanelOperations.cpp @@ -24,6 +24,9 @@ using namespace NWindows; using namespace NFile; using namespace NName; +#define MY_CAST_FUNC (void(*)()) +// #define MY_CAST_FUNC + #ifndef _UNICODE extern bool g_IsNT; #endif @@ -96,7 +99,7 @@ HRESULT CThreadFolderOperations::DoOperation(CPanel &panel, const UString &progr } #ifndef _UNICODE -typedef int (WINAPI * SHFileOperationWP)(LPSHFILEOPSTRUCTW lpFileOp); +typedef int (WINAPI * Func_SHFileOperationW)(LPSHFILEOPSTRUCTW lpFileOp); #endif /* @@ -192,9 +195,10 @@ void CPanel::DeleteItems(bool NON_CE_VAR(toRecycleBin)) #ifdef _UNICODE /* res = */ ::SHFileOperationW(&fo); #else - SHFileOperationWP shFileOperationW = (SHFileOperationWP) + Func_SHFileOperationW shFileOperationW = (Func_SHFileOperationW) + MY_CAST_FUNC ::GetProcAddress(::GetModuleHandleW(L"shell32.dll"), "SHFileOperationW"); - if (shFileOperationW == 0) + if (!shFileOperationW) return; /* res = */ shFileOperationW(&fo); #endif diff --git a/CPP/7zip/UI/FileManager/SysIconUtils.cpp b/CPP/7zip/UI/FileManager/SysIconUtils.cpp index b756dfc..d8e0f8b 100644 --- a/CPP/7zip/UI/FileManager/SysIconUtils.cpp +++ b/CPP/7zip/UI/FileManager/SysIconUtils.cpp @@ -12,6 +12,9 @@ #include +#define MY_CAST_FUNC (void(*)()) +// #define MY_CAST_FUNC + #ifndef _UNICODE extern bool g_IsNT; #endif @@ -39,15 +42,16 @@ int GetIconIndexForCSIDL(int csidl) } #ifndef _UNICODE -typedef int (WINAPI * SHGetFileInfoWP)(LPCWSTR pszPath, DWORD attrib, SHFILEINFOW *psfi, UINT cbFileInfo, UINT uFlags); +typedef int (WINAPI * Func_SHGetFileInfoW)(LPCWSTR pszPath, DWORD attrib, SHFILEINFOW *psfi, UINT cbFileInfo, UINT uFlags); static struct CSHGetFileInfoInit { - SHGetFileInfoWP shGetFileInfoW; + Func_SHGetFileInfoW shGetFileInfoW; CSHGetFileInfoInit() { - shGetFileInfoW = (SHGetFileInfoWP) - ::GetProcAddress(::GetModuleHandleW(L"shell32.dll"), "SHGetFileInfoW"); + shGetFileInfoW = (Func_SHGetFileInfoW) + MY_CAST_FUNC + ::GetProcAddress(::GetModuleHandleW(L"shell32.dll"), "SHGetFileInfoW"); } } g_SHGetFileInfoInit; #endif diff --git a/CPP/7zip/UI/FileManager/TextPairs.cpp b/CPP/7zip/UI/FileManager/TextPairs.cpp index 6a989fc..4edf025 100644 --- a/CPP/7zip/UI/FileManager/TextPairs.cpp +++ b/CPP/7zip/UI/FileManager/TextPairs.cpp @@ -104,13 +104,16 @@ void CPairsStorage::Sort() { Pairs.Sort(ComparePairItems, 0); } int CPairsStorage::FindID(const UString &id, int &insertPos) const { - int left = 0, right = Pairs.Size(); + unsigned left = 0, right = Pairs.Size(); while (left != right) { - int mid = (left + right) / 2; - int compResult = ComparePairIDs(id, Pairs[mid].ID); + const unsigned mid = (left + right) / 2; + const int compResult = ComparePairIDs(id, Pairs[mid].ID); if (compResult == 0) + { + insertPos = mid; // to disable GCC warning return mid; + } if (compResult < 0) right = mid; else @@ -129,7 +132,7 @@ int CPairsStorage::FindID(const UString &id) const void CPairsStorage::AddPair(const CTextPair &pair) { int insertPos; - int pos = FindID(pair.ID, insertPos); + const int pos = FindID(pair.ID, insertPos); if (pos >= 0) Pairs[pos] = pair; else @@ -138,7 +141,7 @@ void CPairsStorage::AddPair(const CTextPair &pair) void CPairsStorage::DeletePair(const UString &id) { - int pos = FindID(id); + const int pos = FindID(id); if (pos >= 0) Pairs.Delete(pos); } @@ -146,7 +149,7 @@ void CPairsStorage::DeletePair(const UString &id) bool CPairsStorage::GetValue(const UString &id, UString &value) const { value.Empty(); - int pos = FindID(id); + const int pos = FindID(id); if (pos < 0) return false; value = Pairs[pos].Value; @@ -155,7 +158,7 @@ bool CPairsStorage::GetValue(const UString &id, UString &value) const UString CPairsStorage::GetValue(const UString &id) const { - int pos = FindID(id); + const int pos = FindID(id); if (pos < 0) return UString(); return Pairs[pos].Value; diff --git a/CPP/7zip/UI/GUI/CompressDialog.cpp b/CPP/7zip/UI/GUI/CompressDialog.cpp index 25b9219..b85ae1e 100644 --- a/CPP/7zip/UI/GUI/CompressDialog.cpp +++ b/CPP/7zip/UI/GUI/CompressDialog.cpp @@ -292,6 +292,7 @@ static const CFormatInfo g_Formats[] = "Tar", (1 << 0), METHODS_PAIR(g_TarMethods), + 0 // kFF_Time_Unix | kFF_Time_Win // | kFF_Time_1ns }, { @@ -596,7 +597,6 @@ void CCompressDialog::EnableMultiCombo(unsigned id) } static LRESULT ComboBox_AddStringAscii(NControl::CComboBox &cb, const char *s); -static void FormatOptions_To_String(const NCompression::CFormatOptions &fo, AString &s); static void Combine_Two_BoolPairs(const CBoolPair &b1, const CBoolPair &b2, CBool1 &res) { @@ -607,7 +607,7 @@ static void Combine_Two_BoolPairs(const CBoolPair &b1, const CBoolPair &b2, CBoo } #define SET_GUI_BOOL(name) \ - Combine_Two_BoolPairs(Info. ## name, m_RegistryInfo. ## name, name) + Combine_Two_BoolPairs(Info. name, m_RegistryInfo. name, name) static void Set_Final_BoolPairs( @@ -630,7 +630,7 @@ static void Set_Final_BoolPairs( } #define SET_FINAL_BOOL_PAIRS(name) \ - Set_Final_BoolPairs(name, Info. ## name, m_RegistryInfo. ## name) + Set_Final_BoolPairs(name, Info. name, m_RegistryInfo. name) void CCompressDialog::FormatChanged(bool isChanged) { @@ -2711,7 +2711,7 @@ void CCompressDialog::ShowOptionsString() NCompression::CFormatOptions &fo = Get_FormatOptions(); AString s; - if (fo.TimePrec != -1) + if (fo.IsSet_TimePrec()) { s.Add_OptSpaced("tp"); s.Add_UInt32(fo.TimePrec); diff --git a/CPP/Windows/MemoryLock.cpp b/CPP/Windows/MemoryLock.cpp index fdfbeb9..24866b1 100644 --- a/CPP/Windows/MemoryLock.cpp +++ b/CPP/Windows/MemoryLock.cpp @@ -21,7 +21,7 @@ typedef BOOL (WINAPI * Func_LookupPrivilegeValue)(LPCTSTR lpSystemName, LPCTSTR typedef BOOL (WINAPI * Func_AdjustTokenPrivileges)(HANDLE TokenHandle, BOOL DisableAllPrivileges, PTOKEN_PRIVILEGES NewState, DWORD BufferLength, PTOKEN_PRIVILEGES PreviousState, PDWORD ReturnLength); } -#define GET_PROC_ADDR(fff, name) Func_ ## fff my_ ## fff = (Func_ ## fff)GetProcAddress(hModule, name) +#define GET_PROC_ADDR(fff, name) Func_ ## fff my_ ## fff = (Func_ ## fff) (void(*)()) GetProcAddress(hModule, name) #endif bool EnablePrivilege(LPCTSTR privilegeName, bool enable) diff --git a/CPP/Windows/SecurityUtils.cpp b/CPP/Windows/SecurityUtils.cpp index 8a7f45c..ede83fa 100644 --- a/CPP/Windows/SecurityUtils.cpp +++ b/CPP/Windows/SecurityUtils.cpp @@ -4,6 +4,9 @@ #include "SecurityUtils.h" +#define MY_CAST_FUNC (void(*)()) +// #define MY_CAST_FUNC + namespace NWindows { namespace NSecurity { @@ -50,8 +53,10 @@ static void MyLookupSids(CPolicy &policy, PSID ps) } */ +extern "C" { + #ifndef _UNICODE -typedef BOOL (WINAPI * LookupAccountNameWP)( +typedef BOOL (WINAPI * Func_LookupAccountNameW)( LPCWSTR lpSystemName, LPCWSTR lpAccountName, PSID Sid, @@ -62,13 +67,17 @@ typedef BOOL (WINAPI * LookupAccountNameWP)( ); #endif +} + static PSID GetSid(LPWSTR accountName) { #ifndef _UNICODE HMODULE hModule = GetModuleHandle(TEXT("Advapi32.dll")); if (hModule == NULL) return NULL; - LookupAccountNameWP lookupAccountNameW = (LookupAccountNameWP)GetProcAddress(hModule, "LookupAccountNameW"); + Func_LookupAccountNameW lookupAccountNameW = (Func_LookupAccountNameW) + MY_CAST_FUNC + GetProcAddress(hModule, "LookupAccountNameW"); if (lookupAccountNameW == NULL) return NULL; #endif diff --git a/CPP/Windows/SecurityUtils.h b/CPP/Windows/SecurityUtils.h index 8966dfd..c0d7b12 100644 --- a/CPP/Windows/SecurityUtils.h +++ b/CPP/Windows/SecurityUtils.h @@ -7,6 +7,31 @@ #include "Defs.h" +#ifndef _UNICODE + +extern "C" { +typedef NTSTATUS (NTAPI *Func_LsaOpenPolicy)(PLSA_UNICODE_STRING SystemName, + PLSA_OBJECT_ATTRIBUTES ObjectAttributes, ACCESS_MASK DesiredAccess, PLSA_HANDLE PolicyHandle); +typedef NTSTATUS (NTAPI *Func_LsaClose)(LSA_HANDLE ObjectHandle); +typedef NTSTATUS (NTAPI *Func_LsaAddAccountRights)(LSA_HANDLE PolicyHandle, + PSID AccountSid, PLSA_UNICODE_STRING UserRights, ULONG CountOfRights ); +#define MY_STATUS_NOT_IMPLEMENTED ((NTSTATUS)0xC0000002L) +} + +#define POLICY_FUNC_CALL(fff, str) \ + if (hModule == NULL) return MY_STATUS_NOT_IMPLEMENTED; \ + Func_ ## fff v = (Func_ ## fff) (void(*)()) GetProcAddress(hModule, str); \ + if (!v) return MY_STATUS_NOT_IMPLEMENTED; \ + const NTSTATUS res = v + +#else + +#define POLICY_FUNC_CALL(fff, str) \ + const NTSTATUS res = ::fff + +#endif + + namespace NWindows { namespace NSecurity { @@ -53,15 +78,9 @@ public: }; -#ifndef _UNICODE -typedef NTSTATUS (NTAPI *LsaOpenPolicyP)(PLSA_UNICODE_STRING SystemName, - PLSA_OBJECT_ATTRIBUTES ObjectAttributes, ACCESS_MASK DesiredAccess, PLSA_HANDLE PolicyHandle); -typedef NTSTATUS (NTAPI *LsaCloseP)(LSA_HANDLE ObjectHandle); -typedef NTSTATUS (NTAPI *LsaAddAccountRightsP)(LSA_HANDLE PolicyHandle, - PSID AccountSid, PLSA_UNICODE_STRING UserRights, ULONG CountOfRights ); -#define MY_STATUS_NOT_IMPLEMENTED ((NTSTATUS)0xC0000002L) -#endif + + struct CPolicy { protected: @@ -82,43 +101,17 @@ public: NTSTATUS Open(PLSA_UNICODE_STRING systemName, PLSA_OBJECT_ATTRIBUTES objectAttributes, ACCESS_MASK desiredAccess) { - #ifndef _UNICODE - if (hModule == NULL) - return MY_STATUS_NOT_IMPLEMENTED; - LsaOpenPolicyP lsaOpenPolicy = (LsaOpenPolicyP)GetProcAddress(hModule, "LsaOpenPolicy"); - if (lsaOpenPolicy == NULL) - return MY_STATUS_NOT_IMPLEMENTED; - #endif - Close(); - return - #ifdef _UNICODE - ::LsaOpenPolicy - #else - lsaOpenPolicy - #endif + POLICY_FUNC_CALL (LsaOpenPolicy, "LsaOpenPolicy") (systemName, objectAttributes, desiredAccess, &_handle); + return res; } NTSTATUS Close() { if (_handle == NULL) return 0; - - #ifndef _UNICODE - if (hModule == NULL) - return MY_STATUS_NOT_IMPLEMENTED; - LsaCloseP lsaClose = (LsaCloseP)GetProcAddress(hModule, "LsaClose"); - if (lsaClose == NULL) - return MY_STATUS_NOT_IMPLEMENTED; - #endif - - NTSTATUS res = - #ifdef _UNICODE - ::LsaClose - #else - lsaClose - #endif + POLICY_FUNC_CALL (LsaClose, "LsaClose") (_handle); _handle = NULL; return res; @@ -137,21 +130,9 @@ public: NTSTATUS AddAccountRights(PSID accountSid, PLSA_UNICODE_STRING userRights, ULONG countOfRights) { - #ifndef _UNICODE - if (hModule == NULL) - return MY_STATUS_NOT_IMPLEMENTED; - LsaAddAccountRightsP lsaAddAccountRights = (LsaAddAccountRightsP)GetProcAddress(hModule, "LsaAddAccountRights"); - if (lsaAddAccountRights == NULL) - return MY_STATUS_NOT_IMPLEMENTED; - #endif - - return - #ifdef _UNICODE - ::LsaAddAccountRights - #else - lsaAddAccountRights - #endif + POLICY_FUNC_CALL (LsaAddAccountRights, "LsaAddAccountRights") (_handle, accountSid, userRights, countOfRights); + return res; } NTSTATUS AddAccountRights(PSID accountSid, PLSA_UNICODE_STRING userRights) { return AddAccountRights(accountSid, userRights, 1); } diff --git a/CPP/Windows/Shell.cpp b/CPP/Windows/Shell.cpp index d0f9032..071833c 100644 --- a/CPP/Windows/Shell.cpp +++ b/CPP/Windows/Shell.cpp @@ -258,14 +258,21 @@ bool BrowseForFolder(HWND owner, LPCTSTR title, #ifndef _UNICODE -typedef BOOL (WINAPI * SHGetPathFromIDListWP)(LPCITEMIDLIST pidl, LPWSTR pszPath); +extern "C" { +typedef BOOL (WINAPI * Func_SHGetPathFromIDListW)(LPCITEMIDLIST pidl, LPWSTR pszPath); +typedef LPITEMIDLIST (WINAPI * Func_SHBrowseForFolderW)(LPBROWSEINFOW lpbi); +} + +#define MY_CAST_FUNC (void(*)()) +// #define MY_CAST_FUNC bool GetPathFromIDList(LPCITEMIDLIST itemIDList, UString &path) { path.Empty(); - SHGetPathFromIDListWP shGetPathFromIDListW = (SHGetPathFromIDListWP) + Func_SHGetPathFromIDListW shGetPathFromIDListW = (Func_SHGetPathFromIDListW) + MY_CAST_FUNC ::GetProcAddress(::GetModuleHandleW(L"shell32.dll"), "SHGetPathFromIDListW"); - if (shGetPathFromIDListW == 0) + if (!shGetPathFromIDListW) return false; const unsigned len = MAX_PATH * 2; bool result = BOOLToBool(shGetPathFromIDListW(itemIDList, path.GetBuf(len))); @@ -273,14 +280,14 @@ bool GetPathFromIDList(LPCITEMIDLIST itemIDList, UString &path) return result; } -typedef LPITEMIDLIST (WINAPI * SHBrowseForFolderWP)(LPBROWSEINFOW lpbi); static bool BrowseForFolder(LPBROWSEINFOW browseInfo, UString &resultPath) { NWindows::NCOM::CComInitializer comInitializer; - SHBrowseForFolderWP shBrowseForFolderW = (SHBrowseForFolderWP) + Func_SHBrowseForFolderW shBrowseForFolderW = (Func_SHBrowseForFolderW) + MY_CAST_FUNC ::GetProcAddress(::GetModuleHandleW(L"shell32.dll"), "SHBrowseForFolderW"); - if (shBrowseForFolderW == 0) + if (!shBrowseForFolderW) return false; LPITEMIDLIST itemIDList = shBrowseForFolderW(browseInfo); if (itemIDList == NULL) -- cgit v1.2.3-55-g6feb