Class: OpenUSD::Format::Usdz::Reader
- Inherits:
-
Object
- Object
- OpenUSD::Format::Usdz::Reader
- Defined in:
- lib/openusd/format/usdz/reader.rb
Overview
Reads and validates the constrained ZIP representation used by USDZ.
Defined Under Namespace
Classes: Entry
Constant Summary collapse
- PACKAGE_URI =
Virtual identifier for an entry inside a package.
/\A(.+\.usdz)\[([^\]]+)\]\z/i- LOCAL_SIGNATURE =
ZIP local-file-header signature.
0x04034B50- CENTRAL_SIGNATURE =
ZIP central-directory-entry signature.
0x02014B50- END_SIGNATURE =
ZIP end-of-central-directory signature.
0x06054B50
Instance Attribute Summary collapse
-
#path ⇒ Object
readonly
Returns the value of attribute path.
Class Method Summary collapse
-
.parse_layer(package_path, root) ⇒ Layer
Parse a validated package entry as USDA.
-
.parse_uri(uri) ⇒ Array(String, String)
Split a virtual package URI.
-
.read(path) ⇒ Layer
Read the default layer from a package.
-
.read_uri(uri) ⇒ Layer
Read a layer identified by a virtual package URI.
-
.unpack(path, destination:) ⇒ Array<String>
Extract a validated package.
Instance Method Summary collapse
-
#entries ⇒ Array<Entry>
Validated entries in archive order.
-
#entry(name) ⇒ Entry?
Find an entry by its exact package path.
-
#extract(destination) ⇒ Array<String>
Securely extract all entries below a destination.
-
#initialize(path) ⇒ Reader
constructor
A new instance of Reader.
Constructor Details
#initialize(path) ⇒ Reader
Returns a new instance of Reader.
76 77 78 79 80 81 82 |
# File 'lib/openusd/format/usdz/reader.rb', line 76 def initialize(path) @path = File.(path) @archive = File.binread(@path) @entries = nil rescue Errno::ENOENT raise PackageError, "package not found: #{path}" end |
Instance Attribute Details
#path ⇒ Object (readonly)
Returns the value of attribute path.
74 75 76 |
# File 'lib/openusd/format/usdz/reader.rb', line 74 def path @path end |
Class Method Details
.parse_layer(package_path, root) ⇒ Layer
Parse a validated package entry as USDA.
56 57 58 59 60 61 62 63 64 65 |
# File 'lib/openusd/format/usdz/reader.rb', line 56 def parse_layer(package_path, root) extension = File.extname(root.name).downcase raise NotSupportedError, "USDC root layers are not supported" if extension == ".usdc" raise PackageError, "first USDZ entry must be a native USD layer" unless %w[.usd .usda].include?(extension) layer = Format::Usda::Parser.parse(root.data.dup.force_encoding(Encoding::UTF_8), file: "#{package_path}[#{root.name}]") layer.identifier = "#{File.(package_path)}[#{root.name}]" layer end |
.parse_uri(uri) ⇒ Array(String, String)
Split a virtual package URI.
47 48 49 50 51 52 |
# File 'lib/openusd/format/usdz/reader.rb', line 47 def parse_uri(uri) match = PACKAGE_URI.match(uri.to_s) raise PackageError, "invalid package URI: #{uri}" unless match [File.(match[1]), match[2]] end |
.read(path) ⇒ Layer
Read the default layer from a package.
26 27 28 29 30 31 32 |
# File 'lib/openusd/format/usdz/reader.rb', line 26 def read(path) package = new(path) root = package.entries.first raise PackageError, "USDZ package is empty" unless root parse_layer(package.path, root) end |
.read_uri(uri) ⇒ Layer
Read a layer identified by a virtual package URI.
36 37 38 39 40 41 42 43 |
# File 'lib/openusd/format/usdz/reader.rb', line 36 def read_uri(uri) package_path, entry_name = parse_uri(uri) package = new(package_path) entry = package.entry(entry_name) raise PackageError, "package entry not found: #{entry_name}" unless entry parse_layer(package.path, entry) end |
.unpack(path, destination:) ⇒ Array<String>
Extract a validated package.
69 70 71 |
# File 'lib/openusd/format/usdz/reader.rb', line 69 def unpack(path, destination:) new(path).extract(destination) end |
Instance Method Details
#entries ⇒ Array<Entry>
Returns validated entries in archive order.
85 86 87 |
# File 'lib/openusd/format/usdz/reader.rb', line 85 def entries @entries ||= parse_entries.freeze end |
#entry(name) ⇒ Entry?
Find an entry by its exact package path.
91 92 93 |
# File 'lib/openusd/format/usdz/reader.rb', line 91 def entry(name) entries.find { |candidate| candidate.name == name.to_s } end |
#extract(destination) ⇒ Array<String>
Securely extract all entries below a destination.
97 98 99 100 101 102 103 104 105 106 107 108 109 |
# File 'lib/openusd/format/usdz/reader.rb', line 97 def extract(destination) root = File.(destination) entries.each do |entry| output = File.(entry.name, root) unless output.start_with?("#{root}#{File::SEPARATOR}") raise PackageError, "unsafe package entry: #{entry.name.inspect}" end FileUtils.mkdir_p(File.dirname(output)) File.binwrite(output, entry.data) end entries.map(&:name) end |