Class: Cabriolet::OAB::Decompressor
- Inherits:
-
Object
- Object
- Cabriolet::OAB::Decompressor
- Defined in:
- lib/cabriolet/oab/decompressor.rb
Overview
Decompressor for OAB (Outlook Offline Address Book) files
OAB files use LZX compression and come in two formats:
-
Full files (version 3.1): Complete address book data
-
Incremental patches (version 3.2): Binary patches applied to base file
This implementation is based on libmspack’s oabd.c
NOTE: This implementation cannot be fully validated due to lack of test fixtures. OAB files are specialized Outlook data files. Testing relies on round-trip compression/decompression.
Constant Summary collapse
- DEFAULT_BUFFER_SIZE =
Default buffer size for I/O operations
4096
Instance Attribute Summary collapse
-
#buffer_size ⇒ Object
Returns the value of attribute buffer_size.
-
#io_system ⇒ Object
readonly
Returns the value of attribute io_system.
Instance Method Summary collapse
-
#decompress(input_file, output_file) ⇒ Integer
Decompress a full OAB file.
-
#decompress_incremental(patch_file, base_file, output_file) ⇒ Integer
Decompress an incremental patch file.
-
#initialize(io_system = nil) ⇒ Decompressor
constructor
Initialize OAB decompressor.
Constructor Details
#initialize(io_system = nil) ⇒ Decompressor
Initialize OAB decompressor
28 29 30 31 |
# File 'lib/cabriolet/oab/decompressor.rb', line 28 def initialize(io_system = nil) @io_system = io_system || System::IOSystem.new @buffer_size = DEFAULT_BUFFER_SIZE end |
Instance Attribute Details
#buffer_size ⇒ Object
Returns the value of attribute buffer_size.
20 21 22 |
# File 'lib/cabriolet/oab/decompressor.rb', line 20 def buffer_size @buffer_size end |
#io_system ⇒ Object (readonly)
Returns the value of attribute io_system.
19 20 21 |
# File 'lib/cabriolet/oab/decompressor.rb', line 19 def io_system @io_system end |
Instance Method Details
#decompress(input_file, output_file) ⇒ Integer
Decompress a full OAB file
39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 |
# File 'lib/cabriolet/oab/decompressor.rb', line 39 def decompress(input_file, output_file) input_handle = @io_system.open(input_file, Constants::MODE_READ) output_handle = @io_system.open(output_file, Constants::MODE_WRITE) begin # Read and validate header header_data = @io_system.read(input_handle, 16) raise Error, "Failed to read OAB header" if header_data.length < 16 header = Binary::OABStructures::FullHeader.read(header_data) raise Error, "Invalid OAB header" unless header.valid? block_max = header.block_max target_size = header.target_size total_written = 0 # Process blocks until target size reached while target_size.positive? total_written += decompress_block( input_handle, output_handle, block_max, target_size ) target_size -= [block_max, target_size].min end total_written ensure @io_system.close(input_handle) if input_handle @io_system.close(output_handle) if output_handle end end |
#decompress_incremental(patch_file, base_file, output_file) ⇒ Integer
Decompress an incremental patch file
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 |
# File 'lib/cabriolet/oab/decompressor.rb', line 77 def decompress_incremental(patch_file, base_file, output_file) patch_handle = @io_system.open(patch_file, Constants::MODE_READ) base_handle = @io_system.open(base_file, Constants::MODE_READ) output_handle = @io_system.open(output_file, Constants::MODE_WRITE) begin # Read and validate patch header header_data = @io_system.read(patch_handle, 28) if header_data.length < 28 raise Error, "Failed to read OAB patch header" end header = Binary::OABStructures::PatchHeader.read(header_data) raise Error, "Invalid OAB patch header" unless header.valid? block_max = [header.block_max, 16].max # At least 16 for header target_size = header.target_size total_written = 0 # Process patch blocks until target size reached while target_size.positive? total_written += decompress_patch_block( patch_handle, base_handle, output_handle, block_max, target_size ) target_size = header.target_size - total_written end total_written ensure @io_system.close(patch_handle) if patch_handle @io_system.close(base_handle) if base_handle @io_system.close(output_handle) if output_handle end end |