depix 1.0.1 → 1.0.2
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/DPX_HEADER_STRUCTURE.txt +91 -94
- data/History.txt +5 -0
- data/Manifest.txt +3 -0
- data/README.txt +4 -6
- data/Rakefile +8 -4
- data/bin/depix-describe +15 -6
- data/lib/depix.rb +69 -100
- data/lib/depix/compact_structs.rb +42 -0
- data/lib/depix/dict.rb +343 -0
- data/lib/depix/enums.rb +43 -0
- data/lib/depix/struct_explainer.rb +37 -40
- data/lib/depix/structs.rb +112 -232
- data/test/test_depix.rb +23 -90
- data/test/test_dict.rb +650 -0
- metadata +6 -2
data/DPX_HEADER_STRUCTURE.txt
CHANGED
@@ -1,100 +1,97 @@
|
|
1
1
|
= DPX header structure description
|
2
2
|
|
3
|
-
DPX metadata gets returned as a
|
4
|
-
|
5
|
-
|
6
|
-
meta.file.magic # same as meta[:file][:magic]
|
3
|
+
DPX metadata gets returned as a Depix::DPX object with nested properties.
|
4
|
+
|
5
|
+
meta.file.magic # => "SDPX"
|
7
6
|
|
8
7
|
== Metadata structure
|
9
8
|
|
10
|
-
* <tt>file</tt>
|
11
|
-
* <tt>magic</tt> String
|
12
|
-
* <tt>image_offset</tt>
|
13
|
-
* <tt>version</tt> String
|
14
|
-
* <tt>file_size</tt>
|
15
|
-
* <tt>ditto_key</tt>
|
16
|
-
* <tt>generic_size</tt>
|
17
|
-
* <tt>industry_size</tt>
|
18
|
-
* <tt>user_size</tt>
|
19
|
-
* <tt>filename</tt> String
|
20
|
-
* <tt>timestamp</tt> String
|
21
|
-
* <tt>creator</tt> String
|
22
|
-
* <tt>
|
23
|
-
* <tt>copyright</tt> String
|
24
|
-
* <tt>encrypt_key</tt>
|
25
|
-
* <tt>reserve</tt> String
|
26
|
-
* <tt>image</tt>
|
27
|
-
* <tt>orientation</tt> Integer
|
28
|
-
* <tt>number_elements</tt> Integer
|
29
|
-
* <tt>pixels_per_line</tt>
|
30
|
-
* <tt>lines_per_element</tt>
|
31
|
-
* <tt>image_elements</tt>
|
32
|
-
* <tt>data_sign</tt>
|
33
|
-
* <tt>low_data</tt>
|
34
|
-
* <tt>low_quantity</tt> Float
|
35
|
-
* <tt>high_data</tt>
|
36
|
-
* <tt>high_quantity</tt> Float
|
37
|
-
* <tt>descriptor</tt> Integer
|
38
|
-
* <tt>transfer</tt> Integer
|
39
|
-
* <tt>colorimetric</tt> Integer
|
40
|
-
* <tt>bit_size</tt> Integer
|
41
|
-
* <tt>packing</tt> Integer
|
42
|
-
* <tt>encoding</tt> Integer
|
43
|
-
* <tt>data_offset</tt>
|
44
|
-
* <tt>end_of_line_padding</tt>
|
45
|
-
* <tt>end_of_image_padding</tt>
|
46
|
-
* <tt>description</tt> String
|
47
|
-
* <tt>reserve</tt> String
|
48
|
-
* <tt>orientation</tt>
|
49
|
-
* <tt>x_offset</tt>
|
50
|
-
* <tt>y_offset</tt>
|
51
|
-
* <tt>x_center</tt> Float
|
52
|
-
* <tt>y_center</tt> Float
|
53
|
-
* <tt>x_size</tt>
|
54
|
-
* <tt>y_size</tt>
|
55
|
-
* <tt>filename</tt> String
|
56
|
-
* <tt>timestamp</tt> String
|
57
|
-
* <tt>device</tt> String
|
58
|
-
* <tt>serial</tt> String
|
59
|
-
* <tt>border</tt>
|
60
|
-
* <tt
|
61
|
-
* <tt>
|
62
|
-
|
63
|
-
* <tt>
|
64
|
-
* <tt>
|
65
|
-
* <tt>
|
66
|
-
* <tt>
|
67
|
-
* <tt>
|
68
|
-
* <tt>
|
69
|
-
* <tt>
|
70
|
-
* <tt>
|
71
|
-
* <tt>
|
72
|
-
* <tt>
|
73
|
-
* <tt>
|
74
|
-
* <tt>
|
75
|
-
* <tt>
|
76
|
-
* <tt>
|
77
|
-
|
78
|
-
* <tt>
|
79
|
-
* <tt>
|
80
|
-
* <tt>
|
81
|
-
* <tt>
|
82
|
-
* <tt>
|
83
|
-
* <tt>
|
84
|
-
* <tt>
|
85
|
-
* <tt>
|
86
|
-
* <tt>
|
87
|
-
* <tt>
|
88
|
-
* <tt>
|
89
|
-
* <tt>
|
90
|
-
* <tt>
|
91
|
-
* <tt>
|
92
|
-
* <tt>
|
93
|
-
* <tt>
|
94
|
-
* <tt>
|
95
|
-
|
96
|
-
* <tt>
|
97
|
-
* <tt>
|
98
|
-
* <tt>id</tt> String
|
99
|
-
* <tt>user_data</tt> Integer
|
9
|
+
* <tt>file</tt> (Depix::FileInfo) File information:
|
10
|
+
* <tt>magic</tt> (String) Endianness (SDPX is big endian) - required
|
11
|
+
* <tt>image_offset</tt> Offset to image data in bytes - required
|
12
|
+
* <tt>version</tt> (String) Version of header format - required
|
13
|
+
* <tt>file_size</tt> Total image size in bytes - required
|
14
|
+
* <tt>ditto_key</tt> Whether the basic headers stay the same through the sequence (1 means they do)
|
15
|
+
* <tt>generic_size</tt> Generic header length
|
16
|
+
* <tt>industry_size</tt> Industry header length
|
17
|
+
* <tt>user_size</tt> User header length
|
18
|
+
* <tt>filename</tt> (String) Original filename
|
19
|
+
* <tt>timestamp</tt> (String) Creation 15
|
20
|
+
* <tt>creator</tt> (String) Creator application
|
21
|
+
* <tt>roject</tt> (String) Project name
|
22
|
+
* <tt>copyright</tt> (String) Copyright
|
23
|
+
* <tt>encrypt_key</tt> Encryption key
|
24
|
+
* <tt>reserve</tt> (String)
|
25
|
+
* <tt>image</tt> (Depix::ImageInfo) Image information:
|
26
|
+
* <tt>orientation</tt> (Integer) Orientation descriptor - required
|
27
|
+
* <tt>number_elements</tt> (Integer) How many elements to scan - required
|
28
|
+
* <tt>pixels_per_line</tt> Pixels per horizontal line - required
|
29
|
+
* <tt>lines_per_element</tt> Line count - required
|
30
|
+
* <tt>image_elements</tt> (Array of 8 Depix::ImageElement fields) Image elements:
|
31
|
+
* <tt>data_sign</tt> Data sign (0=unsigned, 1=signed). Core is unsigned - required
|
32
|
+
* <tt>low_data</tt> Reference low data code value
|
33
|
+
* <tt>low_quantity</tt> (Float) Reference low quantity represented
|
34
|
+
* <tt>high_data</tt> Reference high data code value (1023 for 10bit per channel)
|
35
|
+
* <tt>high_quantity</tt> (Float) Reference high quantity represented
|
36
|
+
* <tt>descriptor</tt> (Integer) Descriptor for this image element (ie Video or Film), by enum - required
|
37
|
+
* <tt>transfer</tt> (Integer) Transfer function (ie Linear), by enum - required
|
38
|
+
* <tt>colorimetric</tt> (Integer) Colorimetric (ie YcbCr), by enum - required
|
39
|
+
* <tt>bit_size</tt> (Integer) Bit size for element (ie 10) - required
|
40
|
+
* <tt>packing</tt> (Integer) Packing (0=Packed into 32-bit words, 1=Filled to 32-bit words)) - required
|
41
|
+
* <tt>encoding</tt> (Integer) Encoding (0=None, 1=RLE) - required
|
42
|
+
* <tt>data_offset</tt> Offset to data for this image element - required
|
43
|
+
* <tt>end_of_line_padding</tt> End-of-line padding for this image element
|
44
|
+
* <tt>end_of_image_padding</tt> End-of-line padding for this image element
|
45
|
+
* <tt>description</tt> (String)
|
46
|
+
* <tt>reserve</tt> (String)
|
47
|
+
* <tt>orientation</tt> (Depix::OrientationInfo) Orientation:
|
48
|
+
* <tt>x_offset</tt>
|
49
|
+
* <tt>y_offset</tt>
|
50
|
+
* <tt>x_center</tt> (Float)
|
51
|
+
* <tt>y_center</tt> (Float)
|
52
|
+
* <tt>x_size</tt> Original X size
|
53
|
+
* <tt>y_size</tt> Original Y size
|
54
|
+
* <tt>filename</tt> (String) Source image filename
|
55
|
+
* <tt>timestamp</tt> (String) Source image/tape timestamp
|
56
|
+
* <tt>device</tt> (String) Input device or tape
|
57
|
+
* <tt>serial</tt> (String) Input device serial number
|
58
|
+
* <tt>border</tt> (Array of 4 Integer fields) Border validity: XL, XR, YT, YB:
|
59
|
+
* <tt>aspect_ratio</tt> (Array of 2 fields) Aspect (H:V):
|
60
|
+
* <tt>reserve</tt> (String)
|
61
|
+
* <tt>film</tt> (Depix::FilmInfo) Film industry info:
|
62
|
+
* <tt>id</tt> (String) Film mfg. ID code (2 digits from film edge code)
|
63
|
+
* <tt>type</tt> (String) Film type (2 digits from film edge code)
|
64
|
+
* <tt>offset</tt> (String) Offset in perfs (2 digits from film edge code)
|
65
|
+
* <tt>prefix</tt> (String) Prefix (6 digits from film edge code
|
66
|
+
* <tt>count</tt> (String) Count (4 digits from film edge code)
|
67
|
+
* <tt>format</tt> (String) Format (e.g. Academy)
|
68
|
+
* <tt>frame_position</tt> Frame position in sequence
|
69
|
+
* <tt>sequence_extent</tt> Sequence length
|
70
|
+
* <tt>held_count</tt> For how many frames the frame is held
|
71
|
+
* <tt>frame_rate</tt> (Float) Frame rate
|
72
|
+
* <tt>shutter_angle</tt> (Float) Shutter angle
|
73
|
+
* <tt>frame_id</tt> (String) Frame identification (keyframe)
|
74
|
+
* <tt>slate</tt> (String) Slate information
|
75
|
+
* <tt>reserve</tt> (String)
|
76
|
+
* <tt>television</tt> (Depix::TelevisionInfo) TV industry info:
|
77
|
+
* <tt>time_code</tt> Timecode, formatted as HH:MM:SS:FF in the 4 higher bits of each 8bit group
|
78
|
+
* <tt>user_bits</tt> Timecode UBITs
|
79
|
+
* <tt>interlace</tt> (Integer) Interlace (0 = noninterlaced; 1 = 2:1 interlace
|
80
|
+
* <tt>field_number</tt> (Integer) Field number
|
81
|
+
* <tt>video_signal</tt> (Integer) Video signal (by enum)
|
82
|
+
* <tt>padding</tt> (Integer) Zero (for byte alignment)
|
83
|
+
* <tt>horizontal_sample_rate</tt> (Float) Horizontal sampling Hz
|
84
|
+
* <tt>vertical_sample_rate</tt> (Float) Vertical sampling Hz
|
85
|
+
* <tt>frame_rate</tt> (Float) Frame rate
|
86
|
+
* <tt>time_offset</tt> (Float) From sync pulse to first pixel
|
87
|
+
* <tt>gamma</tt> (Float) Gamma
|
88
|
+
* <tt>black_level</tt> (Float) Black pedestal code value
|
89
|
+
* <tt>black_gain</tt> (Float) Black gain code value
|
90
|
+
* <tt>break_point</tt> (Float) Break point (?)
|
91
|
+
* <tt>white_level</tt> (Float) White level
|
92
|
+
* <tt>integration_times</tt> (Float) Integration times (S)
|
93
|
+
* <tt>reserve</tt> (Float)
|
94
|
+
* <tt>user</tt> (Depix::UserInfo) User info:
|
95
|
+
* <tt>id</tt> (String) Name of the user data tag
|
96
|
+
* <tt>user_data_ptr</tt>
|
100
97
|
|
data/History.txt
CHANGED
data/Manifest.txt
CHANGED
@@ -7,6 +7,9 @@ bin/depix-describe
|
|
7
7
|
lib/depix.rb
|
8
8
|
lib/depix/struct_explainer.rb
|
9
9
|
lib/depix/structs.rb
|
10
|
+
lib/depix/compact_structs.rb
|
11
|
+
lib/depix/enums.rb
|
12
|
+
lib/depix/dict.rb
|
10
13
|
test/test_depix.rb
|
11
14
|
test/samples/E012_P001_L000002_lin.0001.dpx
|
12
15
|
test/samples/E012_P001_L000002_lin.0002.dpx
|
data/README.txt
CHANGED
@@ -9,10 +9,11 @@ Read DPX file metadata
|
|
9
9
|
== SYNOPSIS:
|
10
10
|
|
11
11
|
meta = Depix::Reader.from_file(dpx_file_path)
|
12
|
-
puts meta.
|
12
|
+
puts meta.time_code #=> 10:00:00:02
|
13
13
|
|
14
|
-
The data returned is described in the DPX_HEADER_STRUCTURE[link:files/DPX_HEADER_STRUCTURE_txt.html].
|
15
|
-
|
14
|
+
The data returned is described in the DPX_HEADER_STRUCTURE[link:files/DPX_HEADER_STRUCTURE_txt.html]. It's
|
15
|
+
a vanilla Ruby object with no extra methods except for the readers that have the same name as the specified
|
16
|
+
fields
|
16
17
|
|
17
18
|
The gem also contains an executable called depix-desribe which can be used from the command line
|
18
19
|
|
@@ -20,9 +21,6 @@ The gem also contains an executable called depix-desribe which can be used from
|
|
20
21
|
|
21
22
|
== NOTES:
|
22
23
|
|
23
|
-
The reader tries to be efficient - fast Ruby unpacking is used, some shortcuts are taken. Also don't worry - we do not need to read
|
24
|
-
the whole DPX file (which usually is around 8mb per frame) to know the details.
|
25
|
-
|
26
24
|
In the future there will be a possibility to modify and commit the headers, but it's not a priority at this time.
|
27
25
|
|
28
26
|
Autodesk IFFS systems write the reel name for the file to the orientation.device field
|
data/Rakefile
CHANGED
@@ -1,15 +1,19 @@
|
|
1
1
|
require 'rubygems'
|
2
2
|
require 'hoe'
|
3
|
-
require './lib/depix
|
3
|
+
require './lib/depix'
|
4
4
|
|
5
|
-
|
5
|
+
Class.new(Hoe) do
|
6
|
+
def extra_deps
|
7
|
+
super.reject {|e| e[0] == 'hoe' }
|
8
|
+
end
|
9
|
+
end.new('depix', Depix::VERSION) do |p|
|
6
10
|
p.developer('Julik Tarkhanov', 'me@julik.nl')
|
7
11
|
p.rubyforge_name = 'wiretap'
|
8
|
-
p.extra_deps
|
12
|
+
p.extra_deps << 'timecode'
|
9
13
|
p.remote_rdoc_dir = 'depix'
|
10
14
|
end
|
11
15
|
|
12
16
|
task :describe_structs do
|
13
17
|
require File.dirname(__FILE__) + '/lib/depix/struct_explainer'
|
14
|
-
File.open('DPX_HEADER_STRUCTURE.txt', 'w') {|f| f << RdocExplainer.new.get_rdoc_for(Depix::
|
18
|
+
File.open('DPX_HEADER_STRUCTURE.txt', 'w') {|f| f << RdocExplainer.new.get_rdoc_for(Depix::DPX) }
|
15
19
|
end
|
data/bin/depix-describe
CHANGED
@@ -1,10 +1,19 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
3
|
require File.dirname(__FILE__) + '/../lib/depix'
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
4
|
+
require 'optparse'
|
5
|
+
|
6
|
+
options = {}
|
7
|
+
OptionParser.new do |opts|
|
8
|
+
opts.banner = "Usage: depix-describe somefile.dpx anotherfile.dpx [options]"
|
9
|
+
|
10
|
+
opts.on("-c", "--compact", "Compact output (only fields that change per frame)") do |v|
|
11
|
+
options[:compact] = true
|
12
|
+
end
|
13
|
+
end.parse!
|
14
|
+
|
15
|
+
ARGV.each do | file |
|
16
|
+
puts "Describing DPX #{file}. Empty elements are omitted.\n\n"
|
17
|
+
puts "===================================================\n\n"
|
18
|
+
puts Depix.describe_file(file, options[:compact])
|
10
19
|
end
|
data/lib/depix.rb
CHANGED
@@ -2,29 +2,13 @@ require 'stringio'
|
|
2
2
|
require 'rubygems'
|
3
3
|
require 'timecode'
|
4
4
|
|
5
|
+
require File.dirname(__FILE__) + '/depix/dict'
|
5
6
|
require File.dirname(__FILE__) + '/depix/structs'
|
7
|
+
require File.dirname(__FILE__) + '/depix/compact_structs'
|
8
|
+
require File.dirname(__FILE__) + '/depix/enums'
|
6
9
|
|
7
10
|
module Depix
|
8
|
-
VERSION = '1.0.
|
9
|
-
|
10
|
-
BLANK_2 = 0xFFFF #:nodoc:
|
11
|
-
BLANK_4 = 0xFFFFFFFF #:nodoc:
|
12
|
-
BLANK_F = 0xFFFFFFFF #:nodoc:
|
13
|
-
BLANK_CHAR = 0xFF #:nodoc:
|
14
|
-
|
15
|
-
# Methodic hash - stolen from Camping
|
16
|
-
class H < Hash
|
17
|
-
# Gets or sets keys in the hash.
|
18
|
-
#
|
19
|
-
# @cookies.my_favorite = :macadamian
|
20
|
-
# @cookies.my_favorite
|
21
|
-
# => :macadamian
|
22
|
-
#
|
23
|
-
def method_missing(m,*a)
|
24
|
-
m.to_s=~/=$/ ? (self[$`] = a[0]) : (a == [] ? (self.key?(m.to_s) ? self[m.to_s] : super ) : super)
|
25
|
-
end
|
26
|
-
undef id, type
|
27
|
-
end
|
11
|
+
VERSION = '1.0.2'
|
28
12
|
|
29
13
|
# Offers convenience access to a few common attributes bypassing the piecemeal structs
|
30
14
|
module Synthetics
|
@@ -37,111 +21,96 @@ module Depix
|
|
37
21
|
end
|
38
22
|
|
39
23
|
def time_code
|
40
|
-
Timecode.from_uint(television.time_code
|
24
|
+
Timecode.from_uint(television.time_code) #, film.frame_rate)
|
41
25
|
end
|
42
26
|
|
43
27
|
# Get the name of the transfer function (Linear, Logarithmic, ...)
|
44
28
|
def colorimetric
|
45
|
-
|
29
|
+
COLORIMETRIC.invert[image.image_elements[0].colorimetric]
|
46
30
|
end
|
47
31
|
|
48
32
|
# Get the name of the compnent type (RGB, YCbCr, ...)
|
49
33
|
def component_type
|
50
|
-
|
34
|
+
COMPONENT_TYPE.invert[image.image_elements[0].descriptor]
|
51
35
|
end
|
52
|
-
|
36
|
+
|
37
|
+
# Is this DPX file little-endian? This would be an exception, but still useful
|
38
|
+
def le?
|
39
|
+
file.magic == 'XPDS'
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
class DPX < Dict
|
44
|
+
include Synthetics
|
45
|
+
end
|
46
|
+
|
47
|
+
# Return a DPX object describing a file at path.
|
48
|
+
# The second argument specifies whether you need a compact or a full description
|
49
|
+
def self.from_file(path, compact = false)
|
50
|
+
Reader.new.from_file(path, compact)
|
51
|
+
end
|
52
|
+
|
53
|
+
# Return a DPX object describing headers embedded at the start of the string.
|
54
|
+
# The second argument specifies whether you need a compact or a full description
|
55
|
+
def self.from_string(string, compact = false)
|
56
|
+
Reader.new.parse(string, compact)
|
57
|
+
end
|
58
|
+
|
59
|
+
# Retrurn a formatted description of the DPX file at path. Empty values are omitted.
|
60
|
+
def self.describe_file(path, compact = false)
|
61
|
+
Reader.new.describe_file(path, compact)
|
53
62
|
end
|
54
63
|
|
55
|
-
# Reads the metadata
|
56
64
|
class Reader
|
57
65
|
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
end
|
63
|
-
|
64
|
-
# Read the metadata from an in-memory string. Returns a H with the metadata.
|
65
|
-
def from_string(str)
|
66
|
-
new.from_string(str)
|
67
|
-
end
|
68
|
-
|
69
|
-
# Returns a printable report on all the headers present in the string
|
70
|
-
def describe_string(str)
|
71
|
-
reader = new
|
72
|
-
result = reader.deep_parse(str, Structs::DPX_INFO)
|
73
|
-
reader.inform(result)
|
74
|
-
end
|
75
|
-
|
76
|
-
# Returns a printable report on all the headers present in the file at the path passed
|
77
|
-
def describe_file(path)
|
78
|
-
header = File.open(path, 'r') { |f| f.read(Structs::TEMPLATE_LENGTH) }
|
79
|
-
describe_string(header)
|
80
|
-
end
|
66
|
+
# Returns a printable report on all the headers present in the file at the path passed
|
67
|
+
def describe_file(path, compact = false)
|
68
|
+
header = File.open(path, 'r') { |f| f.read(DPX.length) }
|
69
|
+
describe_struct(parse(header, false))
|
81
70
|
end
|
82
71
|
|
83
|
-
|
84
|
-
|
85
|
-
header
|
86
|
-
from_string(header)
|
72
|
+
def from_file(path, compact)
|
73
|
+
header = File.open(path, 'r') { |f| f.read(DPX.length) }
|
74
|
+
parse(header, compact)
|
87
75
|
end
|
88
76
|
|
89
|
-
|
90
|
-
|
91
|
-
end
|
92
|
-
|
93
|
-
def deep_parse(data, structure)
|
77
|
+
# The hear of Depix
|
78
|
+
def parse(data, compact)
|
94
79
|
magic = data[0..3]
|
95
|
-
|
80
|
+
struct = compact ? CompactDPX : DPX
|
96
81
|
|
97
|
-
|
98
|
-
|
99
|
-
when String
|
100
|
-
clean = unpad(e)
|
101
|
-
clean.empty? ? nil : clean
|
102
|
-
when Integer
|
103
|
-
(e == BLANK_2 || e == BLANK_4) ? nil : e
|
104
|
-
when Float
|
105
|
-
e.nan? ? nil : e
|
106
|
-
end
|
107
|
-
end
|
108
|
-
result
|
82
|
+
template = (magic == "SDPX") ? struct.pattern : make_le(struct.pattern)
|
83
|
+
struct.consume!(data.unpack(template))
|
109
84
|
end
|
110
85
|
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
keys.each_with_index do |path, idx |
|
128
|
-
value = values[idx]
|
129
|
-
|
130
|
-
sub, elems = auto_hash, path.split('.')
|
131
|
-
while elems.any?
|
132
|
-
dir = elems.shift
|
133
|
-
dir = dir.to_i if dir =~ /^(\d+)$/
|
134
|
-
elems.any? ? (sub = sub[dir]) : (sub[dir] = value)
|
86
|
+
# Describe a filled DPX structure
|
87
|
+
def describe_struct(result, pad_offset = 0)
|
88
|
+
result.class.fields.inject([]) do | info, field |
|
89
|
+
value = result.send(field.name)
|
90
|
+
parts = []
|
91
|
+
if value
|
92
|
+
parts << field.desc if field.desc
|
93
|
+
parts << if field.is_a?(InnerField)
|
94
|
+
describe_struct(value, pad_offset + 1)
|
95
|
+
elsif field.is_a?(ArrayField)
|
96
|
+
# Exception for image elements
|
97
|
+
value = result.image_elements[0...result.number_elements] if field.name == :image_elements
|
98
|
+
value.map { | v | v.is_a?(Dict) ? describe_struct(v, pad_offset + 2) : v }
|
99
|
+
else
|
100
|
+
value
|
101
|
+
end
|
135
102
|
end
|
136
|
-
|
137
|
-
|
138
|
-
|
103
|
+
if parts.any?
|
104
|
+
info << parts.join(' ')
|
105
|
+
end
|
106
|
+
info
|
107
|
+
end.map{|e| (' ' * pad_offset) + e }.join("\n")
|
139
108
|
end
|
140
109
|
|
141
|
-
|
142
|
-
|
110
|
+
# Convert an unpack pattern to LE
|
111
|
+
def make_le(pattern)
|
112
|
+
pattern.gsub(/n/, "v").gsub(/N/, "V").gsub(/g/, "f")
|
143
113
|
end
|
144
114
|
|
145
|
-
#:startdoc:
|
146
115
|
end
|
147
116
|
end
|