Class: Omnizip::Formats::SevenZip::Reader
- Inherits:
-
Object
- Object
- Omnizip::Formats::SevenZip::Reader
- Includes:
- Constants
- Defined in:
- lib/omnizip/formats/seven_zip/reader.rb
Overview
.7z archive reader Provides read-only access to .7z archives
Constant Summary
Constants included from Constants
Constants::MAJOR_VERSION, Constants::MAX_NUM_BONDS, Constants::MAX_NUM_CODERS, Constants::MAX_NUM_PACK_STREAMS, Constants::MINOR_VERSION, Constants::SIGNATURE, Constants::SIGNATURE_SIZE, Constants::START_HEADER_SIZE
Instance Attribute Summary collapse
-
#entries ⇒ Object
readonly
Returns the value of attribute entries.
-
#file_path ⇒ Object
readonly
Returns the value of attribute file_path.
-
#header ⇒ Object
readonly
Returns the value of attribute header.
-
#split_reader ⇒ Object
readonly
Returns the value of attribute split_reader.
-
#stream_info ⇒ Object
readonly
Returns the value of attribute stream_info.
Instance Method Summary collapse
-
#can_decrypt? ⇒ Boolean
Check if can decrypt headers (password provided).
-
#encrypted? ⇒ Boolean
Check if headers are encrypted.
-
#extract_all(output_dir) ⇒ Object
Extract all files to directory.
-
#extract_entry(entry_name, output_path) ⇒ Object
Extract file to output path.
-
#extract_entry_data(io, entry) ⇒ String
Extract raw entry payload from the archive.
-
#initialize(file_path, options = {}) ⇒ Reader
constructor
Initialize reader with file path.
-
#list_files ⇒ Array<Models::FileEntry>
List all files in archive.
-
#open ⇒ Object
Open and parse .7z archive.
-
#split? ⇒ Boolean
Check if archive is split.
-
#total_volumes ⇒ Integer
Get total number of volumes (for split archives).
-
#valid? ⇒ Boolean
Check if archive is valid .7z format.
-
#volume_size ⇒ Integer
Get volume size (for split archives).
-
#volumes ⇒ Array<String>
Get list of volumes (for split archives).
Constructor Details
#initialize(file_path, options = {}) ⇒ Reader
Initialize reader with file path
22 23 24 25 26 27 28 29 30 31 |
# File 'lib/omnizip/formats/seven_zip/reader.rb', line 22 def initialize(file_path, = {}) @file_path = file_path @entries = [] @stream_info = nil @split_reader = nil @password = [:password] @offset = [:offset] || 0 @solid_cache = {} @solid_cache_extracted = {} end |
Instance Attribute Details
#entries ⇒ Object (readonly)
Returns the value of attribute entries.
14 15 16 |
# File 'lib/omnizip/formats/seven_zip/reader.rb', line 14 def entries @entries end |
#file_path ⇒ Object (readonly)
Returns the value of attribute file_path.
14 15 16 |
# File 'lib/omnizip/formats/seven_zip/reader.rb', line 14 def file_path @file_path end |
#header ⇒ Object (readonly)
Returns the value of attribute header.
14 15 16 |
# File 'lib/omnizip/formats/seven_zip/reader.rb', line 14 def header @header end |
#split_reader ⇒ Object (readonly)
Returns the value of attribute split_reader.
14 15 16 |
# File 'lib/omnizip/formats/seven_zip/reader.rb', line 14 def split_reader @split_reader end |
#stream_info ⇒ Object (readonly)
Returns the value of attribute stream_info.
14 15 16 |
# File 'lib/omnizip/formats/seven_zip/reader.rb', line 14 def stream_info @stream_info end |
Instance Method Details
#can_decrypt? ⇒ Boolean
Check if can decrypt headers (password provided)
173 174 175 |
# File 'lib/omnizip/formats/seven_zip/reader.rb', line 173 def can_decrypt? encrypted? && !@password.nil? end |
#encrypted? ⇒ Boolean
Check if headers are encrypted
166 167 168 |
# File 'lib/omnizip/formats/seven_zip/reader.rb', line 166 def encrypted? !@encrypted_header.nil? end |
#extract_all(output_dir) ⇒ Object
Extract all files to directory
134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 |
# File 'lib/omnizip/formats/seven_zip/reader.rb', line 134 def extract_all(output_dir) FileUtils.mkdir_p(output_dir) real_out = File.realpath(output_dir) @entries.each do |entry| next if entry.name.nil? || entry.name.empty? output_path = File.join(real_out, entry.name) = File.(output_path) unless .start_with?("#{real_out}#{File::SEPARATOR}") || == real_out raise Omnizip::FormatError, "Path traversal detected: #{entry.name}" end extract_entry(entry.name, output_path) end ensure @solid_cache.clear @solid_cache_extracted.clear end |
#extract_entry(entry_name, output_path) ⇒ Object
Extract file to output path
94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 |
# File 'lib/omnizip/formats/seven_zip/reader.rb', line 94 def extract_entry(entry_name, output_path) # Delegate to split reader if available if @split_reader @split_reader.extract_entry(entry_name, output_path) return end entry = @entries.find { |e| e.name == entry_name } raise "Entry not found: #{entry_name}" unless entry # Create directory if needed FileUtils.mkdir_p(File.dirname(output_path)) # Extract file if entry.directory? FileUtils.mkdir_p(output_path) elsif entry.has_stream? File.open(@file_path, "rb") do |io| # Seek to offset for embedded archives io.seek(@offset) if @offset.positive? data = extract_entry_data(io, entry) File.binwrite(output_path, data) end # Set timestamp if available if entry.mtime File.utime(entry.atime || entry.mtime || Time.now, entry.mtime || Time.now, output_path) end else # Empty file FileUtils.touch(output_path) end end |
#extract_entry_data(io, entry) ⇒ String
Extract raw entry payload from the archive. Public so converters and parallel extractors can reuse the stream-positioning + decompression logic.
184 185 186 |
# File 'lib/omnizip/formats/seven_zip/reader.rb', line 184 def extract_entry_data(io, entry) extract_entry_data_private(io, entry) end |
#list_files ⇒ Array<Models::FileEntry>
List all files in archive
85 86 87 |
# File 'lib/omnizip/formats/seven_zip/reader.rb', line 85 def list_files @entries.reject { |e| e.name.nil? || e.name.empty? } end |
#open ⇒ Object
Open and parse .7z archive
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
# File 'lib/omnizip/formats/seven_zip/reader.rb', line 36 def open # Check if this is a split archive if split_archive? @split_reader = SplitArchiveReader.new(@file_path) @split_reader.open @header = @split_reader.header @entries = @split_reader.entries @stream_info = @split_reader.stream_info else File.open(@file_path, "rb") do |io| # Seek to offset for embedded archives io.seek(@offset) if @offset.positive? parse_archive(io) end end self end |
#split? ⇒ Boolean
Check if archive is split
57 58 59 |
# File 'lib/omnizip/formats/seven_zip/reader.rb', line 57 def split? @split_reader&.split? || false end |
#total_volumes ⇒ Integer
Get total number of volumes (for split archives)
64 65 66 |
# File 'lib/omnizip/formats/seven_zip/reader.rb', line 64 def total_volumes @split_reader&.total_volumes || 1 end |
#valid? ⇒ Boolean
Check if archive is valid .7z format
159 160 161 |
# File 'lib/omnizip/formats/seven_zip/reader.rb', line 159 def valid? !@header.nil? && @header.valid? end |
#volume_size ⇒ Integer
Get volume size (for split archives)
71 72 73 |
# File 'lib/omnizip/formats/seven_zip/reader.rb', line 71 def volume_size @split_reader&.volume_size || File.size(@file_path) end |
#volumes ⇒ Array<String>
Get list of volumes (for split archives)
78 79 80 |
# File 'lib/omnizip/formats/seven_zip/reader.rb', line 78 def volumes @split_reader&.volumes || [@file_path] end |