depix 1.0.1 → 1.0.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|