9 releases
Uses new Rust 2024
| 0.4.2 | Apr 12, 2026 |
|---|---|
| 0.4.1 | Feb 21, 2026 |
| 0.3.5 | Feb 17, 2026 |
| 0.2.0 | Feb 11, 2026 |
#283 in Compression
Used in dpp-tool
485KB
10K
SLoC
dpp
All-in-one Rust pipeline for Apple DMG → HFS+/APFS → PKG → PBZX extraction
Open a .dmg, browse the HFS+ or APFS filesystem inside, extract .pkg installers, and unpack their payloads — all in a single pipeline, on any platform.
No macOS required — works on Linux and Windows too.
Why dpp?
dpp is the only Rust library that chains the entire Apple package extraction pipeline into a single API.
Without dpp, extracting files from a macOS .dmg requires 4+ separate tools:
DMG file → [dmg tool] → raw partition → [hfs/apfs tool] → pkg file → [xar tool] → payload → [pbzx tool] → files
With dpp:
let files = dpp::extract_pkg_payload("image.dmg", "/path/to.pkg", "component")?;
| Feature | dpp | Manual pipeline |
|---|---|---|
| Single API call | ✓ | ❌ (4+ tools) |
| HFS+ and APFS support | ✓ | partial |
| Auto-detect filesystem | ✓ | ❌ |
| Memory-efficient streaming | ✓ | ❌ (temp files) |
| Type-safe error handling | ✓ | ❌ (string errors) |
| Cross-platform | ✓ | partial |
| Low memory mode | ✓ | ❌ |
Features
| Open DMG | Parse UDIF disk images with all compression formats |
| Browse HFS+ | Navigate HFS+ filesystems inside the DMG |
| Browse APFS | Navigate APFS filesystems inside the DMG |
| Auto-detect FS | open_filesystem() detects HFS+ or APFS automatically |
| Extract PKG | Open .pkg installers found on the volume |
| Unpack PBZX | Decompress XZ payloads and parse CPIO archives |
| Find packages | Auto-discover all .pkg files in a DMG |
| Low memory | Stream through temp files instead of buffering in RAM |
Pipeline
┌─────────┐
┌──▶│ HFS+ │──┐
┌─────────┐ │ │ (volume)│ │ ┌─────────┐ ┌─────────┐
│ UDIF │──┤ └─────────┘ ├──▶│ XAR │───▶│ PBZX │
│ (DMG) │ │ ┌─────────┐ │ │ (PKG) │ │ (files) │
└─────────┘ └──▶│ APFS │──┘ └─────────┘ └─────────┘
udif │ (volume)│ xara pbzx
└─────────┘
hfsplus / apfs
Extraction Modes
| Mode | Memory | Speed | Best for |
|---|---|---|---|
TempFile (default) |
Low (~4 KB) | Normal | Large DMGs (1+ GB) |
InMemory |
High (partition size) | Fast | Small DMGs (< 500 MB) |
Quick Start
Browse a DMG (auto-detect filesystem)
use dpp::DmgPipeline;
// Open DMG and auto-detect HFS+ or APFS
let mut pipeline = DmgPipeline::open("image.dmg")?;
let mut fs = pipeline.open_filesystem()?;
// Check what was detected
println!("Filesystem: {:?}", fs.fs_type());
// List root directory (unified FsDirEntry)
for entry in fs.list_directory("/")? {
println!("{:?} {:>12} {}", entry.kind, entry.size, entry.name);
}
// Get unified volume info
let info = fs.volume_info();
println!("Files: {}, Dirs: {}", info.file_count, info.directory_count);
// Read a file
let data = fs.read_file("/path/to/file.txt")?;
Choose Extraction Mode
use dpp::{DmgPipeline, ExtractMode};
// In-memory mode: faster for small DMGs
let mut pipeline = DmgPipeline::open("small.dmg")?;
let mut fs = pipeline.open_filesystem_with_mode(ExtractMode::InMemory)?;
// Temp-file mode (default): low memory for large DMGs
let mut pipeline = DmgPipeline::open("large.dmg")?;
let mut fs = pipeline.open_filesystem_with_mode(ExtractMode::TempFile)?;
Browse a DMG (HFS+ specific)
use dpp::DmgPipeline;
// Open DMG and extract HFS+ volume directly
let mut pipeline = DmgPipeline::open("Kernel_Debug_Kit.dmg")?;
let mut hfs = pipeline.open_hfs()?;
// List root directory
for entry in hfs.list_directory("/")? {
println!("{:?} {:>12} {}", entry.kind, entry.size, entry.name);
}
// Read a file
let data = hfs.read_file("/Library/Developer/KDKs/readme.txt")?;
Browse a DMG (APFS specific)
use dpp::DmgPipeline;
// Open DMG and extract APFS volume directly
let mut pipeline = DmgPipeline::open("app.dmg")?;
let mut apfs = pipeline.open_apfs()?;
// Volume info
let vi = apfs.volume_info();
println!("Volume: {} ({} files)", vi.name, vi.num_files);
// List root directory
for entry in apfs.list_directory("/")? {
println!("{:?} {:>12} {}", entry.kind, entry.size, entry.name);
}
Extract a PKG Payload
// Open a .pkg found on the HFS+ volume
let mut pkg = hfs.open_pkg("/path/to/installer.pkg")?;
// List components
for component in pkg.components() {
println!("Component: {}", component);
}
// Extract payload (PBZX archive)
let payload = pkg.payload("com.apple.pkg.KDK")?;
let archive = pbzx::Archive::from_reader(std::io::Cursor::new(payload))?;
// List files in the payload
for entry in archive.list()? {
println!("{}: {} bytes", entry.path, entry.size);
}
One-Call Extraction
// Find all .pkg files in a DMG
let packages = dpp::find_packages("image.dmg")?;
for pkg_path in &packages {
println!("Found: {}", pkg_path);
}
// Extract a specific component payload in one call
let archive = dpp::extract_pkg_payload(
"image.dmg",
"/path/to/installer.pkg",
"com.apple.pkg.KDK",
)?;
for entry in archive.list()? {
println!("{}", entry.path);
}
Low-Memory Streaming
// Use TempFile mode for large DMGs (default)
let mut hfs = pipeline.open_hfs()?;
// Stream a PKG through a temp file instead of buffering
let mut pkg = hfs.open_pkg_streaming("/large-installer.pkg")?;
// Stream payload to disk
let mut out = std::fs::File::create("payload.pbzx")?;
pkg.payload_to("component", &mut out)?;
Documentation
| CLI Tool | dpp-tool usage for exploring DMGs interactively |
| Architecture | Pipeline design and type-erasure patterns |
Example Output
$ dpp-tool info Kernel_Debug_Kit.dmg
DMG Pipeline: Kernel_Debug_Kit.dmg
════════════════════════════════════════════════════════════
DMG (UDIF)
────────────────────────────────────────────────────────────
Version 4
Partitions 7
Compressed 975.87 MB (975.87 MB)
Uncompressed 1.12 GB
Space savings 15.0%
Block types LZFSE: 988
ID Sectors Size Ratio Name
----------------------------------------------------------
-1 1 512 B 89.6% MBR : 0
2 2089050 1020.04 MB 4.3% Apple_HFSX : 3
HFS+ Volume
────────────────────────────────────────────────────────────
Signature HFSX (case-sensitive)
Version 5
Block size 4096 bytes
Files 3,847
Folders 612
Packages
────────────────────────────────────────────────────────────
└── /Library/Developer/KDKs/KDK_14.2_23C64.pkg 512.30 MB
$ dpp-tool hfs tree Kernel_Debug_Kit.dmg /Library/Developer/KDKs
Tree: Kernel_Debug_Kit.dmg:/Library/Developer/KDKs
════════════════════════════════════════════════════════════
├── KDK_14.2_23C64.pkg 512.30 MB
├── readme.txt 1.22 KB
└── LICENSE.txt 4.78 KB
$ dpp-tool payload ls Kernel_Debug_Kit.dmg /path.pkg com.apple.pkg.KDK /usr
Payload: com.apple.pkg.KDK — /usr
════════════════════════════════════════════════════════════
Kind Size Name
--------------------------------------------------------
dir - lib
dir - share
12.19 KB libfoo.dylib
1 file(s), 2 directory(ies)
Alternatives
There is no equivalent single-crate solution in Rust. The closest approach is to manually combine separate tools:
| Approach | DMG | HFS+ | APFS | PKG | PBZX | Single API | Cross-platform |
|---|---|---|---|---|---|---|---|
| dpp | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
hdiutil + shell |
✓ | ✓ | ✓ | ✓ | ✓ | ❌ | macOS only |
| dmgwiz + hfsfuse + xar | ✓ | ✓ | ❌ | ✓ | ❌ | ❌ | Unix only |
| apple-platform-rs | partial | ❌ | ❌ | partial | ❌ | ❌ | ✓ |
Choose dpp if you need:
- End-to-end DMG → files extraction on any platform
- Single Rust dependency for the entire pipeline
- Memory-efficient streaming for large disk images
- Programmatic access to macOS installer contents
License
MIT
Dependencies
~8–15MB
~294K SLoC