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, parsing on first use — a Reader is always usable; #open remains for eager loading.
-
#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 32 |
# 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 = {} @opened = false 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)
178 179 180 |
# File 'lib/omnizip/formats/seven_zip/reader.rb', line 178 def can_decrypt? encrypted? && !@password.nil? end |
#encrypted? ⇒ Boolean
Check if headers are encrypted
171 172 173 |
# File 'lib/omnizip/formats/seven_zip/reader.rb', line 171 def encrypted? !@encrypted_header.nil? end |
#extract_all(output_dir) ⇒ Object
Extract all files to directory
138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 |
# File 'lib/omnizip/formats/seven_zip/reader.rb', line 138 def extract_all(output_dir) ensure_open 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
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 129 130 131 132 |
# File 'lib/omnizip/formats/seven_zip/reader.rb', line 97 def extract_entry(entry_name, output_path) ensure_open # 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.
189 190 191 |
# File 'lib/omnizip/formats/seven_zip/reader.rb', line 189 def extract_entry_data(io, entry) extract_entry_data_private(io, entry) end |
#list_files ⇒ Array<Models::FileEntry>
List all files in archive, parsing on first use — a Reader is always usable; #open remains for eager loading
87 88 89 90 |
# File 'lib/omnizip/formats/seven_zip/reader.rb', line 87 def list_files ensure_open @entries.reject { |e| e.name.nil? || e.name.empty? } end |
#open ⇒ Object
Open and parse .7z archive
37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
# File 'lib/omnizip/formats/seven_zip/reader.rb', line 37 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
58 59 60 |
# File 'lib/omnizip/formats/seven_zip/reader.rb', line 58 def split? @split_reader&.split? || false end |
#total_volumes ⇒ Integer
Get total number of volumes (for split archives)
65 66 67 |
# File 'lib/omnizip/formats/seven_zip/reader.rb', line 65 def total_volumes @split_reader&.total_volumes || 1 end |
#valid? ⇒ Boolean
Check if archive is valid .7z format
164 165 166 |
# File 'lib/omnizip/formats/seven_zip/reader.rb', line 164 def valid? !@header.nil? && @header.valid? end |
#volume_size ⇒ Integer
Get volume size (for split archives)
72 73 74 |
# File 'lib/omnizip/formats/seven_zip/reader.rb', line 72 def volume_size @split_reader&.volume_size || File.size(@file_path) end |
#volumes ⇒ Array<String>
Get list of volumes (for split archives)
79 80 81 |
# File 'lib/omnizip/formats/seven_zip/reader.rb', line 79 def volumes @split_reader&.volumes || [@file_path] end |