Class: Cabriolet::OAB::CommandHandler

Inherits:
Commands::BaseCommandHandler show all
Defined in:
lib/cabriolet/oab/command_handler.rb

Overview

Command handler for OAB (Outlook Offline Address Book) format

This handler implements the unified command interface for OAB files, wrapping the existing OAB::Decompressor and OAB::Compressor classes. OAB files use LZX compression for address book data.

Unlike other formats, OAB is a compressed data format rather than an archive - the “list” command displays header information only.

Instance Method Summary collapse

Methods inherited from Commands::BaseCommandHandler

#initialize

Constructor Details

This class inherits a constructor from Cabriolet::Commands::BaseCommandHandler

Instance Method Details

#create(output, files = [], options = {}) ⇒ void

This method returns an undefined value.

Create OAB compressed file

Compresses a file using OAB LZX compression.

Parameters:

  • output (String)

    Output OAB file path

  • files (Array<String>) (defaults to: [])

    Input file (single file for OAB)

  • options (Hash) (defaults to: {})

    Additional options

Options Hash (options):

  • :block_size (Integer)

    Block size for compression

  • :base_file (String)

    Base file for creating incremental patch

Raises:



88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
# File 'lib/cabriolet/oab/command_handler.rb', line 88

def create(output, files = [], options = {})
  raise ArgumentError, "No file specified" if files.empty?

  if files.size > 1
    raise ArgumentError,
          "OAB format supports only one file at a time"
  end

  file = files.first
  unless File.exist?(file)
    raise ArgumentError,
          "File does not exist: #{file}"
  end

  compressor = Compressor.new

  # Auto-generate output name if not provided
  if output.nil?
    output = "#{file}.oab"
  end

  if options[:base_file]
    base_file = options[:base_file]
    unless File.exist?(base_file)
      raise ArgumentError,
            "Base file does not exist: #{base_file}"
    end

    puts "Creating incremental patch: #{file} - #{base_file} -> #{output}" if verbose?
    bytes = compressor.compress_incremental(file, base_file, output,
                                            **options)
    puts "Created incremental patch #{output} (#{bytes} bytes)"
  else
    block_size = options[:block_size]
    puts "Compressing #{file} -> #{output} (block_size: #{block_size || 'default'})" if verbose?
    bytes = compressor.compress(file, output, **options)
    puts "Compressed #{file} to #{output} (#{bytes} bytes)"
  end
end

#extract(file, output_dir = nil, options = {}) ⇒ void

This method returns an undefined value.

Extract/decompress OAB file

Decompresses the OAB file to its original form. Auto-detects output filename if not specified.

Parameters:

  • file (String)

    Path to the OAB file

  • output_dir (String) (defaults to: nil)

    Output directory (not typically used for OAB)

  • options (Hash) (defaults to: {})

    Additional options

Options Hash (options):

  • :output (String)

    Output file path

  • :base_file (String)

    Base file for incremental patches



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
69
70
71
72
73
74
75
# File 'lib/cabriolet/oab/command_handler.rb', line 44

def extract(file, output_dir = nil, options = {})
  validate_file_exists(file)

  output = options[:output]

  # Auto-detect output name if not provided
  if output.nil? && output_dir.nil?
    output = auto_output_filename(file)
  end

  # If output_dir is specified, construct output path
  if output.nil? && output_dir
    base_name = File.basename(file, ".*")
    output = File.join(output_dir, base_name)
  end

  decompressor = Decompressor.new

  # Check if this is an incremental patch
  if options[:base_file]
    base_file = options[:base_file]
    validate_file_exists(base_file)

    puts "Applying incremental patch: #{file} + #{base_file} -> #{output}" if verbose?
    bytes = decompressor.decompress_incremental(file, base_file, output)
    puts "Applied patch to #{output} (#{bytes} bytes)"
  else
    puts "Decompressing #{file} -> #{output}" if verbose?
    bytes = decompressor.decompress(file, output)
    puts "Decompressed #{file} to #{output} (#{bytes} bytes)"
  end
end

#info(file, _options = {}) ⇒ void

This method returns an undefined value.

Display detailed OAB file information

Parameters:

  • file (String)

    Path to the OAB file

  • options (Hash)

    Additional options (unused)



133
134
135
136
137
# File 'lib/cabriolet/oab/command_handler.rb', line 133

def info(file, _options = {})
  validate_file_exists(file)

  display_oab_info(file)
end

#list(file, _options = {}) ⇒ void

This method returns an undefined value.

List OAB file information

Displays information about the OAB file including version, block size, and target size.

Parameters:

  • file (String)

    Path to the OAB file

  • options (Hash)

    Additional options (unused)



27
28
29
30
31
# File 'lib/cabriolet/oab/command_handler.rb', line 27

def list(file, _options = {})
  validate_file_exists(file)

  display_oab_info(file)
end

#test(file, _options = {}) ⇒ void

This method returns an undefined value.

Test OAB file integrity

Verifies the OAB file structure.

Parameters:

  • file (String)

    Path to the OAB file

  • options (Hash)

    Additional options (unused)



146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
# File 'lib/cabriolet/oab/command_handler.rb', line 146

def test(file, _options = {})
  validate_file_exists(file)

  puts "Testing #{file}..."

  # Try to read and validate header
  decompressor = Decompressor.new
  # We can't easily test without decompressing, so we attempt to read the header
  io_system = decompressor.io_system
  handle = io_system.open(file, Constants::MODE_READ)

  begin
    header_data = io_system.read(handle, 16)
    if header_data.length < 16
      puts "ERROR: Failed to read OAB header"
      return
    end

    # Check if it's a full file or patch file
    full_header = Binary::OABStructures::FullHeader.read(header_data)
    if full_header.valid?
      puts "OK: OAB full file structure is valid"
      puts "Version: #{full_header.version_hi}.#{full_header.version_lo}"
      puts "Target size: #{full_header.target_size} bytes"
      puts "Block max: #{full_header.block_max} bytes"
    else
      # Check for patch header
      patch_header = Binary::OABStructures::PatchHeader.read(header_data)
      if patch_header.valid?
        puts "OK: OAB patch file structure is valid"
        puts "Version: #{patch_header.version_hi}.#{patch_header.version_lo}"
        puts "Target size: #{patch_header.target_size} bytes"
        puts "Source size: #{patch_header.source_size} bytes"
      else
        puts "ERROR: Invalid OAB header signature"
      end
    end
  rescue StandardError => e
    puts "ERROR: OAB file validation failed: #{e.message}"
  ensure
    io_system.close(handle)
  end
end