Class: Omnizip::Formats::Rar::Rar5::Writer

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

Overview

RAR5 format writer

This class creates RAR5 archives with STORE or LZMA compression. Supports single-file archives, multi-volume archives, solid compression, AES-256-CBC encryption, and PAR2 recovery records.

Examples:

Create single archive with STORE compression

writer = Writer.new('archive.rar')
writer.add_file('test.txt')
writer.write

Create archive with LZMA compression

writer = Writer.new('archive.rar', compression: :lzma, level: 5)
writer.add_file('test.txt')
writer.write

Create solid archive

writer = Writer.new('archive.rar', compression: :lzma, level: 5, solid: true)
writer.add_directory('project/')
writer.write

Create encrypted archive

writer = Writer.new('archive.rar',
  compression: :lzma,
  password: 'SecurePass123!',
  kdf_iterations: 262_144
)
writer.add_file('confidential.pdf')
writer.write

Create multi-volume archive

writer = Writer.new('archive.rar',
  multi_volume: true,
  volume_size: '10M',
  compression: :lzma
)
writer.add_file('largefile.dat')
writer.write  # Returns: ['archive.part1.rar', 'archive.part2.rar', ...]

Constant Summary collapse

RAR5_SIGNATURE =

RAR5 signature: "Rar!\x1A\x07\x01\x00"

[0x52, 0x61, 0x72, 0x21, 0x1A, 0x07, 0x01,
0x00].pack("C*")
AUTO_COMPRESS_THRESHOLD =

Threshold for automatic compression selection (1 KB)

1024

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(path, options = {}) ⇒ Writer

Initialize RAR5 writer

Parameters:

  • path (String)

    Output RAR file path

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

    Archive options

Options Hash (options):

  • :compression (Symbol)

    Compression method (:store, :lzma, :auto)

  • :level (Integer)

    LZMA compression level (1-5, default: 3)

  • :include_mtime (Boolean)

    Include modification time in file headers (default: false)

  • :include_crc32 (Boolean)

    Include CRC32 checksum in file headers (default: false)

  • :solid (Boolean)

    Enable solid compression (default: false)

  • :password (String)

    Password for encryption (default: nil)

  • :kdf_iterations (Integer)

    PBKDF2 iterations for encryption (default: 262,144)

  • :recovery (Boolean)

    Enable PAR2 recovery records (default: false)

  • :recovery_percent (Integer)

    Redundancy percentage for PAR2 (default: 5)

  • :multi_volume (Boolean)

    Enable multi-volume archive (default: false)

  • :volume_size (Integer, String)

    Maximum volume size (e.g., "10M", 10485760)

  • :volume_naming (String)

    Volume naming pattern ("part", "volume", "numeric")



75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
# File 'lib/omnizip/formats/rar/rar5/writer.rb', line 75

def initialize(path, options = {})
  @path = path
  @options = {
    compression: :store,
    level: 3,
    include_mtime: false,
    include_crc32: false,
    solid: false,
    password: nil,
    kdf_iterations: 262_144,
    recovery: false,
    recovery_percent: 5,
    multi_volume: false,
    volume_size: nil,
    volume_naming: "part",
  }.merge(options)
  @files = []

  # Initialize encryption manager if password provided (and not empty)
  @encryption_manager = if @options[:password] && !@options[:password].empty?
                          Encryption::EncryptionManager.new(
                            @options[:password],
                            kdf_iterations: @options[:kdf_iterations],
                          )
                        end
end

Instance Attribute Details

#optionsHash (readonly)

Returns Archive options.

Returns:

  • (Hash)

    Archive options



57
58
59
# File 'lib/omnizip/formats/rar/rar5/writer.rb', line 57

def options
  @options
end

#pathString (readonly)

Returns Output archive path.

Returns:

  • (String)

    Output archive path



54
55
56
# File 'lib/omnizip/formats/rar/rar5/writer.rb', line 54

def path
  @path
end

Instance Method Details

#add_directory(dir_path, base_path = nil) ⇒ void

This method returns an undefined value.

Add directory recursively

Parameters:

  • dir_path (String)

    Directory path

  • base_path (String, nil) (defaults to: nil)

    Base path for relative names



129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
# File 'lib/omnizip/formats/rar/rar5/writer.rb', line 129

def add_directory(dir_path, base_path = nil)
  unless File.directory?(dir_path)
    raise ArgumentError,
          "Directory not found: #{dir_path}"
  end

  base_path ||= dir_path

  Dir.glob(File.join(dir_path, "**", "*")).each do |path|
    next unless File.file?(path)

    relative_path = path.sub(
      /^#{Regexp.escape(base_path)}#{File::SEPARATOR}?/, ""
    )
    add_file(path, relative_path)
  end
end

#add_file(input_path, archive_path = nil) ⇒ Object

Add file to archive

Parameters:

  • input_path (String)

    Path to file on disk

  • archive_path (String, nil) (defaults to: nil)

    Path within archive (defaults to basename)

Raises:

  • (ArgumentError)

    if file does not exist



107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
# File 'lib/omnizip/formats/rar/rar5/writer.rb', line 107

def add_file(input_path, archive_path = nil)
  unless File.exist?(input_path)
    raise ArgumentError,
          "File not found: #{input_path}"
  end

  archive_path ||= File.basename(input_path)

  # Store file with metadata
  @files << {
    input: input_path,
    archive: archive_path,
    mtime: File.mtime(input_path),
    stat: File.stat(input_path),
  }
end

#writeString+

Write archive to disk

For single archives, returns the archive path or array of paths (with PAR2). For multi-volume archives, returns an array of volume paths.

Returns:

  • (String, Array<String>)

    Path(s) to created archive(s) and PAR2 files



153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
# File 'lib/omnizip/formats/rar/rar5/writer.rb', line 153

def write
  archive_paths = if @options[:multi_volume]
                    write_multi_volume
                  else
                    write_single_archive
                    [@path]
                  end

  # Generate PAR2 recovery files if requested
  if @options[:recovery]
    par2_paths = generate_recovery_files(archive_paths)
    return archive_paths + par2_paths
  end

  @options[:multi_volume] ? archive_paths : archive_paths.first
end