julik-depix 1.0.2 → 1.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/History.txt +6 -1
- data/Manifest.txt +4 -0
- data/README.txt +18 -4
- data/bin/depix-describe +14 -3
- data/lib/depix/benchmark.rb +15 -0
- data/lib/depix/dict.rb +127 -2
- data/lib/depix/editor.rb +32 -0
- data/lib/depix/reader.rb +83 -0
- data/lib/depix/structs.rb +16 -7
- data/lib/depix.rb +25 -76
- data/test/test_depix.rb +39 -2
- data/test/test_dict.rb +210 -19
- metadata +6 -3
data/History.txt
CHANGED
data/Manifest.txt
CHANGED
@@ -7,9 +7,13 @@ bin/depix-describe
|
|
7
7
|
lib/depix.rb
|
8
8
|
lib/depix/struct_explainer.rb
|
9
9
|
lib/depix/structs.rb
|
10
|
+
lib/depix/benchmark.rb
|
10
11
|
lib/depix/compact_structs.rb
|
11
12
|
lib/depix/enums.rb
|
12
13
|
lib/depix/dict.rb
|
14
|
+
lib/depix/reader.rb
|
15
|
+
lib/depix/editor.rb
|
16
|
+
test/test_dict.rb
|
13
17
|
test/test_depix.rb
|
14
18
|
test/samples/E012_P001_L000002_lin.0001.dpx
|
15
19
|
test/samples/E012_P001_L000002_lin.0002.dpx
|
data/README.txt
CHANGED
@@ -4,12 +4,22 @@
|
|
4
4
|
|
5
5
|
== DESCRIPTION:
|
6
6
|
|
7
|
-
Read DPX file metadata
|
7
|
+
Read and write DPX file metadata
|
8
8
|
|
9
9
|
== SYNOPSIS:
|
10
10
|
|
11
|
+
Reading headers
|
12
|
+
|
11
13
|
meta = Depix.from_file(dpx_file_path)
|
12
14
|
puts meta.time_code #=> 10:00:00:02
|
15
|
+
|
16
|
+
Writing headers
|
17
|
+
|
18
|
+
editor = Depix::Editor.new(dpx_file_path)
|
19
|
+
|
20
|
+
# Advance the time code by one frame and save
|
21
|
+
editor.headers.time_code = editor.headers.time_code + 1
|
22
|
+
editor.commit!
|
13
23
|
|
14
24
|
The data returned is described in the DPX_HEADER_STRUCTURE[link:files/DPX_HEADER_STRUCTURE_txt.html]. It's
|
15
25
|
a vanilla Ruby object with no extra methods except for the readers that have the same name as the specified
|
@@ -19,11 +29,15 @@ The gem also contains an executable called depix-desribe which can be used from
|
|
19
29
|
|
20
30
|
$book depix-describe 001_PTAPE_001.001.dpx
|
21
31
|
|
22
|
-
|
32
|
+
for a long description or
|
33
|
+
|
34
|
+
$book depix-describe -s 001_PTAPE_001.001.dpx
|
23
35
|
|
24
|
-
|
36
|
+
for a short description
|
37
|
+
|
38
|
+
== NOTES:
|
25
39
|
|
26
|
-
Autodesk IFFS systems write the reel name for the file to the orientation.device field
|
40
|
+
Autodesk IFFS systems write the reel name for the file to the orientation.device field, some scanners write it into user data.
|
27
41
|
|
28
42
|
== REQUIREMENTS:
|
29
43
|
|
data/bin/depix-describe
CHANGED
@@ -10,13 +10,24 @@ OptionParser.new do |opts|
|
|
10
10
|
opts.on("-c", "--compact", "Compact output (only fields that change per frame)") do |v|
|
11
11
|
options[:compact] = true
|
12
12
|
end
|
13
|
+
|
14
|
+
opts.on("-s", "--synthetics", "Output only synthetic fields (like time code and aspect)") do |v|
|
15
|
+
options[:synthetics] = true
|
16
|
+
end
|
17
|
+
|
13
18
|
end.parse!
|
14
19
|
|
15
20
|
ARGV.each do | file |
|
16
|
-
puts "Describing DPX #{file}. Empty elements are omitted
|
17
|
-
puts "===================================================\n
|
21
|
+
puts "Describing DPX #{file}. Empty elements are omitted."
|
22
|
+
puts "===================================================\n"
|
18
23
|
begin
|
19
|
-
|
24
|
+
if options[:synthetics]
|
25
|
+
puts Depix.describe_brief(file)
|
26
|
+
elsif options[:compact]
|
27
|
+
puts Depix.describe_file(file, true)
|
28
|
+
else
|
29
|
+
puts Depix.describe_file(file)
|
30
|
+
end
|
20
31
|
rescue Depix::InvalidHeader
|
21
32
|
puts " - Invalid header data"
|
22
33
|
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../depix'
|
2
|
+
|
3
|
+
require 'benchmark'
|
4
|
+
|
5
|
+
iter = 10000
|
6
|
+
|
7
|
+
puts "Reading DPX header #{iter} times, all data"
|
8
|
+
puts Benchmark.measure {
|
9
|
+
iter.times { Depix.from_file(File.dirname(__FILE__)+"/../../test/samples/026_FROM_HERO_TAPE_5-3-1_MOV.0029.dpx", false) }
|
10
|
+
}
|
11
|
+
|
12
|
+
puts "Reading DPX header #{iter} times, compact data"
|
13
|
+
puts Benchmark.measure {
|
14
|
+
iter.times { Depix.from_file(File.dirname(__FILE__)+"/../../test/samples/026_FROM_HERO_TAPE_5-3-1_MOV.0029.dpx", true) }
|
15
|
+
}
|
data/lib/depix/dict.rb
CHANGED
@@ -50,6 +50,26 @@ module Depix
|
|
50
50
|
def consume!(stack)
|
51
51
|
clean(stack.shift)
|
52
52
|
end
|
53
|
+
|
54
|
+
# Check that the passed value:
|
55
|
+
# a) Matches the Ruby type expected
|
56
|
+
# b) Fits into the slot
|
57
|
+
# c) Does not overflow
|
58
|
+
# When the validation fails should raise
|
59
|
+
def validate!(value)
|
60
|
+
raise "#{name} value required, but got nil in #{name}".strip if value.nil? && req?
|
61
|
+
raise "Value expected to be #{rtype} but was #{value.class}" if !value.nil? && rtype && !value.is_a?(rtype)
|
62
|
+
end
|
63
|
+
|
64
|
+
# Pack a value passed into a string
|
65
|
+
def pack(value)
|
66
|
+
raise "No pattern defined for #{self}" unless pattern
|
67
|
+
if value.nil?
|
68
|
+
[self.class.const_get(:BLANK)].pack(pattern)
|
69
|
+
else
|
70
|
+
[value].pack(pattern)
|
71
|
+
end
|
72
|
+
end
|
53
73
|
end
|
54
74
|
|
55
75
|
class U32Field < Field
|
@@ -67,6 +87,14 @@ module Depix
|
|
67
87
|
def clean(value)
|
68
88
|
value == BLANK ? nil : value
|
69
89
|
end
|
90
|
+
|
91
|
+
# Override - might be Bignum although cast to Integer sometimes
|
92
|
+
def validate!(value)
|
93
|
+
raise "#{name} value required, but got nil".strip if value.nil? && req?
|
94
|
+
raise "#{name} value expected to be #{rtype} but was #{value.class}" if !value.nil? && (!value.is_a?(Integer) && !value.is_a?(Bignum))
|
95
|
+
raise "#{name} value #{value} overflows" if !value.nil? && (value < 0 || value >= BLANK)
|
96
|
+
end
|
97
|
+
|
70
98
|
end
|
71
99
|
|
72
100
|
class U8Field < Field
|
@@ -87,7 +115,12 @@ module Depix
|
|
87
115
|
end
|
88
116
|
|
89
117
|
def clean(v)
|
90
|
-
v == BLANK ? nil : v
|
118
|
+
(v == BLANK || v == -1) ? nil : v
|
119
|
+
end
|
120
|
+
|
121
|
+
def validate!(value)
|
122
|
+
super(value)
|
123
|
+
raise "#{name} value #{value} out of bounds for 8 bit unsigned int".lstrip if (!value.nil? && (value < 0 || value >= BLANK))
|
91
124
|
end
|
92
125
|
end
|
93
126
|
|
@@ -101,6 +134,10 @@ module Depix
|
|
101
134
|
def consume(stack)
|
102
135
|
nil
|
103
136
|
end
|
137
|
+
|
138
|
+
def pack(data)
|
139
|
+
raise "This is a filler, it cannot be reconstructed from a value"
|
140
|
+
end
|
104
141
|
end
|
105
142
|
|
106
143
|
class U16Field < Field
|
@@ -122,10 +159,16 @@ module Depix
|
|
122
159
|
def clean(v)
|
123
160
|
v == BLANK ? nil : v
|
124
161
|
end
|
162
|
+
|
163
|
+
def validate!(value)
|
164
|
+
super(value)
|
165
|
+
raise "#{name} value #{value} out of bounds for 16bit unsigned int" if (value < 0 || value >= BLANK)
|
166
|
+
end
|
125
167
|
end
|
126
168
|
|
127
169
|
class R32Field < Field
|
128
170
|
undef :length=, :pattern=
|
171
|
+
BLANK = 0xFFFFFFFF
|
129
172
|
|
130
173
|
def pattern
|
131
174
|
"g"
|
@@ -169,6 +212,15 @@ module Depix
|
|
169
212
|
def rtype
|
170
213
|
String
|
171
214
|
end
|
215
|
+
|
216
|
+
def validate!(value)
|
217
|
+
super(value)
|
218
|
+
raise "#{value} overflows the #{length} bytes allocated" if !value.nil? && value.length > length
|
219
|
+
end
|
220
|
+
|
221
|
+
def pack(value)
|
222
|
+
value.ljust(length, "\000") rescue ("\000" * length)
|
223
|
+
end
|
172
224
|
end
|
173
225
|
|
174
226
|
# Wrapper for an array structure
|
@@ -198,6 +250,27 @@ module Depix
|
|
198
250
|
r = (req? ? "- required" : nil)
|
199
251
|
[tpl, desc, r].compact.join(' ')
|
200
252
|
end
|
253
|
+
|
254
|
+
def validate!(array)
|
255
|
+
raise "This value would overflow, #{array.length} elements passed but only #{members.length} fit" unless array.length <= members.length
|
256
|
+
raise "This value is required, but the array is empty" if req? && array.empty?
|
257
|
+
array.zip(members).map do | v, m |
|
258
|
+
m.validate!(v) unless (v.nil? && !m.req?)
|
259
|
+
end
|
260
|
+
end
|
261
|
+
|
262
|
+
def pack(values)
|
263
|
+
# For members that are present, get values. For members that are missing, fill with null bytes upto length.
|
264
|
+
# For values that are nil, skip packing
|
265
|
+
members.zip(values).map do |m, v|
|
266
|
+
if !m.req? && v.nil?
|
267
|
+
raise "#{m} needs to provide length" unless m.length
|
268
|
+
"\377" * m.length
|
269
|
+
else
|
270
|
+
v.respond_to?(:pack) ? v.pack : m.pack(v)
|
271
|
+
end
|
272
|
+
end.join
|
273
|
+
end
|
201
274
|
end
|
202
275
|
|
203
276
|
# Wrapper for a contained structure
|
@@ -220,6 +293,15 @@ module Depix
|
|
220
293
|
def rtype
|
221
294
|
cast
|
222
295
|
end
|
296
|
+
|
297
|
+
def validate!(value)
|
298
|
+
super(value)
|
299
|
+
cast.validate!(value) if cast.respond_to?(:validate!) && (!value.nil? || req?)
|
300
|
+
end
|
301
|
+
|
302
|
+
def pack(value)
|
303
|
+
cast.pack(value)
|
304
|
+
end
|
223
305
|
end
|
224
306
|
|
225
307
|
# Base class for a struct. Could also be implemented as a module actually
|
@@ -232,7 +314,14 @@ module Depix
|
|
232
314
|
def fields
|
233
315
|
@fields ||= []
|
234
316
|
end
|
235
|
-
|
317
|
+
|
318
|
+
# Validate a passed instance
|
319
|
+
def validate!(instance)
|
320
|
+
fields.each do | f |
|
321
|
+
f.validate!(instance.send(f.name)) if f.name
|
322
|
+
end
|
323
|
+
end
|
324
|
+
|
236
325
|
# Define a 4-byte unsigned integer
|
237
326
|
def u32(name, *extras)
|
238
327
|
count, opts = count_and_opts_from(extras)
|
@@ -273,6 +362,7 @@ module Depix
|
|
273
362
|
else
|
274
363
|
[Field.send("emit_#{mapped_to}")] * count
|
275
364
|
end
|
365
|
+
yield a.members if block_given?
|
276
366
|
fields << a
|
277
367
|
end
|
278
368
|
|
@@ -343,6 +433,41 @@ module Depix
|
|
343
433
|
only([])
|
344
434
|
end
|
345
435
|
|
436
|
+
# Pack the instance of this struct
|
437
|
+
def pack(instance, buffer = nil)
|
438
|
+
|
439
|
+
# Preallocate a buffer just as big as me since we want everything to remain at fixed offsets
|
440
|
+
buffer ||= ("\000" * length)
|
441
|
+
|
442
|
+
# If the instance is nil return pure padding
|
443
|
+
return buffer if instance.nil?
|
444
|
+
|
445
|
+
# Now for the important stuff. For each field that we have, replace a piece at offsets in the buffer
|
446
|
+
# with the packed results, skipping fillers
|
447
|
+
fields.each_with_index do | f, i |
|
448
|
+
|
449
|
+
# Skip blanking, we just dont touch it. TODO - test!
|
450
|
+
next if f.is_a?(Filler)
|
451
|
+
|
452
|
+
# Where should we put that value?
|
453
|
+
offset = fields[0...i].inject(0){|_, s| _ + s.length }
|
454
|
+
|
455
|
+
val = instance.send(f.name)
|
456
|
+
|
457
|
+
# Validate the passed value using the format the field supports
|
458
|
+
f.validate!(val)
|
459
|
+
|
460
|
+
packed = f.pack(val)
|
461
|
+
|
462
|
+
# Signal offset violation
|
463
|
+
raise "Improper length for #{f.name} - packed #{packed.length} bytes but #{f.length} is required to fill the slot" if packed.length != f.length
|
464
|
+
|
465
|
+
buffer[offset...(offset+f.length)] = packed
|
466
|
+
end
|
467
|
+
raise "Resulting buffer not the same length, expected #{length} bytes but compued #{buffer.length}" if buffer.length != length
|
468
|
+
buffer
|
469
|
+
end
|
470
|
+
|
346
471
|
private
|
347
472
|
|
348
473
|
# extract_options! on a diet
|
data/lib/depix/editor.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
module Depix
|
2
|
+
# Used to edit DPX headers. Create an Editor object and pass the path to the file to it. Change the headers variable to contain the edited
|
3
|
+
# DPX headers and call commit!. Note that the DPX header will be overwritten in place - if you want to save another version you need to manage it yourself
|
4
|
+
class Editor
|
5
|
+
|
6
|
+
# Stores the path to file
|
7
|
+
attr_reader :path
|
8
|
+
|
9
|
+
# Stores the Depix::DPX object with headers
|
10
|
+
attr_accessor :headers
|
11
|
+
|
12
|
+
# Create a new editor for the file at path
|
13
|
+
def initialize(file_path)
|
14
|
+
@path = file_path
|
15
|
+
@headers = Depix.from_file(@path)
|
16
|
+
end
|
17
|
+
|
18
|
+
# Save the headers to file at path, overwriting the old ones
|
19
|
+
def commit!
|
20
|
+
raise "No headers" unless @headers
|
21
|
+
raise "Cannot pack LE headers" if @headers.le?
|
22
|
+
packed = @headers.class.pack(@headers)
|
23
|
+
|
24
|
+
# Validate that we can unpack first - what if something went wrong?
|
25
|
+
Depix::Reader.new.parse(packed, false)
|
26
|
+
|
27
|
+
File.open(@path, 'rb+') do | f |
|
28
|
+
f.seek(0, IO::SEEK_SET); f.write(packed)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
data/lib/depix/reader.rb
ADDED
@@ -0,0 +1,83 @@
|
|
1
|
+
module Depix
|
2
|
+
class Reader
|
3
|
+
|
4
|
+
# Returns a printable report on all the headers present in the file at the path passed
|
5
|
+
def describe_file(path, compact = false)
|
6
|
+
header = File.open(path, 'r') { |f| f.read(DPX.length) }
|
7
|
+
struct = parse(header, false)
|
8
|
+
describe_struct(struct) + describe_synthetics_of_struct(struct)
|
9
|
+
end
|
10
|
+
|
11
|
+
def describe_synthetics_of_struct(struct)
|
12
|
+
Synthetics.instance_methods.reject{|m| m.include?('=')}.map do | m |
|
13
|
+
[m, struct.send(m)].join(' : ')
|
14
|
+
end.unshift("============").unshift("\nSynthetic properties").join("\n")
|
15
|
+
end
|
16
|
+
|
17
|
+
def from_file(path, compact)
|
18
|
+
header = File.open(path, 'r') { |f| f.read(DPX.length) }
|
19
|
+
begin
|
20
|
+
parse(header, compact)
|
21
|
+
rescue InvalidHeader => e
|
22
|
+
raise InvalidHeader, "Invalid header in file #{path} - #{e.message}"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# The hear of Depix
|
27
|
+
def parse(data, compact)
|
28
|
+
magic = data[0..3]
|
29
|
+
|
30
|
+
raise InvalidHeader, "No magic bytes found at start" unless %w( SDPX XPDS).include?(magic)
|
31
|
+
|
32
|
+
struct = compact ? CompactDPX : DPX
|
33
|
+
|
34
|
+
is_be = (magic == "SDPX")
|
35
|
+
version_check = FileInfo.only(:magic, :version)
|
36
|
+
|
37
|
+
result = begin
|
38
|
+
if is_be
|
39
|
+
version_check.consume!(data.unpack(version_check.pattern))
|
40
|
+
else
|
41
|
+
version_check.consume!(data.unpack(make_le(version_check.pattern)))
|
42
|
+
end
|
43
|
+
rescue ArgumentError
|
44
|
+
raise InvalidHeader
|
45
|
+
end
|
46
|
+
|
47
|
+
raise InvalidHeader, "Unknown version tag #{result.version}" unless result.version == "V1.0"
|
48
|
+
|
49
|
+
template = is_be ? DPX.pattern : make_le(DPX.pattern)
|
50
|
+
struct.consume!(data.unpack(struct.pattern))
|
51
|
+
end
|
52
|
+
|
53
|
+
# Describe a filled DPX structure
|
54
|
+
def describe_struct(result, pad_offset = 0)
|
55
|
+
result.class.fields.inject([]) do | info, field |
|
56
|
+
value = result.send(field.name)
|
57
|
+
parts = []
|
58
|
+
if value
|
59
|
+
parts << field.desc if field.desc
|
60
|
+
parts << if field.is_a?(InnerField)
|
61
|
+
describe_struct(value, pad_offset + 1)
|
62
|
+
elsif field.is_a?(ArrayField)
|
63
|
+
# Exception for image elements
|
64
|
+
value = result.image_elements[0...result.number_elements] if field.name == :image_elements
|
65
|
+
value.map { | v | v.is_a?(Dict) ? describe_struct(v, pad_offset + 2) : v }
|
66
|
+
else
|
67
|
+
value
|
68
|
+
end
|
69
|
+
end
|
70
|
+
if parts.any?
|
71
|
+
info << parts.join(' ')
|
72
|
+
end
|
73
|
+
info
|
74
|
+
end.map{|e| (' ' * pad_offset) + e }.join("\n")
|
75
|
+
end
|
76
|
+
|
77
|
+
# Convert an unpack pattern to LE
|
78
|
+
def make_le(pattern)
|
79
|
+
pattern.gsub(/n/, "v").gsub(/N/, "V").gsub(/g/, "f")
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
83
|
+
end
|
data/lib/depix/structs.rb
CHANGED
@@ -121,17 +121,26 @@ module Depix
|
|
121
121
|
|
122
122
|
u32 :pixels_per_line, :desc => 'Pixels per horizontal line', :req => true
|
123
123
|
u32 :lines_per_element, :desc => 'Line count', :req => true
|
124
|
-
|
124
|
+
|
125
|
+
array :image_elements, ImageElement, 8, :desc => "Image elements" do | elements |
|
126
|
+
elements[0].req = true
|
127
|
+
end
|
128
|
+
|
125
129
|
char :reserve, 52
|
130
|
+
|
131
|
+
# Only expose the elements present
|
132
|
+
def image_elements #:nodoc:
|
133
|
+
@image_elements[0...number_elements]
|
134
|
+
end
|
126
135
|
end
|
127
136
|
|
128
137
|
#:include:DPX_HEADER_STRUCTURE.txt
|
129
138
|
class DPX < Dict
|
130
|
-
inner :file, FileInfo, :desc => "File information"
|
131
|
-
inner :image, ImageInfo, :desc => "Image information"
|
132
|
-
inner :orientation, OrientationInfo, :desc => "Orientation"
|
133
|
-
inner :film, FilmInfo, :desc => "Film industry info"
|
134
|
-
inner :television, TelevisionInfo, :desc => "TV industry info"
|
135
|
-
inner :user, UserInfo, :desc => "User info"
|
139
|
+
inner :file, FileInfo, :desc => "File information", :req => true
|
140
|
+
inner :image, ImageInfo, :desc => "Image information", :req => true
|
141
|
+
inner :orientation, OrientationInfo, :desc => "Orientation", :req => true
|
142
|
+
inner :film, FilmInfo, :desc => "Film industry info", :req => true
|
143
|
+
inner :television, TelevisionInfo, :desc => "TV industry info", :req => true
|
144
|
+
inner :user, UserInfo, :desc => "User info", :req => true
|
136
145
|
end
|
137
146
|
end
|
data/lib/depix.rb
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
require 'stringio'
|
2
1
|
require 'rubygems'
|
3
2
|
require 'timecode'
|
4
3
|
|
@@ -6,14 +5,18 @@ require File.dirname(__FILE__) + '/depix/dict'
|
|
6
5
|
require File.dirname(__FILE__) + '/depix/structs'
|
7
6
|
require File.dirname(__FILE__) + '/depix/compact_structs'
|
8
7
|
require File.dirname(__FILE__) + '/depix/enums'
|
8
|
+
require File.dirname(__FILE__) + '/depix/reader'
|
9
|
+
require File.dirname(__FILE__) + '/depix/editor'
|
10
|
+
|
9
11
|
|
10
12
|
module Depix
|
11
|
-
VERSION = '1.0.
|
13
|
+
VERSION = '1.0.4'
|
12
14
|
|
13
15
|
class InvalidHeader < RuntimeError; end
|
14
16
|
|
15
17
|
# Offers convenience access to a few common attributes bypassing the piecemeal structs
|
16
18
|
module Synthetics
|
19
|
+
|
17
20
|
def keycode
|
18
21
|
[film.id, film.type, film.offset, film.prefix, film.count].compact.join(' ')
|
19
22
|
end
|
@@ -21,13 +24,23 @@ module Depix
|
|
21
24
|
# Return the flame reel name. The data after the first null byte is not meant to be seen and is used by Flame internally
|
22
25
|
# as it seems
|
23
26
|
def flame_reel
|
24
|
-
orientation.device.split(
|
27
|
+
orientation.device.split(0x00.chr).shift
|
28
|
+
end
|
29
|
+
|
30
|
+
# Assign reel name
|
31
|
+
def flame_reel=(new_reel)
|
32
|
+
orientation.device = new_reel
|
25
33
|
end
|
26
34
|
|
27
35
|
def time_code
|
28
36
|
Timecode.from_uint(television.time_code) #, film.frame_rate)
|
29
37
|
end
|
30
38
|
|
39
|
+
# Assign frame rate and timecode from a Timecode object
|
40
|
+
def time_code=(new_tc)
|
41
|
+
television.time_code, film.frame_rate = new_tc.to_uint, new_tc.fps
|
42
|
+
end
|
43
|
+
|
31
44
|
# Get the name of the transfer function (Linear, Logarithmic, ...)
|
32
45
|
def colorimetric
|
33
46
|
COLORIMETRIC.invert[image.image_elements[0].colorimetric]
|
@@ -38,6 +51,11 @@ module Depix
|
|
38
51
|
COMPONENT_TYPE.invert[image.image_elements[0].descriptor]
|
39
52
|
end
|
40
53
|
|
54
|
+
# Aspect in it's traditional repr
|
55
|
+
def aspect
|
56
|
+
"%.2f" % (orientation.aspect_ratio[0].to_f / orientation.aspect_ratio[1].to_f)
|
57
|
+
end
|
58
|
+
|
41
59
|
# Is this DPX file little-endian? This would be an exception, but still useful
|
42
60
|
def le?
|
43
61
|
file.magic == 'XPDS'
|
@@ -65,78 +83,9 @@ module Depix
|
|
65
83
|
Reader.new.describe_file(path, compact)
|
66
84
|
end
|
67
85
|
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
def describe_file(path, compact = false)
|
72
|
-
header = File.open(path, 'r') { |f| f.read(DPX.length) }
|
73
|
-
describe_struct(parse(header, false))
|
74
|
-
end
|
75
|
-
|
76
|
-
def from_file(path, compact)
|
77
|
-
header = File.open(path, 'r') { |f| f.read(DPX.length) }
|
78
|
-
begin
|
79
|
-
parse(header, compact)
|
80
|
-
rescue InvalidHeader => e
|
81
|
-
raise InvalidHeader, "Invalid header in file #{path}"
|
82
|
-
end
|
83
|
-
end
|
84
|
-
|
85
|
-
# The hear of Depix
|
86
|
-
def parse(data, compact)
|
87
|
-
magic = data[0..3]
|
88
|
-
|
89
|
-
raise InvalidHeader unless %w( SDPX XPDS).include?(magic)
|
90
|
-
|
91
|
-
struct = compact ? CompactDPX : DPX
|
92
|
-
|
93
|
-
is_be = (magic == "SDPX")
|
94
|
-
version_check = FileInfo.only(:magic, :version)
|
95
|
-
|
96
|
-
result = begin
|
97
|
-
if is_be
|
98
|
-
version_check.consume!(data.unpack(version_check.pattern))
|
99
|
-
else
|
100
|
-
version_check.consume!(data.unpack(make_le(version_check.pattern)))
|
101
|
-
end
|
102
|
-
rescue ArgumentError
|
103
|
-
raise InvalidHeader
|
104
|
-
end
|
105
|
-
|
106
|
-
raise InvalidHeader unless result.version == "V1.0"
|
107
|
-
|
108
|
-
template = is_be ? DPX.pattern : make_le(DPX.pattern)
|
109
|
-
struct.consume!(data.unpack(struct.pattern))
|
110
|
-
end
|
111
|
-
|
112
|
-
# Describe a filled DPX structure
|
113
|
-
def describe_struct(result, pad_offset = 0)
|
114
|
-
result.class.fields.inject([]) do | info, field |
|
115
|
-
value = result.send(field.name)
|
116
|
-
parts = []
|
117
|
-
if value
|
118
|
-
parts << field.desc if field.desc
|
119
|
-
parts << if field.is_a?(InnerField)
|
120
|
-
describe_struct(value, pad_offset + 1)
|
121
|
-
elsif field.is_a?(ArrayField)
|
122
|
-
# Exception for image elements
|
123
|
-
value = result.image_elements[0...result.number_elements] if field.name == :image_elements
|
124
|
-
value.map { | v | v.is_a?(Dict) ? describe_struct(v, pad_offset + 2) : v }
|
125
|
-
else
|
126
|
-
value
|
127
|
-
end
|
128
|
-
end
|
129
|
-
if parts.any?
|
130
|
-
info << parts.join(' ')
|
131
|
-
end
|
132
|
-
info
|
133
|
-
end.map{|e| (' ' * pad_offset) + e }.join("\n")
|
134
|
-
end
|
135
|
-
|
136
|
-
# Convert an unpack pattern to LE
|
137
|
-
def make_le(pattern)
|
138
|
-
pattern.gsub(/n/, "v").gsub(/N/, "V").gsub(/g/, "f")
|
139
|
-
end
|
140
|
-
|
86
|
+
# Return a formatted description of the DPX file at path, showing only synthetic attributes
|
87
|
+
def self.describe_brief(path)
|
88
|
+
Reader.new.describe_synthetics_of_struct(from_file(path))
|
141
89
|
end
|
90
|
+
|
142
91
|
end
|
data/test/test_depix.rb
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
require File.dirname(__FILE__) + '/../lib/depix'
|
2
2
|
require 'test/unit'
|
3
3
|
|
4
|
+
SAMPLE_DPX = File.dirname(__FILE__) + '/samples/E012_P001_L000002_lin.0001.dpx'
|
5
|
+
|
4
6
|
class ReaderTest < Test::Unit::TestCase
|
5
7
|
|
6
|
-
SAMPLE_DPX = File.dirname(__FILE__) + '/samples/E012_P001_L000002_lin.0001.dpx'
|
7
|
-
|
8
8
|
def test_parsed_properly
|
9
9
|
file = SAMPLE_DPX
|
10
10
|
parsed = Depix.from_file(file)
|
@@ -69,6 +69,7 @@ class ReaderTest < Test::Unit::TestCase
|
|
69
69
|
assert_equal :RGB, parsed.component_type
|
70
70
|
assert_equal :Linear, parsed.colorimetric
|
71
71
|
assert_equal "E012", parsed.flame_reel
|
72
|
+
assert_equal "1.33", parsed.aspect
|
72
73
|
end
|
73
74
|
|
74
75
|
def test_parsed_properly_using_compact_structs
|
@@ -84,6 +85,17 @@ class ReaderTest < Test::Unit::TestCase
|
|
84
85
|
end
|
85
86
|
end
|
86
87
|
|
88
|
+
def test_packing
|
89
|
+
original_header = File.read(SAMPLE_DPX)[0...Depix::DPX.length]
|
90
|
+
|
91
|
+
assert_nothing_raised do
|
92
|
+
dpx = Depix.from_string(original_header)
|
93
|
+
packed = Depix::DPX.pack(dpx, original_header.dup)
|
94
|
+
|
95
|
+
dpx2 = Depix.from_string(packed)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
87
99
|
def test_parsing_something_else_should_raise
|
88
100
|
s = "Mary had a little lamb"
|
89
101
|
assert_raise(Depix::InvalidHeader) { Depix.from_string(s) }
|
@@ -95,4 +107,29 @@ class ReaderTest < Test::Unit::TestCase
|
|
95
107
|
assert_raise(Depix::InvalidHeader) { Depix.from_string(s) }
|
96
108
|
|
97
109
|
end
|
110
|
+
end
|
111
|
+
|
112
|
+
class EditorTest < Test::Unit::TestCase
|
113
|
+
def test_instantiation
|
114
|
+
e = Depix::Editor.new(SAMPLE_DPX)
|
115
|
+
assert_not_nil e
|
116
|
+
assert_equal SAMPLE_DPX, e.path
|
117
|
+
assert_not_nil e.headers
|
118
|
+
end
|
119
|
+
|
120
|
+
def test_commit
|
121
|
+
temp_path = SAMPLE_DPX + ".test"
|
122
|
+
begin
|
123
|
+
FileUtils.cp(SAMPLE_DPX, temp_path)
|
124
|
+
e = Depix::Editor.new(temp_path)
|
125
|
+
e.headers.orientation.device = "E013"
|
126
|
+
|
127
|
+
assert_nothing_raised { e.commit! }
|
128
|
+
|
129
|
+
re_read = Depix.from_file(temp_path)
|
130
|
+
assert_equal "E013", re_read.orientation.device
|
131
|
+
ensure
|
132
|
+
File.unlink(temp_path)
|
133
|
+
end
|
134
|
+
end
|
98
135
|
end
|
data/test/test_dict.rb
CHANGED
@@ -3,6 +3,28 @@ require 'test/unit'
|
|
3
3
|
|
4
4
|
include Depix
|
5
5
|
|
6
|
+
class BogusError < RuntimeError; end
|
7
|
+
|
8
|
+
class AlwaysInvalidField < Field
|
9
|
+
def validate!(value)
|
10
|
+
raise BogusError, "Never valid"
|
11
|
+
end
|
12
|
+
|
13
|
+
def pack(some_value)
|
14
|
+
raise BogusError, "Will not pack"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
class AlwaysInvalidStruct
|
19
|
+
def self.validate!(value)
|
20
|
+
raise BogusError, "Never valid"
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.pack(instance)
|
24
|
+
raise BogusError, "Will not pack"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
6
28
|
module FieldConformity
|
7
29
|
def conform_field!(f)
|
8
30
|
assert_respond_to f, :name
|
@@ -12,6 +34,8 @@ module FieldConformity
|
|
12
34
|
assert_respond_to f, :req?
|
13
35
|
assert_respond_to f, :rtype
|
14
36
|
assert_respond_to f, :explain
|
37
|
+
assert_respond_to f, :validate!
|
38
|
+
assert_respond_to f, :pack
|
15
39
|
end
|
16
40
|
|
17
41
|
def assert_method_removed(f, method)
|
@@ -99,24 +123,24 @@ class TestField < Test::Unit::TestCase
|
|
99
123
|
assert_equal [2,3], ar
|
100
124
|
end
|
101
125
|
|
102
|
-
def
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
end
|
107
|
-
end
|
108
|
-
|
109
|
-
f = InnerField.new :cast => catcher
|
110
|
-
assert_respond_to f, :consume!
|
126
|
+
def test_validate
|
127
|
+
f = Field.new
|
128
|
+
f.rtype = self.class
|
129
|
+
assert_nothing_raised { f.validate! nil }
|
111
130
|
|
112
|
-
assert_raise(RuntimeError) { f.
|
131
|
+
assert_raise(RuntimeError) { f.validate! "boo" }
|
132
|
+
assert_nothing_raised { f.validate! self }
|
113
133
|
end
|
114
134
|
|
115
|
-
def
|
116
|
-
f =
|
117
|
-
|
118
|
-
|
119
|
-
|
135
|
+
def test_validate_if_required
|
136
|
+
f = Field.new
|
137
|
+
f.req = true
|
138
|
+
assert_raise(RuntimeError) { f.validate! nil }
|
139
|
+
end
|
140
|
+
|
141
|
+
def test_pack_raises
|
142
|
+
f = Field.new
|
143
|
+
assert_raise(RuntimeError) { f.pack("foo")}
|
120
144
|
end
|
121
145
|
end
|
122
146
|
|
@@ -159,6 +183,59 @@ class TestArrayField < Test::Unit::TestCase
|
|
159
183
|
assert_equal 3, f.length
|
160
184
|
assert_equal "CC2", f.pattern
|
161
185
|
end
|
186
|
+
|
187
|
+
def test_consume
|
188
|
+
f = ArrayField.new :members => [Field.new, Field.new]
|
189
|
+
assert_respond_to f, :consume!
|
190
|
+
|
191
|
+
assert_equal [1,2], f.consume!([1,2])
|
192
|
+
end
|
193
|
+
|
194
|
+
def test_validate
|
195
|
+
f = ArrayField.new :members => [Field.new(:rtype => self.class)]
|
196
|
+
|
197
|
+
# Overflow
|
198
|
+
assert_raise(RuntimeError) { f.validate!([nil, nil]) }
|
199
|
+
|
200
|
+
# Just empty
|
201
|
+
assert_nothing_raised { f.validate!([]) }
|
202
|
+
|
203
|
+
# Nil vaue
|
204
|
+
assert_nothing_raised { f.validate!([nil]) }
|
205
|
+
|
206
|
+
# type cast
|
207
|
+
assert_raise(RuntimeError) { f.validate!(["nil"]) }
|
208
|
+
|
209
|
+
assert_nothing_raised { f.validate!([self]) }
|
210
|
+
end
|
211
|
+
|
212
|
+
def test_validate_fails_with_empty_array_and_required_field
|
213
|
+
f = ArrayField.new :members => [Field.new(:rtype => self.class)], :req => true
|
214
|
+
assert_raise(RuntimeError) { f.validate!([]) }
|
215
|
+
end
|
216
|
+
|
217
|
+
def test_validate_does_not_validate_inner_structure_if_no_value_present_and_field_is_not_required
|
218
|
+
f = ArrayField.new :members => [AlwaysInvalidField.new]
|
219
|
+
assert_nothing_raised { f.validate! [nil] }
|
220
|
+
end
|
221
|
+
|
222
|
+
|
223
|
+
def test_pack_tries_to_pack_inner_structures
|
224
|
+
f = ArrayField.new :members => [AlwaysInvalidField.new]
|
225
|
+
assert_raise(BogusError) { f.pack([1, 2]) }
|
226
|
+
end
|
227
|
+
|
228
|
+
def test_pack_pads_properly
|
229
|
+
f = ArrayField.new :members => [U32Field.new, R32Field.new, R32Field.new]
|
230
|
+
assert_equal "\000\000\000\001@\000\000\000\377\377\377\377", f.pack([1.0, 2.0])
|
231
|
+
assert_equal f.length, f.pack([1.0, 2.0]).length
|
232
|
+
end
|
233
|
+
|
234
|
+
def test_does_not_try_to_pack_nil_values
|
235
|
+
f = ArrayField.new(:members => [AlwaysInvalidField.new(:length => 2)])
|
236
|
+
assert_equal "\377\377", f.pack([])
|
237
|
+
end
|
238
|
+
|
162
239
|
end
|
163
240
|
|
164
241
|
class TestInnerField < Test::Unit::TestCase
|
@@ -194,6 +271,34 @@ class TestInnerField < Test::Unit::TestCase
|
|
194
271
|
casted = InnerField.new(:cast => c)
|
195
272
|
assert_equal c, casted.rtype
|
196
273
|
end
|
274
|
+
|
275
|
+
def test_consume
|
276
|
+
catcher = Class.new do
|
277
|
+
def self.consume!(arg)
|
278
|
+
raise RuntimeError if arg == ["julik"]
|
279
|
+
end
|
280
|
+
end
|
281
|
+
|
282
|
+
f = InnerField.new :cast => catcher
|
283
|
+
assert_respond_to f, :consume!
|
284
|
+
|
285
|
+
assert_raise(RuntimeError) { f.consume!(["julik"]) }
|
286
|
+
end
|
287
|
+
|
288
|
+
def test_validate_with_nil_and_no_requirement
|
289
|
+
f = InnerField.new :cast => AlwaysInvalidStruct, :req => true
|
290
|
+
assert_raise(RuntimeError) { f.validate!(nil) }
|
291
|
+
end
|
292
|
+
|
293
|
+
def test_validate
|
294
|
+
f = InnerField.new :cast => AlwaysInvalidStruct
|
295
|
+
assert_raise(BogusError) { f.validate!(AlwaysInvalidStruct.new) }
|
296
|
+
end
|
297
|
+
|
298
|
+
def test_pack_tries_to_pack_inner_structures
|
299
|
+
f = InnerField.new :cast => AlwaysInvalidStruct
|
300
|
+
assert_raise(BogusError) { f.pack(AlwaysInvalidStruct.new) }
|
301
|
+
end
|
197
302
|
end
|
198
303
|
|
199
304
|
class TestWideIntField < Test::Unit::TestCase
|
@@ -209,6 +314,23 @@ class TestWideIntField < Test::Unit::TestCase
|
|
209
314
|
assert_equal 66, f.clean(66)
|
210
315
|
assert_equal nil, f.clean(0xFFFFFFFF)
|
211
316
|
end
|
317
|
+
|
318
|
+
def test_validate
|
319
|
+
f = U32Field.new
|
320
|
+
|
321
|
+
assert_nothing_raised { f.validate! 8 }
|
322
|
+
assert_nothing_raised { f.validate! 0 }
|
323
|
+
assert_nothing_raised { f.validate! 65536 }
|
324
|
+
assert_raise(RuntimeError) { f.validate!(0xFFFFFFFF) }
|
325
|
+
assert_nothing_raised { f.validate!(0xFFFFFFFF - 1) }
|
326
|
+
|
327
|
+
end
|
328
|
+
|
329
|
+
def test_pack
|
330
|
+
w = U32Field.new
|
331
|
+
assert_equal "\000\000\000\036", w.pack(30)
|
332
|
+
assert_equal "\377\377\377\377", w.pack(nil)
|
333
|
+
end
|
212
334
|
end
|
213
335
|
|
214
336
|
class TestCharField < Test::Unit::TestCase
|
@@ -240,7 +362,25 @@ class TestCharField < Test::Unit::TestCase
|
|
240
362
|
assert_equal nil, f.clean("\0\0\0\0\0\0")
|
241
363
|
assert_equal nil, f.clean("\0\0\0\377\377\0\0\0")
|
242
364
|
assert_equal "foo\0foo", f.clean("\0\0foo\0foo\0")
|
243
|
-
|
365
|
+
end
|
366
|
+
|
367
|
+
def test_char_field_validates_overflow
|
368
|
+
f = CharField.new :length => 2
|
369
|
+
assert_raise(RuntimeError) { f.validate!("xxx")}
|
370
|
+
assert_nothing_raised { f.validate!("xx")}
|
371
|
+
assert_nothing_raised { f.validate!(nil)}
|
372
|
+
end
|
373
|
+
|
374
|
+
def test_char_field_validates_required_with_nil
|
375
|
+
f = CharField.new :length => 2, :req => true
|
376
|
+
assert_raise(RuntimeError) { f.validate!(nil)}
|
377
|
+
end
|
378
|
+
|
379
|
+
def test_char_field_packs
|
380
|
+
f = CharField.new(:length => 6)
|
381
|
+
assert_equal "xx\000\000\000\000", f.pack("xx")
|
382
|
+
assert_equal "\000\000\000\000\000\000", f.pack("")
|
383
|
+
assert_equal "\000\000\000\000\000\000", f.pack(nil)
|
244
384
|
end
|
245
385
|
end
|
246
386
|
|
@@ -261,6 +401,12 @@ class TestFloatField < Test::Unit::TestCase
|
|
261
401
|
assert_equal Float, f.rtype
|
262
402
|
assert_equal nil, f.clean(the_nan)
|
263
403
|
end
|
404
|
+
|
405
|
+
def test_pack
|
406
|
+
w = R32Field.new
|
407
|
+
assert_equal "@fff", w.pack(3.6)
|
408
|
+
assert_equal "O\200\000\000", w.pack(nil)
|
409
|
+
end
|
264
410
|
end
|
265
411
|
|
266
412
|
class TestSmallintField < Test::Unit::TestCase
|
@@ -272,7 +418,6 @@ class TestSmallintField < Test::Unit::TestCase
|
|
272
418
|
|
273
419
|
assert_method_removed(f, :pattern=)
|
274
420
|
assert_method_removed(f, :length=)
|
275
|
-
|
276
421
|
end
|
277
422
|
|
278
423
|
def test_smallint_operation
|
@@ -285,11 +430,18 @@ class TestSmallintField < Test::Unit::TestCase
|
|
285
430
|
|
286
431
|
def test_smallint_clean
|
287
432
|
f = U8Field.new
|
288
|
-
|
289
433
|
assert_equal nil, f.clean(0xFF)
|
290
434
|
assert_equal 10, f.clean(10)
|
291
435
|
end
|
292
436
|
|
437
|
+
def test_validate
|
438
|
+
f = U8Field.new
|
439
|
+
assert_nothing_raised { f.validate! 8 }
|
440
|
+
assert_nothing_raised { f.validate! 0 }
|
441
|
+
assert_raise(RuntimeError) { f.validate!( -1 ) }
|
442
|
+
assert_raise(RuntimeError) { f.validate!( 255) }
|
443
|
+
assert_raise(RuntimeError) { f.validate!( 256) }
|
444
|
+
end
|
293
445
|
end
|
294
446
|
|
295
447
|
class TestDoubleField < Test::Unit::TestCase
|
@@ -317,6 +469,15 @@ class TestDoubleField < Test::Unit::TestCase
|
|
317
469
|
assert_equal nil, f.clean(0xFFFF)
|
318
470
|
assert_equal 10, f.clean(10)
|
319
471
|
end
|
472
|
+
|
473
|
+
def test_validate
|
474
|
+
f = U16Field.new
|
475
|
+
assert_nothing_raised { f.validate! 8 }
|
476
|
+
assert_nothing_raised { f.validate! 0 }
|
477
|
+
assert_raise(RuntimeError) { f.validate!( -1) }
|
478
|
+
assert_raise(RuntimeError) { f.validate!( 65535) }
|
479
|
+
assert_raise(RuntimeError) { f.validate!( 65536) }
|
480
|
+
end
|
320
481
|
end
|
321
482
|
|
322
483
|
class TestFillerField < Test::Unit::TestCase
|
@@ -344,7 +505,10 @@ class TestFillerField < Test::Unit::TestCase
|
|
344
505
|
data.freeze
|
345
506
|
assert_nothing_raised { Filler.new(:length => 1).consume(data) }
|
346
507
|
end
|
347
|
-
|
508
|
+
|
509
|
+
def test_pack_raises
|
510
|
+
assert_raise(RuntimeError) { Filler.new(:length => 3).pack('xxx') }
|
511
|
+
end
|
348
512
|
end
|
349
513
|
|
350
514
|
class TestFieldEmit < Test::Unit::TestCase
|
@@ -401,6 +565,12 @@ class TestDict < Test::Unit::TestCase
|
|
401
565
|
assert_equal [], dict_class.fields
|
402
566
|
end
|
403
567
|
|
568
|
+
def test_dict_responds_to_validate
|
569
|
+
dict_class = Class.new(Dict)
|
570
|
+
assert_respond_to dict_class, :validate!
|
571
|
+
one = dict_class.new
|
572
|
+
end
|
573
|
+
|
404
574
|
def test_dict_fields_array_not_class_shared
|
405
575
|
d1, d2 = (0..1).map{|_| Class.new(Dict) }
|
406
576
|
|
@@ -434,7 +604,27 @@ class TestDict < Test::Unit::TestCase
|
|
434
604
|
assert_equal 'A1A1', c.pattern
|
435
605
|
assert_equal 2, c.length
|
436
606
|
end
|
607
|
+
|
608
|
+
def test_dict_does_not_validate_inner_nil
|
609
|
+
wrapper_class = Class.new(Dict) do
|
610
|
+
u32 :bigint
|
611
|
+
inner :invalid, AlwaysInvalidStruct
|
612
|
+
end
|
613
|
+
struct = wrapper_class.new
|
614
|
+
assert_nothing_raised { wrapper_class.validate!(struct) }
|
615
|
+
end
|
437
616
|
|
617
|
+
def test_dict_calls_validate
|
618
|
+
wrapper_class = Class.new(Dict) do
|
619
|
+
u32 :bigint
|
620
|
+
inner :invalid, AlwaysInvalidStruct, :req => true
|
621
|
+
end
|
622
|
+
|
623
|
+
struct = wrapper_class.new
|
624
|
+
struct.invalid = AlwaysInvalidStruct.new
|
625
|
+
|
626
|
+
assert_raise(BogusError) { wrapper_class.validate!(struct) }
|
627
|
+
end
|
438
628
|
end
|
439
629
|
|
440
630
|
class TestDictConsume < Test::Unit::TestCase
|
@@ -449,6 +639,7 @@ class TestDictConsume < Test::Unit::TestCase
|
|
449
639
|
assert_equal "a", result.foo
|
450
640
|
assert_equal "b", result.bar
|
451
641
|
end
|
642
|
+
|
452
643
|
end
|
453
644
|
|
454
645
|
class TestDictEmitDSL < Test::Unit::TestCase
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: julik-depix
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Julik Tarkhanov
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2008-12-
|
12
|
+
date: 2008-12-26 00:00:00 -08:00
|
13
13
|
default_executable: depix-describe
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -43,15 +43,18 @@ files:
|
|
43
43
|
- lib/depix.rb
|
44
44
|
- lib/depix/struct_explainer.rb
|
45
45
|
- lib/depix/structs.rb
|
46
|
+
- lib/depix/benchmark.rb
|
46
47
|
- lib/depix/compact_structs.rb
|
47
48
|
- lib/depix/enums.rb
|
48
49
|
- lib/depix/dict.rb
|
50
|
+
- lib/depix/reader.rb
|
51
|
+
- lib/depix/editor.rb
|
52
|
+
- test/test_dict.rb
|
49
53
|
- test/test_depix.rb
|
50
54
|
- test/samples/E012_P001_L000002_lin.0001.dpx
|
51
55
|
- test/samples/E012_P001_L000002_lin.0002.dpx
|
52
56
|
- test/samples/E012_P001_L000002_log.0001.dpx
|
53
57
|
- test/samples/E012_P001_L000002_log.0002.dpx
|
54
|
-
- test/test_dict.rb
|
55
58
|
has_rdoc: true
|
56
59
|
homepage: http://wiretap.rubyforge.org/depix
|
57
60
|
post_install_message:
|