Class: Omnizip::Parity::Models::IfscPacket

Inherits:
Packet
  • Object
show all
Defined in:
lib/omnizip/parity/models/ifsc_packet.rb

Overview

PAR2 IFSC (Input File Slice Checksum) packet

Contains checksums for individual data blocks of a file. One IFSC packet contains checksums for ALL blocks of a file.

Body structure:

  • file_id (16 bytes): File identifier
  • For each block:
    • block_hash (16 bytes): MD5 hash of block data
    • block_crc32 (4 bytes, L<): CRC32 of block data

Constant Summary collapse

PACKET_TYPE =

Packet type identifier

"PAR 2.0\x00IFSC\x00\x00\x00\x00"

Constants inherited from Packet

Packet::PACKET_SIGNATURE

Instance Attribute Summary

Attributes inherited from Packet

#body_data

Instance Method Summary collapse

Methods inherited from Packet

#calculate_hash, #packet_type, read_from, #valid_hash?, #write_to

Constructor Details

#initialize(**attributes) ⇒ IfscPacket

Initialize IFSC packet

Parameters:

  • attributes (Hash)

    Packet attributes



32
33
34
35
36
37
# File 'lib/omnizip/parity/models/ifsc_packet.rb', line 32

def initialize(**attributes)
  super
  self.type = PACKET_TYPE
  self.block_hashes = [] if block_hashes.nil?
  self.block_crc32s = [] if block_crc32s.nil?
end

Instance Method Details

#build_bodyString

Build body data from attributes

Constructs binary body data

Returns:

  • (String)

    Binary body data



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
# File 'lib/omnizip/parity/models/ifsc_packet.rb', line 79

def build_body
  data = +""

  # Validate file_id is 16 bytes
  if file_id.bytesize != 16
    raise ArgumentError,
          "file_id must be 16 bytes, got #{file_id.bytesize}"
  end

  # Write file_id
  data << file_id

  # Write all blocks
  block_hashes.each_with_index do |block_hash, i|
    # Validate block_hash is 16 bytes
    if block_hash.bytesize != 16
      raise ArgumentError,
            "block_hash must be 16 bytes, got #{block_hash.bytesize}"
    end

    # Write block_hash
    data << block_hash

    # Write block_crc32 (4 bytes, little-endian)
    data << [block_crc32s[i]].pack("L<")
  end

  self.body_data = data
end

#parse_bodyObject

Parse body data into attributes

Body format:

  • file_id: 16 bytes
  • For each block:
    • block_hash: 16 bytes
    • block_crc32: 4 bytes (L<)


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
# File 'lib/omnizip/parity/models/ifsc_packet.rb', line 46

def parse_body
  return if body_data.nil? || body_data.empty?
  return if body_data.bytesize < 16

  pos = 0

  # Read file_id (16 bytes)
  self.file_id = body_data[pos, 16]
  pos += 16

  # Read all blocks (each is 16 bytes hash + 4 bytes CRC = 20 bytes)
  self.block_hashes = []
  self.block_crc32s = []

  while pos + 20 <= body_data.bytesize
    # Read block_hash (16 bytes)
    block_hash = body_data[pos, 16]
    pos += 16

    # Read block_crc32 (4 bytes, little-endian unsigned 32-bit)
    block_crc32 = body_data[pos, 4].unpack1("L<")
    pos += 4

    block_hashes << block_hash
    block_crc32s << block_crc32
  end
end