Class: Omnizip::Formats::Rar::ParityHandler

Inherits:
Object
  • Object
show all
Defined in:
lib/omnizip/formats/rar/parity_handler.rb

Overview

RAR parity operations handler Reads parity data and performs recovery calculations

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(recovery_record) ⇒ ParityHandler

Initialize parity handler

Parameters:



14
15
16
17
# File 'lib/omnizip/formats/rar/parity_handler.rb', line 14

def initialize(recovery_record)
  @recovery_record = recovery_record
  @parity_blocks = []
end

Instance Attribute Details

#parity_blocksObject (readonly)

Returns the value of attribute parity_blocks.



9
10
11
# File 'lib/omnizip/formats/rar/parity_handler.rb', line 9

def parity_blocks
  @parity_blocks
end

#recovery_recordObject (readonly)

Returns the value of attribute recovery_record.



9
10
11
# File 'lib/omnizip/formats/rar/parity_handler.rb', line 9

def recovery_record
  @recovery_record
end

Instance Method Details

#calculate_parity(data, block_index) ⇒ String

Calculate parity for a block

Parameters:

  • data (String)

    Binary data

  • block_index (Integer)

    Block index

Returns:

  • (String)

    Parity data



65
66
67
68
69
70
# File 'lib/omnizip/formats/rar/parity_handler.rb', line 65

def calculate_parity(data, block_index)
  # Basic XOR parity for simple recovery
  # In production, would use Reed-Solomon
  parity = data.bytes.reduce(0) { |acc, byte| acc ^ byte }
  [parity, block_index].pack("CN")
end

#can_recover?(block_index) ⇒ Boolean

Check if block can be recovered

Parameters:

  • block_index (Integer)

    Block index

Returns:

  • (Boolean)

    true if recoverable



91
92
93
94
95
96
# File 'lib/omnizip/formats/rar/parity_handler.rb', line 91

def can_recover?(block_index)
  return false if @parity_blocks.empty?

  # Can recover if we have parity data for this block
  @parity_blocks.any? { |p| p[:index] == block_index }
end

#load_parity_data(rev_files) ⇒ Boolean

Load parity data from .rev files

Parameters:

  • rev_files (Array<String>)

    Paths to .rev files

Returns:

  • (Boolean)

    true if loaded successfully



23
24
25
26
27
28
29
30
31
32
# File 'lib/omnizip/formats/rar/parity_handler.rb', line 23

def load_parity_data(rev_files)
  @parity_blocks = []

  rev_files.each do |rev_file|
    blocks = parse_rev_file(rev_file)
    @parity_blocks.concat(blocks) if blocks
  end

  @parity_blocks.any?
end

#parity_block(index) ⇒ Hash?

Get parity block by index

Parameters:

  • index (Integer)

    Block index

Returns:

  • (Hash, nil)

    Parity block data



111
112
113
# File 'lib/omnizip/formats/rar/parity_handler.rb', line 111

def parity_block(index)
  @parity_blocks.find { |p| p[:index] == index }
end

#recover_block(archive_path, block_index) ⇒ String?

Recover corrupted block

Parameters:

  • archive_path (String)

    Path to archive

  • block_index (Integer)

    Block to recover

Returns:

  • (String, nil)

    Recovered data or nil



77
78
79
80
81
82
83
84
85
# File 'lib/omnizip/formats/rar/parity_handler.rb', line 77

def recover_block(archive_path, block_index)
  return nil unless can_recover?(block_index)

  if @recovery_record.version == 5
    recover_rar5_block(archive_path, block_index)
  else
    recover_rar4_block(archive_path, block_index)
  end
end

#total_blocksInteger

Get total number of blocks

Returns:

  • (Integer)

    Total blocks



101
102
103
104
105
# File 'lib/omnizip/formats/rar/parity_handler.rb', line 101

def total_blocks
  return 0 if @recovery_record.block_size.zero?

  (@recovery_record.protected_size / @recovery_record.block_size.to_f).ceil
end

#verify_blocks(archive_path, block_indices = nil) ⇒ Hash

Verify archive blocks using parity

Parameters:

  • archive_path (String)

    Path to archive

  • block_indices (Array<Integer>) (defaults to: nil)

    Blocks to verify

Returns:

  • (Hash)

    Verification results



39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
# File 'lib/omnizip/formats/rar/parity_handler.rb', line 39

def verify_blocks(archive_path, block_indices = nil)
  if @parity_blocks.empty?
    return { verified: false,
             error: "No parity data" }
  end

  blocks_to_check = block_indices || (0...total_blocks).to_a
  corrupted_blocks = []

  blocks_to_check.each do |index|
    corrupted_blocks << index unless verify_block(archive_path, index)
  end

  {
    verified: corrupted_blocks.empty?,
    total: blocks_to_check.size,
    ok: blocks_to_check.size - corrupted_blocks.size,
    corrupted: corrupted_blocks,
  }
end