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
63 64 65 66 67 68 69 70 |
# File 'lib/omnizip/formats/xar/reader.rb', line 63 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.
21 22 23 |
# File 'lib/omnizip/formats/xar/reader.rb', line 21 def entries @entries end |
#file_path ⇒ Object (readonly)
Returns the value of attribute file_path.
21 22 23 |
# File 'lib/omnizip/formats/xar/reader.rb', line 21 def file_path @file_path end |
#header ⇒ Object (readonly)
Returns the value of attribute header.
21 22 23 |
# File 'lib/omnizip/formats/xar/reader.rb', line 21 def header @header end |
#toc ⇒ Object (readonly)
Returns the value of attribute toc.
21 22 23 |
# File 'lib/omnizip/formats/xar/reader.rb', line 21 def toc @toc end |
Class Method Details
.extract(file_path, output_dir) ⇒ Object
Extract XAR archive to directory
54 55 56 57 58 |
# File 'lib/omnizip/formats/xar/reader.rb', line 54 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
46 47 48 |
# File 'lib/omnizip/formats/xar/reader.rb', line 46 def self.list(file_path) open(file_path, &:entries) # rubocop:disable Security/Open end |
.open(file_path) ⇒ Reader
Open a XAR archive for reading
27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
# File 'lib/omnizip/formats/xar/reader.rb', line 27 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
83 84 85 86 |
# File 'lib/omnizip/formats/xar/reader.rb', line 83 def close @file&.close @file = nil end |
#extract_all(output_dir) ⇒ Object
Extract all entries to directory
130 131 132 133 134 135 136 137 138 139 140 141 |
# File 'lib/omnizip/formats/xar/reader.rb', line 130 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
147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 |
# File 'lib/omnizip/formats/xar/reader.rb', line 147 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
106 107 108 |
# File 'lib/omnizip/formats/xar/reader.rb', line 106 def get_entry(name) @entries.find { |e| e.name == name } end |
#info ⇒ Hash
Get archive information
175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 |
# File 'lib/omnizip/formats/xar/reader.rb', line 175 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
98 99 100 |
# File 'lib/omnizip/formats/xar/reader.rb', line 98 def list @entries end |
#open ⇒ Reader
Open and parse the archive
75 76 77 78 79 80 |
# File 'lib/omnizip/formats/xar/reader.rb', line 75 def open @file = File.open(@file_path, "rb") read_header read_toc self end |
#open? ⇒ Boolean
Check if archive is open
91 92 93 |
# File 'lib/omnizip/formats/xar/reader.rb', line 91 def open? !@file.nil? end |
#read_data(entry) ⇒ String?
Read entry data
114 115 116 117 118 119 120 121 122 123 124 125 |
# File 'lib/omnizip/formats/xar/reader.rb', line 114 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 |