Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 64 additions & 0 deletions Config/products/macpacker.json
Original file line number Diff line number Diff line change
Expand Up @@ -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": [
Expand Down
77 changes: 77 additions & 0 deletions MacPacker/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,43 @@
<key>LSTypeIsPackage</key>
<false/>
</dict>
<dict>
<key>CFBundleTypeExtensions</key>
<array>
<string>lzma</string>
</array>
<key>CFBundleTypeName</key>
<string>LZMA Archive</string>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
<key>LSHandlerRank</key>
<string>Default</string>
<key>LSItemContentTypes</key>
<array>
<string>org.tukaani.lzma-archive</string>
</array>
<key>LSTypeIsPackage</key>
<false/>
</dict>
<dict>
<key>CFBundleTypeExtensions</key>
<array>
<string>tlzma</string>
<string>tar.lzma</string>
</array>
<key>CFBundleTypeName</key>
<string>LZMA Tarball Archive</string>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
<key>LSHandlerRank</key>
<string>Default</string>
<key>LSItemContentTypes</key>
<array>
<string>org.tukaani.tar-lzma-archive</string>
</array>
<key>LSTypeIsPackage</key>
<false/>
</dict>
<dict>
<key>CFBundleTypeExtensions</key>
<array>
Expand Down Expand Up @@ -1060,6 +1097,46 @@
</array>
</dict>
</dict>
<dict>
<key>UTTypeConformsTo</key>
<array>
<string>public.archive</string>
<string>public.data</string>
</array>
<key>UTTypeDescription</key>
<string>LZMA File</string>
<key>UTTypeIcons</key>
<dict/>
<key>UTTypeIdentifier</key>
<string>org.tukaani.lzma-archive</string>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array>
<string>lzma</string>
</array>
</dict>
</dict>
<dict>
<key>UTTypeConformsTo</key>
<array>
<string>public.archive</string>
<string>public.data</string>
</array>
<key>UTTypeDescription</key>
<string>LZMA Tar Archive</string>
<key>UTTypeIcons</key>
<dict/>
<key>UTTypeIdentifier</key>
<string>org.tukaani.tar-lzma-archive</string>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array>
<string>tlzma</string>
</array>
</dict>
</dict>
</array>
<key>ITSAppUsesNonExemptEncryption</key>
<true/>
Expand Down
77 changes: 77 additions & 0 deletions MacPacker/Info_Store.plist
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,43 @@
<key>LSTypeIsPackage</key>
<false/>
</dict>
<dict>
<key>CFBundleTypeExtensions</key>
<array>
<string>lzma</string>
</array>
<key>CFBundleTypeName</key>
<string>LZMA Archive</string>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
<key>LSHandlerRank</key>
<string>Default</string>
<key>LSItemContentTypes</key>
<array>
<string>org.tukaani.lzma-archive</string>
</array>
<key>LSTypeIsPackage</key>
<false/>
</dict>
<dict>
<key>CFBundleTypeExtensions</key>
<array>
<string>tlzma</string>
<string>tar.lzma</string>
</array>
<key>CFBundleTypeName</key>
<string>LZMA Tarball Archive</string>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
<key>LSHandlerRank</key>
<string>Default</string>
<key>LSItemContentTypes</key>
<array>
<string>org.tukaani.tar-lzma-archive</string>
</array>
<key>LSTypeIsPackage</key>
<false/>
</dict>
<dict>
<key>CFBundleTypeExtensions</key>
<array>
Expand Down Expand Up @@ -1054,6 +1091,46 @@
</array>
</dict>
</dict>
<dict>
<key>UTTypeConformsTo</key>
<array>
<string>public.archive</string>
<string>public.data</string>
</array>
<key>UTTypeDescription</key>
<string>LZMA File</string>
<key>UTTypeIcons</key>
<dict/>
<key>UTTypeIdentifier</key>
<string>org.tukaani.lzma-archive</string>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array>
<string>lzma</string>
</array>
</dict>
</dict>
<dict>
<key>UTTypeConformsTo</key>
<array>
<string>public.archive</string>
<string>public.data</string>
</array>
<key>UTTypeDescription</key>
<string>LZMA Tar Archive</string>
<key>UTTypeIcons</key>
<dict/>
<key>UTTypeIdentifier</key>
<string>org.tukaani.tar-lzma-archive</string>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array>
<string>tlzma</string>
</array>
</dict>
</dict>
</array>
<key>ITSAppUsesNonExemptEncryption</key>
<true/>
Expand Down
27 changes: 27 additions & 0 deletions Modules/Sources/CSevenZip/sevenzip_bridge.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1125,6 +1125,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;
Expand Down Expand Up @@ -1196,6 +1214,15 @@ SZArchiveRef sz_open(const char *path, const char *password,
for (int depth = 0; depth < kMaxNestingDepth; depth++) {
IInArchive *currentArc = handle->levels.back().archive;

// 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);
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);
Expand Down
19 changes: 19 additions & 0 deletions Modules/Sources/Core/Formats/Catalog.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -571,6 +583,13 @@
"extensions": ["tlz4","tar.lz4"],
"components": ["tar","lz4"]
},
{
"id": "tar.lzma",
"name": "LZMA Tar Archive",
"uti": ["org.tukaani.tar-lzma-archive"],
"extensions": ["tlzma", "tar.lzma"],
"components": ["tar","lzma"]
},
{
"id": "tar.xz",
"name": "XZ Tar Archive",
Expand Down
23 changes: 23 additions & 0 deletions Modules/Tests/CoreTests/DefaultArchiveTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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)
])
Expand All @@ -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"),
Expand Down
1 change: 1 addition & 0 deletions QuickLookExtension/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
<string>org.gnu.gnu-zip-archive</string>
<string>org.gnu.gnu-zip-tar-archive</string>
<string>org.tukaani.lzma-archive</string>
<string>org.tukaani.tar-lzma-archive</string>
<string>org.tukaani.tar-xz-archive</string>
<string>org.tukaani.xz-archive</string>
<string>public.archive</string>
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,8 @@ MacPacker reads and extracts 40+ formats across archives, disk images, and compr
| --- | --- |
| **Archives** | 7z · aar · apk · ar · arj · cab · cbr · cbz · chm · cpio · deb · exe · jar · 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 (tlzma) · tar.xz (txz) · tar.lz4 · tar.z (taz) |
| **Split archives** | zip.001 · z01 · 7z.001 |

See the [full format reference and per-format guides](https://macpacker.app/en/docs) on the website.
Expand Down
Loading