Class: Omnizip::Formats::Xar::Reader
- Inherits:
-
Object
- Object
- Omnizip::Formats::Xar::Reader
- Includes:
- Constants
- Defined in:
- lib/omnizip/formats/xar/reader.rb
Overview
XAR archive reader
Provides read access to XAR archives with support for:
- Multiple compression algorithms (gzip, bzip2, lzma, xz, none)
- Checksum verification
- Extended attributes
- Hardlinks and symlinks
Constant Summary
Constants included from Constants
Constants::CHECKSUM_ALGORITHMS, Constants::CHECKSUM_NAMES, Constants::CHECKSUM_SIZES, Constants::CKSUM_MD5, Constants::CKSUM_NONE, Constants::CKSUM_OTHER, Constants::CKSUM_SHA1, Constants::COMPRESSION_BZIP2, Constants::COMPRESSION_GZIP, Constants::COMPRESSION_LZMA, Constants::COMPRESSION_MIME_TYPES, Constants::COMPRESSION_NONE, Constants::COMPRESSION_XZ, Constants::DEFAULT_COMPRESSION, Constants::DEFAULT_COMPRESSION_LEVEL, Constants::DEFAULT_FILE_CHECKSUM, Constants::DEFAULT_TOC_CHECKSUM, Constants::HEADER_CKSUM_ALG_OFFSET, Constants::HEADER_MAGIC_OFFSET, Constants::HEADER_SIZE, Constants::HEADER_SIZE_EX, Constants::HEADER_SIZE_OFFSET, Constants::HEADER_TOC_COMPRESSED_OFFSET, Constants::HEADER_TOC_UNCOMPRESSED_OFFSET, Constants::HEADER_VERSION_OFFSET, Constants::MAGIC, Constants::MAGIC_BYTES, Constants::MAX_PATH_LENGTH, Constants::MIME_TYPE_TO_COMPRESSION, Constants::TOC_XML_DECLARATION, Constants::TYPE_BLOCK, Constants::TYPE_CHAR, Constants::TYPE_DIRECTORY, Constants::TYPE_FIFO, Constants::TYPE_FILE, Constants::TYPE_HARDLINK, Constants::TYPE_SOCKET, Constants::TYPE_SYMLINK, Constants::XAR_VERSION
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.
-
#toc ⇒ Object
readonly
Returns the value of attribute toc.
Class Method Summary collapse
-
.extract(file_path, output_dir) ⇒ Object
Extract XAR archive to directory.
-
.list(file_path) ⇒ Array<Entry>
Read and list entries from XAR archive.
-
.open(file_path) ⇒ Reader
Open a XAR archive for reading.
Instance Method Summary collapse
-
#close ⇒ Object
Close the archive.
-
#extract_all(output_dir) ⇒ Object
Extract all entries to directory.
-
#extract_entry(entry, output_dir) ⇒ Object
Extract single entry to directory.
-
#get_entry(name) ⇒ Entry?
Get entry by name.
-
#info ⇒ Hash
Get archive information.
-
#initialize(file_path) ⇒ Reader
constructor
Initialize reader.
-
#list ⇒ Array<Entry>
Get all entries.
-
#open ⇒ Reader
Open and parse the archive.
-
#open? ⇒ Boolean
Check if archive is open.
-
#read_data(entry) ⇒ String?
Read entry data.
Constructor Details
#initialize(file_path) ⇒ Reader
Initialize reader
61 62 63 64 65 66 67 68 |
# File 'lib/omnizip/formats/xar/reader.rb', line 61 def initialize(file_path) @file_path = file_path @file = nil @header = nil @toc = nil @entries = [] @heap_offset = 0 end |
Instance Attribute Details
#entries ⇒ Object (readonly)
Returns the value of attribute entries.
19 20 21 |
# File 'lib/omnizip/formats/xar/reader.rb', line 19 def entries @entries end |
#file_path ⇒ Object (readonly)
Returns the value of attribute file_path.
19 20 21 |
# File 'lib/omnizip/formats/xar/reader.rb', line 19 def file_path @file_path end |
#header ⇒ Object (readonly)
Returns the value of attribute header.
19 20 21 |
# File 'lib/omnizip/formats/xar/reader.rb', line 19 def header @header end |
#toc ⇒ Object (readonly)
Returns the value of attribute toc.
19 20 21 |
# File 'lib/omnizip/formats/xar/reader.rb', line 19 def toc @toc end |
Class Method Details
.extract(file_path, output_dir) ⇒ Object
Extract XAR archive to directory
52 53 54 55 56 |
# File 'lib/omnizip/formats/xar/reader.rb', line 52 def self.extract(file_path, output_dir) open(file_path) do |reader| # rubocop:disable Security/Open reader.extract_all(output_dir) end end |
.list(file_path) ⇒ Array<Entry>
Read and list entries from XAR archive
44 45 46 |
# File 'lib/omnizip/formats/xar/reader.rb', line 44 def self.list(file_path) open(file_path, &:entries) # rubocop:disable Security/Open end |
.open(file_path) ⇒ Reader
Open a XAR archive for reading
25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
# File 'lib/omnizip/formats/xar/reader.rb', line 25 def self.open(file_path) reader = new(file_path) reader.open if block_given? begin yield reader ensure reader.close end else reader end end |
Instance Method Details
#close ⇒ Object
Close the archive
81 82 83 84 |
# File 'lib/omnizip/formats/xar/reader.rb', line 81 def close @file&.close @file = nil end |
#extract_all(output_dir) ⇒ Object
Extract all entries to directory
128 129 130 131 132 133 134 135 136 137 138 139 |
# File 'lib/omnizip/formats/xar/reader.rb', line 128 def extract_all(output_dir) FileUtils.mkdir_p(output_dir) # Sort entries to ensure directories are created first sorted_entries = @entries.sort_by do |e| [e.directory? ? 0 : 1, e.name] end sorted_entries.each do |entry| extract_entry(entry, output_dir) end end |
#extract_entry(entry, output_dir) ⇒ Object
Extract single entry to directory
145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 |
# File 'lib/omnizip/formats/xar/reader.rb', line 145 def extract_entry(entry, output_dir) full_path = File.join(output_dir, entry.name) case entry.type when TYPE_DIRECTORY FileUtils.mkdir_p(full_path) when TYPE_SYMLINK extract_symlink(entry, full_path) when TYPE_HARDLINK extract_hardlink(entry, full_path, output_dir) when TYPE_FILE extract_file(entry, full_path) when TYPE_BLOCK, TYPE_CHAR extract_device(entry, full_path) when TYPE_FIFO extract_fifo(entry, full_path) else # Unknown type, try to extract as file extract_file(entry, full_path) if entry.data_size&.positive? end # Set file metadata (entry, full_path) end |
#get_entry(name) ⇒ Entry?
Get entry by name
104 105 106 |
# File 'lib/omnizip/formats/xar/reader.rb', line 104 def get_entry(name) @entries.find { |e| e.name == name } end |
#info ⇒ Hash
Get archive information
173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 |
# File 'lib/omnizip/formats/xar/reader.rb', line 173 def info { file_path: @file_path, header: { version: @header&.version, checksum_algorithm: @header&.checksum_algorithm_name, toc_compressed_size: @header&.toc_compressed_size, toc_uncompressed_size: @header&.toc_uncompressed_size, }, entry_count: @entries.size, file_count: @entries.count(&:file?), directory_count: @entries.count(&:directory?), symlink_count: @entries.count(&:symlink?), total_size: @entries.sum { |e| e.size || 0 }, } end |
#list ⇒ Array<Entry>
Get all entries
96 97 98 |
# File 'lib/omnizip/formats/xar/reader.rb', line 96 def list @entries end |
#open ⇒ Reader
Open and parse the archive
73 74 75 76 77 78 |
# File 'lib/omnizip/formats/xar/reader.rb', line 73 def open @file = File.open(@file_path, "rb") read_header read_toc self end |
#open? ⇒ Boolean
Check if archive is open
89 90 91 |
# File 'lib/omnizip/formats/xar/reader.rb', line 89 def open? !@file.nil? end |
#read_data(entry) ⇒ String?
Read entry data
112 113 114 115 116 117 118 119 120 121 122 123 |
# File 'lib/omnizip/formats/xar/reader.rb', line 112 def read_data(entry) return nil unless entry.data_length&.positive? return nil unless @file @file.seek(@heap_offset + entry.data_offset) # In XAR format: # - data_length is the compressed (archived) size (what to read from heap) # - data_size is the uncompressed (extracted) size (decompressed size) compressed_data = @file.read(entry.data_length) decompress_data(compressed_data, entry.data_encoding, entry.data_size) end |