Class: Omnizip::Parity::Models::MainPacket
- Inherits:
-
Packet
- Object
- Lutaml::Model::Serializable
- Packet
- Omnizip::Parity::Models::MainPacket
- Defined in:
- lib/omnizip/parity/models/main_packet.rb
Overview
PAR2 Main packet
Contains recovery set metadata including block size and file IDs.
Body structure:
- block_size (8 bytes, Q<): Size of each data block
- file_ids (16 bytes each): List of file IDs in the recovery set
Note: In current Par2Creator implementation, the body includes additional fields after block_size that are not part of the standard PAR2 spec. This model follows the actual PAR2 spec.
Constant Summary collapse
- PACKET_TYPE =
Packet type identifier
"PAR 2.0\x00Main\x00\x00\x00\x00"
Constants inherited from Packet
Instance Attribute Summary
Attributes inherited from Packet
Instance Method Summary collapse
-
#build_body ⇒ String
Build body data from attributes.
-
#file_count ⇒ Integer
Get number of files in recovery set.
-
#includes_file?(file_id) ⇒ Boolean
Check if packet contains specific file ID.
-
#initialize(**attributes) ⇒ MainPacket
constructor
Initialize main packet.
-
#parse_body ⇒ Object
Parse body data into attributes.
Methods inherited from Packet
#calculate_hash, #packet_type, read_from, #valid_hash?, #write_to
Constructor Details
#initialize(**attributes) ⇒ MainPacket
Initialize main packet
30 31 32 33 |
# File 'lib/omnizip/parity/models/main_packet.rb', line 30 def initialize(**attributes) super self.type = PACKET_TYPE end |
Instance Method Details
#build_body ⇒ String
Build body data from attributes
Constructs binary body data from block_size and file_ids
90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 |
# File 'lib/omnizip/parity/models/main_packet.rb', line 90 def build_body data = +"" # Write block_size (8 bytes, little-endian) data << [block_size].pack("Q<") # Write file IDs (16 bytes each) file_ids.each do |file_id| # Ensure file_id is exactly 16 bytes if file_id.bytesize != 16 raise ArgumentError, "File ID must be 16 bytes, got #{file_id.bytesize}" end data << file_id end self.body_data = data end |
#file_count ⇒ Integer
Get number of files in recovery set
112 113 114 |
# File 'lib/omnizip/parity/models/main_packet.rb', line 112 def file_count file_ids.size end |
#includes_file?(file_id) ⇒ Boolean
Check if packet contains specific file ID
120 121 122 |
# File 'lib/omnizip/parity/models/main_packet.rb', line 120 def includes_file?(file_id) file_ids.include?(file_id) end |
#parse_body ⇒ Object
Parse body data into attributes
Body format (PAR2 spec):
- block_size: 8 bytes (Q<)
- file_ids: 16 bytes each, until end of body
par2cmdline variant also includes:
- file_count: 4 bytes (L<) after block_size
- then file_ids: 16 bytes each
This method detects which format is used.
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 76 77 78 79 80 81 82 83 |
# File 'lib/omnizip/parity/models/main_packet.rb', line 46 def parse_body return if body_data.nil? || body_data.empty? pos = 0 # Read block_size (8 bytes, little-endian unsigned 64-bit) self.block_size = body_data[pos, 8].unpack1("Q<") pos += 8 # Detect format: check if next 4 bytes are a file_count remaining = body_data.bytesize - pos if remaining >= 4 # Try to read potential file_count potential_count = body_data[pos, 4].unpack1("L<") expected_size = potential_count * 16 # Check if this looks like par2cmdline format: # - Remaining bytes should be: 4 (count) + count * 16 (file_ids) # - Count should be reasonable (> 0, < 10000 for sanity) if remaining == (4 + expected_size) && potential_count.positive? && potential_count < 10_000 # par2cmdline format detected pos += 4 # Skip the file_count field end end # Read file IDs (16 bytes each) until end of body self.file_ids = [] while pos < body_data.bytesize file_id = body_data[pos, 16] break if file_id.nil? || file_id.bytesize < 16 file_ids << file_id pos += 16 end end |