Class: Omnizip::Formats::Rar::Rar5::MultiVolume::VolumeWriter
- Inherits:
-
Object
- Object
- Omnizip::Formats::Rar::Rar5::MultiVolume::VolumeWriter
- Defined in:
- lib/omnizip/formats/rar/rar5/multi_volume/volume_writer.rb
Overview
Volume writer for multi-volume archives
This class writes individual .rar volume files with proper RAR5 headers and volume-specific flags.
Constant Summary collapse
- VOLUME_ARCHIVE_FLAG =
Main header flags for volume archives NOTE: Bits 0-1 are reserved for common flags (EXTRA_AREA, DATA_AREA) Use bits 2+ for format-specific flags
0x0004- VOLUME_NUMBER_FLAG =
Bit 2: This is a volume archive
0x0008- VOLUME_END_FLAG =
End header flags
0x0001
Instance Attribute Summary collapse
-
#io ⇒ IO
readonly
File handle.
-
#is_last ⇒ Boolean
readonly
Is this the last volume?.
-
#path ⇒ String
readonly
Volume file path.
-
#volume_number ⇒ Integer
readonly
Volume number (1-based).
Class Method Summary collapse
-
.volume_filename(base_path, volume_number, naming: "part") ⇒ String
Generate volume filename from base name.
Instance Method Summary collapse
-
#close ⇒ void
Close volume file.
-
#initialize(path, volume_number:, is_last: false) ⇒ VolumeWriter
constructor
Initialize volume writer.
-
#open ⇒ void
Open volume file for writing.
-
#write {|writer| ... } ⇒ void
Write with automatic open/close.
-
#write_end_header ⇒ void
Write End header with volume flags.
-
#write_file_data(file_header, compressed_data) ⇒ void
Write file data (header + compressed data).
-
#write_main_header ⇒ void
Write Main header with volume flags.
-
#write_signature ⇒ void
Write RAR5 signature.
Constructor Details
#initialize(path, volume_number:, is_last: false) ⇒ VolumeWriter
Initialize volume writer
47 48 49 50 51 52 |
# File 'lib/omnizip/formats/rar/rar5/multi_volume/volume_writer.rb', line 47 def initialize(path, volume_number:, is_last: false) @path = path @volume_number = volume_number @is_last = is_last @io = nil end |
Instance Attribute Details
#io ⇒ IO (readonly)
Returns File handle.
40 41 42 |
# File 'lib/omnizip/formats/rar/rar5/multi_volume/volume_writer.rb', line 40 def io @io end |
#is_last ⇒ Boolean (readonly)
Returns Is this the last volume?.
37 38 39 |
# File 'lib/omnizip/formats/rar/rar5/multi_volume/volume_writer.rb', line 37 def is_last @is_last end |
#path ⇒ String (readonly)
Returns Volume file path.
31 32 33 |
# File 'lib/omnizip/formats/rar/rar5/multi_volume/volume_writer.rb', line 31 def path @path end |
#volume_number ⇒ Integer (readonly)
Returns Volume number (1-based).
34 35 36 |
# File 'lib/omnizip/formats/rar/rar5/multi_volume/volume_writer.rb', line 34 def volume_number @volume_number end |
Class Method Details
.volume_filename(base_path, volume_number, naming: "part") ⇒ String
Generate volume filename from base name
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 |
# File 'lib/omnizip/formats/rar/rar5/multi_volume/volume_writer.rb', line 158 def self.volume_filename(base_path, volume_number, naming: "part") dir = File.dirname(base_path) basename = File.basename(base_path, ".*") ext = File.extname(base_path) volume_name = case naming when "part" "#{basename}.part#{volume_number}#{ext}" when "volume" "#{basename}.vol#{volume_number}#{ext}" when "numeric" # Simple numeric suffix: archive.rar, archive.r00, archive.r01, etc. if volume_number == 1 "#{basename}#{ext}" else # Volume 2 => r00, Volume 3 => r01, etc. "#{basename}.r#{format('%02d', volume_number - 2)}" end else "#{basename}.part#{volume_number}#{ext}" end # Handle relative vs absolute paths if dir == "." volume_name else File.join(dir, volume_name) end end |
Instance Method Details
#close ⇒ void
This method returns an undefined value.
Close volume file
64 65 66 67 |
# File 'lib/omnizip/formats/rar/rar5/multi_volume/volume_writer.rb', line 64 def close @io&.close @io = nil end |
#open ⇒ void
This method returns an undefined value.
Open volume file for writing
57 58 59 |
# File 'lib/omnizip/formats/rar/rar5/multi_volume/volume_writer.rb', line 57 def open @io = File.open(@path, "wb") end |
#write {|writer| ... } ⇒ void
This method returns an undefined value.
Write with automatic open/close
73 74 75 76 77 78 |
# File 'lib/omnizip/formats/rar/rar5/multi_volume/volume_writer.rb', line 73 def write open yield self ensure close end |
#write_end_header ⇒ void
This method returns an undefined value.
Write End header with volume flags
135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 |
# File 'lib/omnizip/formats/rar/rar5/multi_volume/volume_writer.rb', line 135 def write_end_header raise "Volume not open" unless @io # Set END_OF_ARCHIVE flags flags = 0 flags | VOLUME_END_FLAG unless @is_last # EndHeader always encodes the plain END_OF_ARCHIVE # marker: the RAR5 spec makes the volume flag optional, # readers position the marker inside the volume # sequence, and the omnizip-rs reference (read-side) # carries no writer-side volume-flag encoding to port. header = EndHeader.new @io.write(header.encode) end |
#write_file_data(file_header, compressed_data) ⇒ void
This method returns an undefined value.
Write file data (header + compressed data)
125 126 127 128 129 130 |
# File 'lib/omnizip/formats/rar/rar5/multi_volume/volume_writer.rb', line 125 def write_file_data(file_header, compressed_data) raise "Volume not open" unless @io @io.write(file_header.encode) @io.write(compressed_data) end |
#write_main_header ⇒ void
This method returns an undefined value.
Write Main header with volume flags
95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 |
# File 'lib/omnizip/formats/rar/rar5/multi_volume/volume_writer.rb', line 95 def write_main_header raise "Volume not open" unless @io # Set volume-specific flags flags = VOLUME_ARCHIVE_FLAG # Add volume number in extra area for volumes 2+ nil if @volume_number > 1 flags |= VOLUME_NUMBER_FLAG # Volume number as VINT in extra area VINT.encode(@volume_number).pack("C*") end header = MainHeader.new(flags: flags) # Extra areas are not written: MainHeader does not # model them and the omnizip-rs reference implements # RAR5 reading only, so there is no writer-side spec # to port. Volumes work without extras (the field is # optional). @io.write(header.encode) end |
#write_signature ⇒ void
This method returns an undefined value.
Write RAR5 signature
83 84 85 86 87 88 89 90 |
# File 'lib/omnizip/formats/rar/rar5/multi_volume/volume_writer.rb', line 83 def write_signature raise "Volume not open" unless @io # RAR5 signature: "Rar!\x1A\x07\x01\x00" signature = [0x52, 0x61, 0x72, 0x21, 0x1A, 0x07, 0x01, 0x00].pack("C*") @io.write(signature) end |