CAB Format Guide
Purpose
This guide provides comprehensive documentation for working with Microsoft Cabinet (CAB) files using Cabriolet. CAB is the most widely used Microsoft compression format, designed for software distribution and system file packaging.
Concepts
What is a CAB File?
CAB (Cabinet) files are Microsoft’s archive format for bundling multiple files with compression. They are used extensively in Windows for:
-
Software installers and updates
-
System file distribution
-
Windows Update packages
-
Driver packages
-
Application deployment
CAB File Structure
A CAB file consists of three main components:
┌─────────────────────────┐
│ Cabinet Header │ File metadata and settings
├─────────────────────────┤
│ Folder Entries │ Compression blocks
│ ┌─────────────────┐ │
│ │ Compressed Data │ │ Files grouped into folders
│ └─────────────────┘ │
├─────────────────────────┤
│ File Entries │ File metadata (names, sizes)
└─────────────────────────┘Cabinet Header: Contains global settings, cabinet ID, and pointers to folders and files.
Folders: Compression units containing one or more files compressed together. Each folder uses a single compression algorithm.
Files: Individual files within the cabinet, stored in folders with metadata like name, size, and attributes.
Compression Support
CAB files support multiple compression algorithms:
-
None (Type 0) - Uncompressed storage
-
MSZIP (Type 1) - Deflate-based compression, ZIP-compatible
-
Quantum (Type 2) - Configurable window size
-
LZX (Type 3) - High compression ratio
For detailed algorithm information, see link:.
Multi-part Archives
Large CAB files can be split across multiple volumes:
large-archive.cab (part 1)
large-archive.ca2 (part 2)
large-archive.ca3 (part 3)Each part references the next, enabling extraction across volumes. See Compression Algorithms Guide for details.
Basic Operations
Listing CAB Contents
View files without extracting:
cabriolet list archive.cabrequire 'cabriolet'
decompressor = Cabriolet::CAB::Decompressor.new('archive.cab')
decompressor.each_file do |file|
puts "#{file.name} (#{file.size} bytes)"
endFiles in archive.cab:
readme.txt (1,245 bytes)
setup.exe (524,288 bytes)
config/settings.ini (512 bytes)
Total: 3 files, 526,045 bytes
Compression: MSZIPExtracting files
Extract all files to a directory:
# Extract to current directory
cabriolet extract archive.cab
# Extract to specific directory
cabriolet extract archive.cab output/require 'cabriolet'
# Extract all files
decompressor = Cabriolet::CAB::Decompressor.new('archive.cab')
decompressor.extract('output/')
# Extract specific file
decompressor.extract_file('readme.txt', 'output/readme.txt')Getting Archive Information
Display detailed cabinet information:
cabriolet info archive.cabrequire 'cabriolet'
decompressor = Cabriolet::CAB::Decompressor.new('archive.cab')
cabinet = decompressor.cabinet
puts "Set ID: #{cabinet.set_id}"
puts "Folders: #{cabinet.folders.count}"
puts "Files: #{cabinet.files.count}"
cabinet.folders.each_with_index do |folder, i|
puts "Folder #{i + 1}: #{folder.compression} compression"
endTesting integrity
Verify archive is not corrupted:
cabriolet test archive.cabrequire 'cabriolet'
decompressor = Cabriolet::CAB::Decompressor.new('archive.cab')
valid = decompressor.test
if valid
puts "Archive is valid"
else
puts "Archive is corrupted"
endCreating CAB Archives
Build new CAB files from source files:
# Create with default MSZIP compression
cabriolet create archive.cab file1.txt file2.txt
# Create with LZX for maximum compression
cabriolet create --compression=lzx small.cab files/
# Create uncompressed
cabriolet create --compression=none fast.cab data/require 'cabriolet'
# Create with MSZIP (default)
compressor = Cabriolet::CAB::Compressor.new
compressor.add_file('readme.txt')
compressor.add_file('setup.exe')
compressor.write('archive.cab')
# Create with LZX compression
compressor = Cabriolet::CAB::Compressor.new(compression: :lzx)
compressor.add_file('large-file.dat')
compressor.write('compressed.cab')Advanced Features
Working with Folders
CAB files organize files into folders (compression blocks):
require 'cabriolet'
decompressor = Cabriolet::CAB::Decompressor.new('archive.cab')
cabinet = decompressor.cabinet
cabinet.folders.each_with_index do |folder, i|
puts "Folder #{i + 1}:"
puts " Compression: #{folder.compression}"
puts " Data size: #{folder.data_size} bytes"
# Files in this folder
folder.files.each do |file|
puts " #{file.name}"
end
endFile Attributes
CAB files preserve file attributes:
require 'cabriolet'
decompressor = Cabriolet::CAB::Decompressor.new('archive.cab')
decompressor.each_file do |file|
puts "#{file.name}:"
puts " Read-only: #{file.read_only?}"
puts " Hidden: #{file.hidden?}"
puts " System: #{file.system?}"
puts " Archive: #{file.archive?}"
puts " Modified: #{file.time}"
endCabinet Sets
Multi-cabinet archives use set IDs to link volumes:
require 'cabriolet'
decompressor = Cabriolet::CAB::Decompressor.new('archive.cab')
cabinet = decompressor.cabinet
puts "Set ID: #{cabinet.set_id}"
puts "Cabinet number: #{cabinet.cabinet_number}"
if cabinet.has_next?
puts "Next cabinet: #{cabinet.next_cabinet}"
end
if cabinet.has_prev?
puts "Previous cabinet: #{cabinet.prev_cabinet}"
endReserve Space
CAB files can reserve space for digital signatures:
require 'cabriolet'
# Create CAB with reserved header space
compressor = Cabriolet::CAB::Compressor.new(
header_reserve: 6144, # Reserve for signature
folder_reserve: 0,
data_reserve: 0
)
compressor.add_file('setup.exe')
compressor.write('signed.cab')Performance Optimization
Choosing Compression
Select compression based on your needs:
| Algorithm | Use Case | Trade-off |
|---|---|---|
None | Pre-compressed files, testing | No compression, fastest |
MSZIP | General purpose, default | Balanced speed/ratio |
LZX | Distribution packages | Best ratio, slower compression |
Quantum | Legacy compatibility | Configurable window size |
See link: for detailed guidance.
Extraction Performance
Tips for faster extraction:
require 'cabriolet'
# Efficient: Extract to specific directory
decompressor = Cabriolet::CAB::Decompressor.new('archive.cab')
decompressor.extract('output/')
# Less efficient: Extract files one-by-one
decompressor.each_file do |file|
# Individual extraction has overhead
decompressor.extract_file(file.name, "output/#{file.name}")
endMemory usage
For large CABs, use streaming:
require 'cabriolet'
# Low memory: Stream files
decompressor = Cabriolet::CAB::Decompressor.new('large.cab')
decompressor.each_file do |file|
File.open("output/#{file.name}", 'wb') do |output|
file.extract_to(output)
end
end
# Higher memory: Load entire cabinet structure
cabinet = decompressor.cabinet
# Now entire structure is in memoryCommon Use Cases
Software Distribution
Creating installer packages:
require 'cabriolet'
# Create installer CAB with LZX
compressor = Cabriolet::CAB::Compressor.new(compression: :lzx)
# Add application files
compressor.add_file('bin/program.exe')
compressor.add_file('bin/library.dll')
# Add documentation
compressor.add_file('docs/readme.txt')
compressor.add_file('docs/license.txt')
# Add configuration
compressor.add_file('config/settings.xml')
compressor.write('installer.cab')Windows Update Packages
Analyzing Windows update files:
require 'cabriolet'
# Extract Windows update CAB
decompressor = Cabriolet::CAB::Decompressor.new('windows-update.cab')
# List contents
decompressor.each_file do |file|
puts "#{file.name} - #{file.size} bytes"
end
# Extract specific files
decompressor.extract_file('update.msu', 'extracted/update.msu')Driver Packages
Working with driver CABs:
require 'cabriolet'
# Extract driver package
decompressor = Cabriolet::CAB::Decompressor.new('driver.cab')
decompressor.extract('drivers/')
# Find INF files
decompressor.each_file do |file|
if file.name.end_with?('.inf')
puts "Driver INF: #{file.name}"
end
endTroubleshooting
Common Errors
"Invalid CAB signature"
The file is not a valid CAB file or is corrupted. Verify with:
file archive.cab # Should show "Microsoft Cabinet archive data""Unsupported compression type"
The CAB uses an unsupported compression algorithm. Check with:
cabriolet info archive.cab # Shows compression type"Corrupt data block"
The CAB file is damaged. Try salvage mode:
cabriolet extract --salvage damaged.cab output/"Cannot find next cabinet"
Multi-part archive is missing volumes. Ensure all parts are present:
ls archive.cab archive.ca*Validation
Verify CAB integrity before use:
require 'cabriolet'
begin
decompressor = Cabriolet::CAB::Decompressor.new('archive.cab')
# Test archive
if decompressor.test
puts "Archive is valid"
decompressor.extract('output/')
else
puts "Archive is corrupted"
end
rescue Cabriolet::FormatError => e
puts "Invalid CAB file: #{e.message}"
rescue Cabriolet::CorruptionError => e
puts "Corrupted data: #{e.message}"
endBest practices
-
Test before distributing: Always verify created CABs with
testcommand -
Choose appropriate compression:
-
MSZIP for general use
-
LZX for distribution (smaller size)
-
None for already-compressed files
-
-
Preserve file attributes: Use
extractto maintain timestamps and attributes -
Handle multi-part archives: Keep all parts together and in order
-
Validate inputs: Check file integrity before extraction
-
Use salvage mode for recovery: When dealing with potentially corrupted files
Format Specifications
File Signature
CAB files start with the signature MSCF (0x4D534346):
Offset Bytes Description
0x0000 4 Signature: "MSCF" (0x4D 0x53 0x43 0x46)
0x0004 4 Reserved1
0x0008 4 Cabinet size
0x000C 4 Reserved2
0x0010 4 Files offsetFor complete format specifications, see link:.
Compression Type Codes
-
0- None (uncompressed) -
1- MSZIP (Deflate) -
2- Quantum -
3- LZX
See Compression Algorithms Guide for details.
Next steps
-
Learn about compression algorithms in detail
-
Explore multi-part cabinets
-
Review extracting files
-
Study Ruby API