From bed9cb93bfecfe3838587576c01a1e961e689228 Mon Sep 17 00:00:00 2001 From: iCrazeiOS <39101269+iCrazeiOS@users.noreply.github.com> Date: Mon, 5 Oct 2026 11:52:16 +0100 Subject: [PATCH 1/6] feat: LZMA support --- MacPacker/Info.plist | 34 +++++++++++++++++++++++ MacPacker/Info_Store.plist | 34 +++++++++++++++++++++++ Modules/Sources/Core/Formats/Catalog.json | 19 +++++++++++++ README.md | 4 +-- 4 files changed, 89 insertions(+), 2 deletions(-) diff --git a/MacPacker/Info.plist b/MacPacker/Info.plist index 32b6f573..1f904ee4 100644 --- a/MacPacker/Info.plist +++ b/MacPacker/Info.plist @@ -205,6 +205,40 @@ LSTypeIsPackage + + CFBundleTypeExtensions + + lzma + + CFBundleTypeName + LZMA Archive + CFBundleTypeRole + Viewer + LSHandlerRank + Default + LSItemContentTypes + + org.tukaani.lzma-archive + + LSTypeIsPackage + + + + CFBundleTypeExtensions + + tar.lzma + + CFBundleTypeName + LZMA Tarball Archive + CFBundleTypeRole + Viewer + LSHandlerRank + Default + LSItemContentTypes + + LSTypeIsPackage + + CFBundleTypeExtensions diff --git a/MacPacker/Info_Store.plist b/MacPacker/Info_Store.plist index fbbd42b6..f4daa445 100644 --- a/MacPacker/Info_Store.plist +++ b/MacPacker/Info_Store.plist @@ -205,6 +205,40 @@ LSTypeIsPackage + + CFBundleTypeExtensions + + lzma + + CFBundleTypeName + LZMA Archive + CFBundleTypeRole + Viewer + LSHandlerRank + Default + LSItemContentTypes + + org.tukaani.lzma-archive + + LSTypeIsPackage + + + + CFBundleTypeExtensions + + tar.lzma + + CFBundleTypeName + LZMA Tarball Archive + CFBundleTypeRole + Viewer + LSHandlerRank + Default + LSItemContentTypes + + LSTypeIsPackage + + CFBundleTypeExtensions diff --git a/Modules/Sources/Core/Formats/Catalog.json b/Modules/Sources/Core/Formats/Catalog.json index a0e54b46..c91c6845 100644 --- a/Modules/Sources/Core/Formats/Catalog.json +++ b/Modules/Sources/Core/Formats/Catalog.json @@ -202,6 +202,18 @@ { "id": "swc", "capabilities": ["listContents", "extractFiles"], "default": true } ] }, + { + "id": "lzma", + "name": "LZMA File", + "kind": "compression", + "uti": ["org.tukaani.lzma-archive"], + "extensions": ["lzma"], + "mime": ["application/x-lzma"], + "rules": [], + "engines": [ + { "id": "7zip", "capabilities": ["listContents", "extractFiles"], "default": true } + ] + }, { "id": "lzx", "name": "LZX Archive", @@ -571,6 +583,13 @@ "extensions": ["tlz4","tar.lz4"], "components": ["tar","lz4"] }, + { + "id": "tar.lzma", + "name": "LZMA Tar Archive", + "uti": [], + "extensions": ["tar.lzma"], + "components": ["tar","lzma"] + }, { "id": "tar.xz", "name": "XZ Tar Archive", diff --git a/README.md b/README.md index bb368542..c457f70d 100644 --- a/README.md +++ b/README.md @@ -55,8 +55,8 @@ MacPacker reads and extracts 40+ formats across archives, disk images, and compr | --- | --- | | **Archives** | 7z · ar · arj · cab · chm · cpio · deb · exe · lha · lzh · lzx · msi · pkg · rar · rpm · sea · sit · sitx · tar · xar · zip · zipx | | **Disk images** | dmg · fat · iso · ntfs · qcow2 · squashfs · vdi · vhd · vhdx · vmdk · wim | -| **Compression** | bz2 · gz · lz4 · xz · z | -| **Tarballs** | tar.gz (tgz) · tar.bz2 (tbz2) · tar.xz (txz) · tar.lz4 · tar.z (taz) | +| **Compression** | bz2 · gz · lz4 · lzma · xz · z | +| **Tarballs** | tar.gz (tgz) · tar.bz2 (tbz2) · tar.lzma · tar.xz (txz) · tar.lz4 · tar.z (taz) | See the [full format reference and per-format guides](https://macpacker.app/en/docs) on the website. From 4ab9951639e0d20de5c74b971d7d158cc527b68e Mon Sep 17 00:00:00 2001 From: iCrazeiOS <39101269+iCrazeiOS@users.noreply.github.com> Date: Mon, 5 Oct 2026 11:53:02 +0100 Subject: [PATCH 2/6] fix: deb files no longer only show "unknown" file entry --- Modules/Sources/CSevenZip/sevenzip_bridge.cpp | 61 ++++++++++--------- 1 file changed, 33 insertions(+), 28 deletions(-) diff --git a/Modules/Sources/CSevenZip/sevenzip_bridge.cpp b/Modules/Sources/CSevenZip/sevenzip_bridge.cpp index 92e18a4d..11de2402 100644 --- a/Modules/Sources/CSevenZip/sevenzip_bridge.cpp +++ b/Modules/Sources/CSevenZip/sevenzip_bridge.cpp @@ -1163,37 +1163,42 @@ SZArchiveRef sz_open(const char *path, const char *password, for (int depth = 0; depth < kMaxNestingDepth; depth++) { IInArchive *currentArc = handle->levels.back().archive; - // Check if this archive signals a nested container - NWindows::NCOM::CPropVariant prop; - currentArc->GetArchiveProperty(kpidMainSubfile, &prop); - if (prop.vt != VT_UI4) - break; - UInt32 mainSubfile = prop.ulVal; - - // Validate index - UInt32 itemCount = 0; - currentArc->GetNumberOfItems(&itemCount); - if (mainSubfile >= itemCount) - break; + // The stream 7-Zip names through kpidMainSubfile. + CMyComPtr subStream; - // Get IInArchiveGetStream from current archive - CMyComPtr getStream; - if (currentArc->QueryInterface( - IID_IInArchiveGetStream_Local, - (void **)&getStream) != S_OK || !getStream) - break; + // Do not drill into a deb: its payload is a tar under a compression + // wrapper whose level has no usable kpidPath, which would render a + // lone entry named "unknown" instead of the deb's members. + NWindows::NCOM::CPropVariant ownExt; + currentArc->GetArchiveProperty(kpidExtension, &ownExt); + const bool isDeb = ownExt.vt == VT_BSTR && ownExt.bstrVal + && wcscmp(ownExt.bstrVal, L"deb") == 0; - // Extract the sub-stream - CMyComPtr subSeqStream; - if (getStream->GetStream(mainSubfile, &subSeqStream) != S_OK - || !subSeqStream) - break; + NWindows::NCOM::CPropVariant prop; + currentArc->GetArchiveProperty(kpidMainSubfile, &prop); + if (!isDeb && prop.vt == VT_UI4) { + UInt32 mainSubfile = prop.ulVal; + + UInt32 itemCount = 0; + currentArc->GetNumberOfItems(&itemCount); + if (mainSubfile < itemCount) { + CMyComPtr getStream; + if (currentArc->QueryInterface( + IID_IInArchiveGetStream_Local, + (void **)&getStream) == S_OK && getStream) { + CMyComPtr subSeqStream; + if (getStream->GetStream(mainSubfile, &subSeqStream) == S_OK + && subSeqStream) { + CMyComPtr in; + if (subSeqStream->QueryInterface( + IID_IInStream_Local, (void **)&in) == S_OK && in) + subStream = in; + } + } + } + } - // Need seekable IInStream for archive opening - CMyComPtr subStream; - if (subSeqStream->QueryInterface( - IID_IInStream_Local, - (void **)&subStream) != S_OK || !subStream) + if (!subStream) break; // Try to open the sub-stream as a new archive, with the password: a 7z From 3ab1dc45d43ac2f273966f94e5235dd827fd5c78 Mon Sep 17 00:00:00 2001 From: iCrazeiOS <39101269+iCrazeiOS@users.noreply.github.com> Date: Wed, 14 Oct 2026 09:51:06 +0100 Subject: [PATCH 3/6] fix: add changelog entries for deb contents and LZMA support --- Config/products/macpacker.json | 48 ++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/Config/products/macpacker.json b/Config/products/macpacker.json index 0620e343..549e80dd 100644 --- a/Config/products/macpacker.json +++ b/Config/products/macpacker.json @@ -88,6 +88,30 @@ "132" ] }, + { + "type": "feat", + "title": { + "en": "Open and extract LZMA files", + "zh-Hans": "打开并解压 LZMA 文件", + "fr": "Ouvrir et extraire les fichiers LZMA", + "de": "LZMA-Dateien öffnen und entpacken", + "it": "Aprire ed estrarre i file LZMA", + "ja": "LZMA ファイルを開いて展開する", + "fa": "باز کردن و استخراج فایل‌های LZMA", + "pl": "Otwieranie i wypakowywanie plików LZMA", + "pt-BR": "Abrir e extrair arquivos LZMA", + "ru": "Открытие и извлечение файлов LZMA", + "uk": "Відкриття та розпакування файлів LZMA", + "es-MX": "Abrir y extraer archivos LZMA", + "ko": "LZMA 파일 열기 및 압축 해제", + "nl": "LZMA-bestanden openen en uitpakken", + "tr": "LZMA dosyalarını açma ve çıkarma", + "vi": "Mở và giải nén tệp LZMA" + }, + "issues": [ + "340" + ] + }, { "type": "fix", "highlight": true, @@ -187,6 +211,30 @@ "275" ] }, + { + "type": "fix", + "title": { + "en": "Deb files list their contents correctly", + "zh-Hans": "deb 文件正确显示内容", + "fr": "Les fichiers deb affichent correctement leur contenu", + "de": "Deb-Dateien listen ihren Inhalt korrekt auf", + "it": "I file deb mostrano correttamente il contenuto", + "ja": "deb ファイルの内容を正しく表示", + "fa": "نمایش صحیح محتوای فایل‌های deb", + "pl": "Pliki deb pokazują poprawnie zawartość", + "pt-BR": "Arquivos deb listam corretamente seu conteúdo", + "ru": "Deb-файлы корректно показывают содержимое", + "uk": "Deb-файли коректно показують вміст", + "es-MX": "Los archivos deb muestran correctamente su contenido", + "ko": "deb 파일 내용을 올바르게 표시", + "nl": "Deb-bestanden tonen hun inhoud correct", + "tr": "Deb dosyaları içeriğini doğru gösteriyor", + "vi": "Tệp deb hiển thị đúng nội dung" + }, + "issues": [ + "340" + ] + }, { "type": "core", "title": { From fdad125feaa13e8b53678e6016b28d2aa9e6de53 Mon Sep 17 00:00:00 2001 From: iCrazeiOS <39101269+iCrazeiOS@users.noreply.github.com> Date: Wed, 14 Oct 2026 12:11:31 +0100 Subject: [PATCH 4/6] add lzma UTType --- MacPacker/Info.plist | 4 +++- MacPacker/Info_Store.plist | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/MacPacker/Info.plist b/MacPacker/Info.plist index 1f904ee4..8672900b 100644 --- a/MacPacker/Info.plist +++ b/MacPacker/Info.plist @@ -235,7 +235,9 @@ LSHandlerRank Default LSItemContentTypes - + + org.tukaani.tar-lzma-archive + LSTypeIsPackage diff --git a/MacPacker/Info_Store.plist b/MacPacker/Info_Store.plist index f4daa445..caacdcd4 100644 --- a/MacPacker/Info_Store.plist +++ b/MacPacker/Info_Store.plist @@ -235,7 +235,9 @@ LSHandlerRank Default LSItemContentTypes - + + org.tukaani.tar-lzma-archive + LSTypeIsPackage From 180e8385d3fb996c8b3b51aa4d6b70c0e6f7c8ee Mon Sep 17 00:00:00 2001 From: iCrazeiOS <39101269+iCrazeiOS@users.noreply.github.com> Date: Wed, 14 Oct 2026 12:30:56 +0100 Subject: [PATCH 5/6] add docstring as requested by coderabbit --- Modules/Sources/CSevenZip/sevenzip_bridge.cpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/Modules/Sources/CSevenZip/sevenzip_bridge.cpp b/Modules/Sources/CSevenZip/sevenzip_bridge.cpp index 36472dd4..a423e015 100644 --- a/Modules/Sources/CSevenZip/sevenzip_bridge.cpp +++ b/Modules/Sources/CSevenZip/sevenzip_bridge.cpp @@ -1100,6 +1100,24 @@ static void sz_indexAppleDoubleSidecars(SZArchiveHandle *handle) { } } +/// Open an archive at the given filesystem path. +/// +/// Tries each registered 7-Zip handler on the file, then drills into nested +/// containers (disk images containing filesystems) up to a fixed depth via +/// the `kpidMainSubfile` stream. A `deb` level is not drilled into: its +/// payload is a tar under a compression wrapper with no usable entry paths, +/// which would otherwise list as a lone entry named "unknown" instead of the +/// deb's members. +/// +/// @param path Filesystem path of the archive (UTF-8). +/// @param password Password for reading encrypted headers (7z `-mhe=on`, +/// RAR `-hp`), or NULL. Also pre-sets the extraction password. +/// @param needs_password_out If non-NULL, set to true when a handler asked +/// for a password during the open. Meaningful only on failure: it tells the +/// caller to prompt and retry rather than report an unsupported file. +/// @param error_out If non-NULL, set to a malloc'd UTF-8 error string on +/// failure; caller must free() it. +/// @return Opaque archive handle on success, NULL on failure. SZArchiveRef sz_open(const char *path, const char *password, bool *needs_password_out, char **error_out) { if (needs_password_out) *needs_password_out = false; From 5d3855b613dcb97e795e58d17846563299744fd0 Mon Sep 17 00:00:00 2001 From: Stephan Arenswald Date: Wed, 21 Oct 2026 14:48:01 +0200 Subject: [PATCH 6/6] fix: tests, tlzma and Finder types for LZMA, 1.2.0 changelog (#340) - Bridge: main's nesting loop again, with an early break for a deb. - Tests: a deb as dpkg-deb writes it lists its members, not "unknown"; tar.lzma and tlzma open as tar. Fixtures from MacPacker-TestArchives#15: a dpkg-deb deb, and the lzma tarballs as real LZMA (they were xz). - tlzma is recognised, like tgz beside tar.gz. - Finder and Quick Look: import org.tukaani.lzma-archive and org.tukaani.tar-lzma-archive. macOS declares neither, so .lzma had no app on a clean Mac. The tar.lzma document type that claimed an undeclared type is gone. - Changelog: both items move from the released 1.1.0 and 1.0.0 blocks to a new 1.2.0 block, in all 21 languages. --- Config/products/macpacker.json | 112 ++++++++++-------- MacPacker/Info.plist | 41 +++++++ MacPacker/Info_Store.plist | 41 +++++++ Modules/Sources/CSevenZip/sevenzip_bridge.cpp | 58 ++++----- Modules/Sources/Core/Formats/Catalog.json | 4 +- .../Tests/CoreTests/DefaultArchiveTests.swift | 23 ++++ Modules/Tests/CoreTests/TestArchives | 2 +- QuickLookExtension/Info.plist | 1 + README.md | 2 +- 9 files changed, 205 insertions(+), 79 deletions(-) diff --git a/Config/products/macpacker.json b/Config/products/macpacker.json index 36e58ce0..774e8bf5 100644 --- a/Config/products/macpacker.json +++ b/Config/products/macpacker.json @@ -35,6 +35,70 @@ "tr": "Bütünlük kontrolü ve kurtarma" }, "versions": [ + { + "version": "1.2.0", + "items": [ + { + "type": "feat", + "highlight": true, + "title": { + "en": "Open and extract LZMA files", + "zh-Hans": "打开并解压 LZMA 文件", + "fr": "Ouvrir et extraire les fichiers LZMA", + "de": "LZMA-Dateien öffnen und entpacken", + "it": "Aprire ed estrarre i file LZMA", + "ja": "LZMA ファイルを開いて展開", + "fa": "باز کردن و استخراج فایل‌های LZMA", + "pl": "Otwieranie i wypakowywanie plików LZMA", + "pt-BR": "Abrir e extrair arquivos LZMA", + "ru": "Открытие и извлечение файлов LZMA", + "uk": "Відкриття та розпакування файлів LZMA", + "es-MX": "Abrir y extraer archivos LZMA", + "ko": "LZMA 파일 열기 및 압축 해제", + "nl": "LZMA-bestanden openen en uitpakken", + "tr": "LZMA dosyalarını açma ve çıkarma", + "vi": "Mở và giải nén tệp LZMA", + "ar": "فتح ملفات LZMA واستخراجها", + "ca": "Obre i extreu fitxers LZMA", + "el": "Άνοιγμα και εξαγωγή αρχείων LZMA", + "nb": "Åpne og pakk ut LZMA-filer", + "zh-TW": "開啟並解壓縮 LZMA 檔案" + }, + "issues": [ + "340" + ] + }, + { + "type": "fix", + "title": { + "en": "Deb files open as one “unknown” file", + "zh-Hans": "deb 文件打开后只有一个“unknown”文件", + "fr": "Les fichiers deb s’ouvrent en un seul fichier « unknown »", + "de": "Deb-Dateien öffnen sich als eine Datei „unknown“", + "it": "I file deb si aprono come un unico file «unknown»", + "ja": "deb ファイルを開くと「unknown」だけが表示される", + "fa": "فایل‌های deb فقط به‌صورت یک فایل «unknown» باز می‌شوند", + "pl": "Pliki deb otwierają się jako jeden plik „unknown”", + "pt-BR": "Arquivos deb abrem como um único arquivo “unknown”", + "ru": "Deb-файлы открываются как один файл «unknown»", + "uk": "Deb-файли відкриваються як один файл «unknown»", + "es-MX": "Los archivos deb se abren como un solo archivo «unknown»", + "ko": "deb 파일이 “unknown” 파일 하나로 열림", + "nl": "Deb-bestanden openen als één bestand “unknown”", + "tr": "Deb dosyaları tek bir “unknown” dosyası olarak açılıyor", + "vi": "Tệp deb mở ra chỉ với một tệp “unknown”", + "ar": "ملفات deb تُفتح كملف واحد باسم «unknown»", + "ca": "Els fitxers deb s’obren com un sol fitxer «unknown»", + "el": "Τα αρχεία deb ανοίγουν ως ένα μόνο αρχείο «unknown»", + "nb": "Deb-filer åpnes som én fil kalt «unknown»", + "zh-TW": "deb 檔案開啟後只有一個「unknown」檔案" + }, + "issues": [ + "340" + ] + } + ] + }, { "version": "1.1.0", "items": [ @@ -98,30 +162,6 @@ "132" ] }, - { - "type": "feat", - "title": { - "en": "Open and extract LZMA files", - "zh-Hans": "打开并解压 LZMA 文件", - "fr": "Ouvrir et extraire les fichiers LZMA", - "de": "LZMA-Dateien öffnen und entpacken", - "it": "Aprire ed estrarre i file LZMA", - "ja": "LZMA ファイルを開いて展開する", - "fa": "باز کردن و استخراج فایل‌های LZMA", - "pl": "Otwieranie i wypakowywanie plików LZMA", - "pt-BR": "Abrir e extrair arquivos LZMA", - "ru": "Открытие и извлечение файлов LZMA", - "uk": "Відкриття та розпакування файлів LZMA", - "es-MX": "Abrir y extraer archivos LZMA", - "ko": "LZMA 파일 열기 및 압축 해제", - "nl": "LZMA-bestanden openen en uitpakken", - "tr": "LZMA dosyalarını açma ve çıkarma", - "vi": "Mở và giải nén tệp LZMA" - }, - "issues": [ - "340" - ] - }, { "type": "fix", "highlight": true, @@ -242,30 +282,6 @@ "275" ] }, - { - "type": "fix", - "title": { - "en": "Deb files list their contents correctly", - "zh-Hans": "deb 文件正确显示内容", - "fr": "Les fichiers deb affichent correctement leur contenu", - "de": "Deb-Dateien listen ihren Inhalt korrekt auf", - "it": "I file deb mostrano correttamente il contenuto", - "ja": "deb ファイルの内容を正しく表示", - "fa": "نمایش صحیح محتوای فایل‌های deb", - "pl": "Pliki deb pokazują poprawnie zawartość", - "pt-BR": "Arquivos deb listam corretamente seu conteúdo", - "ru": "Deb-файлы корректно показывают содержимое", - "uk": "Deb-файли коректно показують вміст", - "es-MX": "Los archivos deb muestran correctamente su contenido", - "ko": "deb 파일 내용을 올바르게 표시", - "nl": "Deb-bestanden tonen hun inhoud correct", - "tr": "Deb dosyaları içeriğini doğru gösteriyor", - "vi": "Tệp deb hiển thị đúng nội dung" - }, - "issues": [ - "340" - ] - }, { "type": "fix", "title": { diff --git a/MacPacker/Info.plist b/MacPacker/Info.plist index ea64840f..95a63597 100644 --- a/MacPacker/Info.plist +++ b/MacPacker/Info.plist @@ -226,6 +226,7 @@ CFBundleTypeExtensions + tlzma tar.lzma CFBundleTypeName @@ -1096,6 +1097,46 @@ + + UTTypeConformsTo + + public.archive + public.data + + UTTypeDescription + LZMA File + UTTypeIcons + + UTTypeIdentifier + org.tukaani.lzma-archive + UTTypeTagSpecification + + public.filename-extension + + lzma + + + + + UTTypeConformsTo + + public.archive + public.data + + UTTypeDescription + LZMA Tar Archive + UTTypeIcons + + UTTypeIdentifier + org.tukaani.tar-lzma-archive + UTTypeTagSpecification + + public.filename-extension + + tlzma + + + ITSAppUsesNonExemptEncryption diff --git a/MacPacker/Info_Store.plist b/MacPacker/Info_Store.plist index 761be9dc..2e708e6b 100644 --- a/MacPacker/Info_Store.plist +++ b/MacPacker/Info_Store.plist @@ -226,6 +226,7 @@ CFBundleTypeExtensions + tlzma tar.lzma CFBundleTypeName @@ -1090,6 +1091,46 @@ + + UTTypeConformsTo + + public.archive + public.data + + UTTypeDescription + LZMA File + UTTypeIcons + + UTTypeIdentifier + org.tukaani.lzma-archive + UTTypeTagSpecification + + public.filename-extension + + lzma + + + + + UTTypeConformsTo + + public.archive + public.data + + UTTypeDescription + LZMA Tar Archive + UTTypeIcons + + UTTypeIdentifier + org.tukaani.tar-lzma-archive + UTTypeTagSpecification + + public.filename-extension + + tlzma + + + ITSAppUsesNonExemptEncryption diff --git a/Modules/Sources/CSevenZip/sevenzip_bridge.cpp b/Modules/Sources/CSevenZip/sevenzip_bridge.cpp index 80f4fc9b..7e324ff8 100644 --- a/Modules/Sources/CSevenZip/sevenzip_bridge.cpp +++ b/Modules/Sources/CSevenZip/sevenzip_bridge.cpp @@ -1214,42 +1214,46 @@ SZArchiveRef sz_open(const char *path, const char *password, for (int depth = 0; depth < kMaxNestingDepth; depth++) { IInArchive *currentArc = handle->levels.back().archive; - // The stream 7-Zip names through kpidMainSubfile. - CMyComPtr subStream; - // Do not drill into a deb: its payload is a tar under a compression // wrapper whose level has no usable kpidPath, which would render a // lone entry named "unknown" instead of the deb's members. NWindows::NCOM::CPropVariant ownExt; currentArc->GetArchiveProperty(kpidExtension, &ownExt); - const bool isDeb = ownExt.vt == VT_BSTR && ownExt.bstrVal - && wcscmp(ownExt.bstrVal, L"deb") == 0; + if (ownExt.vt == VT_BSTR && ownExt.bstrVal + && wcscmp(ownExt.bstrVal, L"deb") == 0) + break; + // Check if this archive signals a nested container NWindows::NCOM::CPropVariant prop; currentArc->GetArchiveProperty(kpidMainSubfile, &prop); - if (!isDeb && prop.vt == VT_UI4) { - UInt32 mainSubfile = prop.ulVal; - - UInt32 itemCount = 0; - currentArc->GetNumberOfItems(&itemCount); - if (mainSubfile < itemCount) { - CMyComPtr getStream; - if (currentArc->QueryInterface( - IID_IInArchiveGetStream_Local, - (void **)&getStream) == S_OK && getStream) { - CMyComPtr subSeqStream; - if (getStream->GetStream(mainSubfile, &subSeqStream) == S_OK - && subSeqStream) { - CMyComPtr in; - if (subSeqStream->QueryInterface( - IID_IInStream_Local, (void **)&in) == S_OK && in) - subStream = in; - } - } - } - } + if (prop.vt != VT_UI4) + break; + UInt32 mainSubfile = prop.ulVal; - if (!subStream) + // Validate index + UInt32 itemCount = 0; + currentArc->GetNumberOfItems(&itemCount); + if (mainSubfile >= itemCount) + break; + + // Get IInArchiveGetStream from current archive + CMyComPtr getStream; + if (currentArc->QueryInterface( + IID_IInArchiveGetStream_Local, + (void **)&getStream) != S_OK || !getStream) + break; + + // Extract the sub-stream + CMyComPtr subSeqStream; + if (getStream->GetStream(mainSubfile, &subSeqStream) != S_OK + || !subSeqStream) + break; + + // Need seekable IInStream for archive opening + CMyComPtr subStream; + if (subSeqStream->QueryInterface( + IID_IInStream_Local, + (void **)&subStream) != S_OK || !subStream) break; // Try to open the sub-stream as a new archive, with the password: a 7z diff --git a/Modules/Sources/Core/Formats/Catalog.json b/Modules/Sources/Core/Formats/Catalog.json index a9bb6191..55c61e36 100644 --- a/Modules/Sources/Core/Formats/Catalog.json +++ b/Modules/Sources/Core/Formats/Catalog.json @@ -586,8 +586,8 @@ { "id": "tar.lzma", "name": "LZMA Tar Archive", - "uti": [], - "extensions": ["tar.lzma"], + "uti": ["org.tukaani.tar-lzma-archive"], + "extensions": ["tlzma", "tar.lzma"], "components": ["tar","lzma"] }, { diff --git a/Modules/Tests/CoreTests/DefaultArchiveTests.swift b/Modules/Tests/CoreTests/DefaultArchiveTests.swift index e2dd99c0..9edf1a80 100644 --- a/Modules/Tests/CoreTests/DefaultArchiveTests.swift +++ b/Modules/Tests/CoreTests/DefaultArchiveTests.swift @@ -68,11 +68,13 @@ extension AllCoreTests { // compounds ("tar.bz2", "tar", 5, 2), ("tar.gz", "tar", 5, 2), + ("tar.lzma", "tar", 5, 2), ("tar.xz", "tar", 5, 2), ("tar.Z", "tar", 5, 2), // comounds with one ending ("tbz2", "tar", 5, 2), ("tgz", "tar", 5, 2), + ("tlzma", "tar", 5, 2), ("txz", "tar", 5, 2), ("taz", "tar", 5, 2) ]) @@ -97,6 +99,27 @@ extension AllCoreTests { #expect(state.root === state.selectedItem) } + /// A deb lists its members, not a lone "unknown". dpkg-deb names the + /// first member `debian-binary`, and 7-Zip then offers the compressed + /// `data.tar.*` as the main subfile, whose one nameless stream was all + /// that showed. fpm names it `debian-binary/`, which 7-Zip reads as a + /// plain ar, so that deb always listed its members. + @Test(arguments: [ + ("defaultarchive-dpkg.deb", ["control.tar.xz", "data.tar.xz"]), + ("defaultarchive.deb", ["control.tar.gz", "data.tar.gz", "debian-binary"]) + ]) + func debListsItsMembers(arg: (String, [String])) async throws { + let state = ArchiveState(catalog: ArchiveTypeCatalog(), engineSelector: ArchiveEngineSelector7zip()) + let url = Bundle.module.url(forResource: "defaultArchives", withExtension: nil)! + .appendingPathComponent(arg.0) + + state.open(url: url) + try await state.openTask?.value + + let names = state.root?.children?.compactMap { state.entries[$0]?.name }.sorted() + #expect(names == arg.1) + } + @Test("Test all defaultArchives on xad", arguments: [ ("zip", "zip"), ("7z", "7zip"), diff --git a/Modules/Tests/CoreTests/TestArchives b/Modules/Tests/CoreTests/TestArchives index a4f5a291..00abea7c 160000 --- a/Modules/Tests/CoreTests/TestArchives +++ b/Modules/Tests/CoreTests/TestArchives @@ -1 +1 @@ -Subproject commit a4f5a291276cb1257f3f918971d8a9c2d5c586c3 +Subproject commit 00abea7ccff3411420ed05ebe2bafd096e780160 diff --git a/QuickLookExtension/Info.plist b/QuickLookExtension/Info.plist index 50a7d6a7..5b4853e2 100644 --- a/QuickLookExtension/Info.plist +++ b/QuickLookExtension/Info.plist @@ -35,6 +35,7 @@ org.gnu.gnu-zip-archive org.gnu.gnu-zip-tar-archive org.tukaani.lzma-archive + org.tukaani.tar-lzma-archive org.tukaani.tar-xz-archive org.tukaani.xz-archive public.archive diff --git a/README.md b/README.md index c457f70d..e10fa0fc 100644 --- a/README.md +++ b/README.md @@ -56,7 +56,7 @@ MacPacker reads and extracts 40+ formats across archives, disk images, and compr | **Archives** | 7z · ar · arj · cab · chm · cpio · deb · exe · lha · lzh · lzx · msi · pkg · rar · rpm · sea · sit · sitx · tar · xar · zip · zipx | | **Disk images** | dmg · fat · iso · ntfs · qcow2 · squashfs · vdi · vhd · vhdx · vmdk · wim | | **Compression** | bz2 · gz · lz4 · lzma · xz · z | -| **Tarballs** | tar.gz (tgz) · tar.bz2 (tbz2) · tar.lzma · tar.xz (txz) · tar.lz4 · tar.z (taz) | +| **Tarballs** | tar.gz (tgz) · tar.bz2 (tbz2) · tar.lzma (tlzma) · tar.xz (txz) · tar.lz4 · tar.z (taz) | See the [full format reference and per-format guides](https://macpacker.app/en/docs) on the website.