Class: Omnizip::Formats::Xar::Toc
- Inherits:
-
Object
- Object
- Omnizip::Formats::Xar::Toc
- Includes:
- Constants
- Defined in:
- lib/omnizip/formats/xar/toc.rb
Overview
XAR Table of Contents (TOC) parser and builder
The TOC is a GZIP-compressed XML document that contains:
- Archive metadata (creation time, checksum info)
- File hierarchy with metadata for each entry
- Data offsets and sizes in the heap
- Extended attributes
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
-
#checksum_offset ⇒ Object
Returns the value of attribute checksum_offset.
-
#checksum_size ⇒ Object
Returns the value of attribute checksum_size.
-
#checksum_style ⇒ Object
Returns the value of attribute checksum_style.
-
#creation_time ⇒ Object
Returns the value of attribute creation_time.
-
#entries ⇒ Object
readonly
Returns the value of attribute entries.
Class Method Summary collapse
-
.decompress(compressed_data, expected_size = nil) ⇒ String
Decompress TOC data.
-
.from_xml(xml_doc) ⇒ Toc
Parse TOC from XML document.
-
.parse(compressed_data, uncompressed_size = nil) ⇒ Toc
Parse TOC from compressed data.
Instance Method Summary collapse
-
#add_entry(entry) ⇒ Entry
Add entry to TOC.
-
#compress ⇒ String
Compress TOC XML.
-
#find_entry(name) ⇒ Entry?
Find entry by name.
-
#find_entry_by_id(id) ⇒ Entry?
Find entry by ID.
-
#initialize ⇒ Toc
constructor
Initialize TOC.
-
#next_id ⇒ Integer
Get next available ID.
-
#to_xml ⇒ REML::Document
Generate XML document.
-
#to_xml_string ⇒ String
Generate XML string.
-
#uncompressed_size ⇒ Integer
Get uncompressed size.
Constructor Details
#initialize ⇒ Toc
Initialize TOC
98 99 100 101 102 103 104 105 |
# File 'lib/omnizip/formats/xar/toc.rb', line 98 def initialize @creation_time = Time.now @entries = [] @checksum_offset = 0 @checksum_size = 0 @checksum_style = DEFAULT_TOC_CHECKSUM @next_id = 1 end |
Instance Attribute Details
#checksum_offset ⇒ Object
Returns the value of attribute checksum_offset.
21 22 23 |
# File 'lib/omnizip/formats/xar/toc.rb', line 21 def checksum_offset @checksum_offset end |
#checksum_size ⇒ Object
Returns the value of attribute checksum_size.
21 22 23 |
# File 'lib/omnizip/formats/xar/toc.rb', line 21 def checksum_size @checksum_size end |
#checksum_style ⇒ Object
Returns the value of attribute checksum_style.
21 22 23 |
# File 'lib/omnizip/formats/xar/toc.rb', line 21 def checksum_style @checksum_style end |
#creation_time ⇒ Object
Returns the value of attribute creation_time.
21 22 23 |
# File 'lib/omnizip/formats/xar/toc.rb', line 21 def creation_time @creation_time end |
#entries ⇒ Object (readonly)
Returns the value of attribute entries.
23 24 25 |
# File 'lib/omnizip/formats/xar/toc.rb', line 23 def entries @entries end |
Class Method Details
.decompress(compressed_data, expected_size = nil) ⇒ String
Decompress TOC data
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
# File 'lib/omnizip/formats/xar/toc.rb', line 41 def self.decompress(compressed_data, expected_size = nil) # XAR TOC is zlib compressed (with zlib headers, 0x78xx) # Try zlib format first (most common), then fall back to raw deflate result = begin # Try standard zlib format (with header) Zlib::Inflate.inflate(compressed_data) rescue Zlib::DataError # Fall back to raw deflate for non-conforming implementations Zlib::Inflate.new(-Zlib::MAX_WBITS).inflate(compressed_data) end if expected_size && result.bytesize != expected_size raise ArgumentError, "TOC size mismatch: #{result.bytesize} != #{expected_size}" end result end |
.from_xml(xml_doc) ⇒ Toc
Parse TOC from XML document
64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 |
# File 'lib/omnizip/formats/xar/toc.rb', line 64 def self.from_xml(xml_doc) toc = new root = xml_doc.root return toc unless root&.name == "xar" toc_element = root.elements["toc"] return toc unless toc_element # Parse creation time if (ctime = toc_element.elements["creation-time"]&.text) toc.creation_time = (ctime) end # Parse checksum info if (checksum = toc_element.elements["checksum"]) toc.checksum_style = checksum.attributes["style"] || "sha1" toc.checksum_offset = checksum.elements["offset"]&.text.to_i toc.checksum_size = checksum.elements["size"]&.text.to_i end # Parse file entries toc_element.elements.each("file") do |file_elem| entry = parse_file_element(file_elem) toc.add_entry(entry) # Parse nested files (subdirectories) parse_nested_files(file_elem, entry, toc) end toc end |
.parse(compressed_data, uncompressed_size = nil) ⇒ Toc
Parse TOC from compressed data
30 31 32 33 34 |
# File 'lib/omnizip/formats/xar/toc.rb', line 30 def self.parse(compressed_data, uncompressed_size = nil) uncompressed = decompress(compressed_data, uncompressed_size) xml_doc = REXML::Document.new(uncompressed) from_xml(xml_doc) end |
Instance Method Details
#add_entry(entry) ⇒ Entry
Add entry to TOC
113 114 115 116 117 118 |
# File 'lib/omnizip/formats/xar/toc.rb', line 113 def add_entry(entry) entry.id ||= @next_id @next_id = [@next_id, entry.id + 1].max @entries << entry entry end |
#compress ⇒ String
Compress TOC XML
184 185 186 187 188 189 190 191 |
# File 'lib/omnizip/formats/xar/toc.rb', line 184 def compress xml = to_xml_string zlib = Zlib::Deflate.new(Zlib::DEFAULT_COMPRESSION, -Zlib::MAX_WBITS) result = zlib.deflate(xml, Zlib::FINISH) zlib.close result end |
#find_entry(name) ⇒ Entry?
Find entry by name
131 132 133 |
# File 'lib/omnizip/formats/xar/toc.rb', line 131 def find_entry(name) @entries.find { |e| e.name == name } end |
#find_entry_by_id(id) ⇒ Entry?
Find entry by ID
139 140 141 |
# File 'lib/omnizip/formats/xar/toc.rb', line 139 def find_entry_by_id(id) @entries.find { |e| e.id == id } end |
#next_id ⇒ Integer
Get next available ID
123 124 125 |
# File 'lib/omnizip/formats/xar/toc.rb', line 123 def next_id @next_id end |
#to_xml ⇒ REML::Document
Generate XML document
146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 |
# File 'lib/omnizip/formats/xar/toc.rb', line 146 def to_xml doc = REXML::Document.new doc.add(REXML::XMLDecl.new("1.0", "UTF-8")) root = doc.add_element("xar") toc_element = root.add_element("toc") # Add creation time ctime_elem = toc_element.add_element("creation-time") ctime_elem.add_text(@creation_time.to_f.to_s) # Add checksum info checksum_elem = toc_element.add_element("checksum") checksum_elem.add_attribute("style", @checksum_style) offset_elem = checksum_elem.add_element("offset") offset_elem.add_text(@checksum_offset.to_s) size_elem = checksum_elem.add_element("size") size_elem.add_text(@checksum_size.to_s) # Add file entries build_file_tree(toc_element) doc end |
#to_xml_string ⇒ String
Generate XML string
174 175 176 177 178 179 |
# File 'lib/omnizip/formats/xar/toc.rb', line 174 def to_xml_string output = +"" doc = to_xml doc.write(output: output, indent: 2) output end |
#uncompressed_size ⇒ Integer
Get uncompressed size
196 197 198 |
# File 'lib/omnizip/formats/xar/toc.rb', line 196 def uncompressed_size to_xml_string.bytesize end |