depix 2.0.0 → 3.0.0
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/.travis.yml +4 -0
- data/DPX_HEADER_STRUCTURE.rdoc +5 -5
- data/Gemfile +13 -0
- data/History.txt +14 -0
- data/README.rdoc +15 -3
- data/Rakefile +28 -14
- data/bin/{depix-describe → depix_describe} +5 -4
- data/bin/depix_fix_headers +39 -0
- data/depix.gemspec +93 -0
- data/lib/depix.rb +2 -12
- data/lib/depix/binary/fields.rb +74 -32
- data/lib/depix/binary/{descriptor.rb → rdoc_generator.rb} +5 -1
- data/lib/depix/binary/structure.rb +9 -4
- data/lib/depix/describe.rb +53 -0
- data/lib/depix/reader.rb +15 -40
- data/lib/depix/structs.rb +5 -5
- data/lib/depix/synthetics.rb +12 -2
- data/test/samples/scratch.dpx +0 -0
- data/test/{test_dict.rb → test_binary.rb} +35 -18
- data/test/test_depix.rb +21 -12
- data/test/test_describe.rb +26 -0
- data/test/test_fix_headers.rb +19 -0
- metadata +113 -63
- data/Manifest.txt +0 -28
- data/lib/depix/struct_explainer.rb +0 -59
data/.travis.yml
ADDED
data/DPX_HEADER_STRUCTURE.rdoc
CHANGED
@@ -21,7 +21,7 @@ DPX metadata gets returned as a Depix::DPX object with nested properties.
|
|
21
21
|
* <tt>project</tt> (String) Project name
|
22
22
|
* <tt>copyright</tt> (String) Copyright
|
23
23
|
* <tt>encrypt_key</tt> Encryption key
|
24
|
-
* <tt>reserve</tt> (
|
24
|
+
* <tt>reserve</tt> (NilClass)
|
25
25
|
* <tt>image</tt> (Depix::ImageInfo) Image information - required:
|
26
26
|
* <tt>orientation</tt> (Integer) Orientation descriptor - required
|
27
27
|
* <tt>number_elements</tt> (Integer) How many elements to scan - required
|
@@ -43,7 +43,7 @@ DPX metadata gets returned as a Depix::DPX object with nested properties.
|
|
43
43
|
* <tt>end_of_line_padding</tt> End-of-line padding for this image element
|
44
44
|
* <tt>end_of_image_padding</tt> End-of-line padding for this image element
|
45
45
|
* <tt>description</tt> (String)
|
46
|
-
* <tt>reserve</tt> (
|
46
|
+
* <tt>reserve</tt> (NilClass)
|
47
47
|
* <tt>orientation</tt> (Depix::OrientationInfo) Orientation - required:
|
48
48
|
* <tt>x_offset</tt>
|
49
49
|
* <tt>y_offset</tt>
|
@@ -57,7 +57,7 @@ DPX metadata gets returned as a Depix::DPX object with nested properties.
|
|
57
57
|
* <tt>serial</tt> (String) Input device serial number
|
58
58
|
* <tt>border</tt> (Array of 4 Integer fields) Border validity: XL, XR, YT, YB:
|
59
59
|
* <tt>aspect_ratio</tt> (Array of 2 fields) Aspect (H:V):
|
60
|
-
* <tt>reserve</tt> (
|
60
|
+
* <tt>reserve</tt> (NilClass)
|
61
61
|
* <tt>film</tt> (Depix::FilmInfo) Film industry info - required:
|
62
62
|
* <tt>id</tt> (String) Film mfg. ID code (2 digits from film edge code)
|
63
63
|
* <tt>type</tt> (String) Film type (2 digits from film edge code)
|
@@ -72,7 +72,7 @@ DPX metadata gets returned as a Depix::DPX object with nested properties.
|
|
72
72
|
* <tt>shutter_angle</tt> (Float) Shutter angle
|
73
73
|
* <tt>frame_id</tt> (String) Frame identification (keyframe)
|
74
74
|
* <tt>slate</tt> (String) Slate information
|
75
|
-
* <tt>reserve</tt> (
|
75
|
+
* <tt>reserve</tt> (NilClass)
|
76
76
|
* <tt>television</tt> (Depix::TelevisionInfo) TV industry info - required:
|
77
77
|
* <tt>time_code</tt> Timecode, formatted as HH:MM:SS:FF in the 4 higher bits of each 8bit group
|
78
78
|
* <tt>user_bits</tt> Timecode UBITs
|
@@ -90,7 +90,7 @@ DPX metadata gets returned as a Depix::DPX object with nested properties.
|
|
90
90
|
* <tt>break_point</tt> (Float) Break point (?)
|
91
91
|
* <tt>white_level</tt> (Float) White level
|
92
92
|
* <tt>integration_times</tt> (Float) Integration times (S)
|
93
|
-
* <tt>reserve</tt> (
|
93
|
+
* <tt>reserve</tt> (NilClass)
|
94
94
|
* <tt>user</tt> (Depix::UserInfo) User info - required:
|
95
95
|
* <tt>id</tt> (String) Name of the user data tag
|
96
96
|
* <tt>user_data_ptr</tt>
|
data/Gemfile
ADDED
data/History.txt
CHANGED
@@ -1,3 +1,17 @@
|
|
1
|
+
=== 3.0.0 / 2011-11-29
|
2
|
+
|
3
|
+
* Use jeweler for gem builds
|
4
|
+
* depix-describe renamed with a dash. Sorry folks.
|
5
|
+
* Adds depix_fix_headers to fix wonky headers with, for instance, improper null-termination
|
6
|
+
* Multiple bug fixes
|
7
|
+
* Padded reserved fields not shown anymore
|
8
|
+
* More fields that have invalid values resolve to nil now
|
9
|
+
* fixed that Synthetics#aspect would return pixel aspect and not image aspect
|
10
|
+
|
11
|
+
=== 2.0.1 / 2011-11-09
|
12
|
+
|
13
|
+
* Fix the errors in depix-describe
|
14
|
+
|
1
15
|
=== 2.0.0 / 2011-06-14
|
2
16
|
|
3
17
|
* Depix::Binary is now public, and it's a nice library. Check it out.
|
data/README.rdoc
CHANGED
@@ -27,17 +27,29 @@ have the same name as the specified fields.
|
|
27
27
|
|
28
28
|
The gem also contains an executable called depix-desribe which can be used from the command line
|
29
29
|
|
30
|
-
$
|
30
|
+
$depix_describe 001_PTAPE_001.001.dpx
|
31
31
|
|
32
32
|
for a long description or
|
33
33
|
|
34
|
-
$
|
34
|
+
$depix_describe -s 001_PTAPE_001.001.dpx
|
35
|
+
|
36
|
+
for a short description.
|
37
|
+
|
38
|
+
If you have a file that does not import into some application you could run "fix headers" on it to comb
|
39
|
+
out invalid data (or data some systems do not approve of). To do so, run depix_fix_headers. Note that the files
|
40
|
+
will be modified in-place
|
41
|
+
|
42
|
+
$depix_fix_headers 001_PTAPE_001.001.dpx
|
43
|
+
|
44
|
+
or for a whole sequence - just supply the -s flag and pass one file
|
45
|
+
|
46
|
+
$depix_fix_headers -s 001_PTAPE_001.001.dpx
|
35
47
|
|
36
|
-
for a short description
|
37
48
|
|
38
49
|
== NOTES:
|
39
50
|
|
40
51
|
Autodesk IFFS systems write the reel name for the file to the orientation.device field, some scanners write it into user data.
|
52
|
+
Currently unpacking slots which contain invalid reals and ints will yield the maximum possible value for the type
|
41
53
|
|
42
54
|
== REQUIREMENTS:
|
43
55
|
|
data/Rakefile
CHANGED
@@ -1,20 +1,34 @@
|
|
1
1
|
require 'rubygems'
|
2
|
-
require 'hoe'
|
3
2
|
require './lib/depix'
|
3
|
+
require 'jeweler'
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
5
|
+
Jeweler::Tasks.new do |gem|
|
6
|
+
gem.version = Depix::VERSION
|
7
|
+
gem.name = "depix"
|
8
|
+
gem.summary = "Read and write DPX file headers"
|
9
|
+
gem.description = "Allos you to edit headers and read their contents parsed into Ruby objects"
|
10
|
+
gem.email = "me@julik.nl"
|
11
|
+
gem.homepage = "http://guerilla-di.org/depix"
|
12
|
+
gem.authors = ["Julik Tarkhanov"]
|
13
|
+
gem.extra_rdoc_files << "DEVELOPER_DOCS.rdoc"
|
14
|
+
gem.license = 'MIT'
|
15
|
+
gem.executables = ["depix_describe", "depix_fix_headers"]
|
16
|
+
gem.extra_rdoc_files = FileList['*.rdoc']
|
15
17
|
end
|
16
18
|
|
17
|
-
|
18
|
-
|
19
|
-
|
19
|
+
Jeweler::RubygemsDotOrgTasks.new
|
20
|
+
|
21
|
+
require 'rake/testtask'
|
22
|
+
desc "Run all tests"
|
23
|
+
Rake::TestTask.new("test") do |t|
|
24
|
+
t.libs << "test"
|
25
|
+
t.pattern = 'test/**/test_*.rb'
|
26
|
+
t.verbose = true
|
27
|
+
end
|
28
|
+
|
29
|
+
task :default => [ :test ]
|
30
|
+
|
31
|
+
task :document_structs do
|
32
|
+
require './lib/depix/binary/descriptor'
|
33
|
+
File.open('DPX_HEADER_STRUCTURE.rdoc', 'w') {|f| f << Depix::Binary::RdocGenerator.new.get_rdoc_for(Depix::DPX) }
|
20
34
|
end
|
@@ -5,7 +5,7 @@ require 'optparse'
|
|
5
5
|
|
6
6
|
options = {}
|
7
7
|
OptionParser.new do |opts|
|
8
|
-
opts.banner = "Usage:
|
8
|
+
opts.banner = "Usage: depix_describe somefile.dpx anotherfile.dpx [options]"
|
9
9
|
|
10
10
|
opts.on("-c", "--compact", "Compact output (only fields that change per frame)") do |v|
|
11
11
|
options[:compact] = true
|
@@ -18,15 +18,16 @@ OptionParser.new do |opts|
|
|
18
18
|
end.parse!
|
19
19
|
|
20
20
|
ARGV.each do | file |
|
21
|
+
puts "\n"
|
21
22
|
puts "Describing DPX #{file}. Empty elements are omitted."
|
22
23
|
puts "===================================================\n"
|
23
24
|
begin
|
24
25
|
if options[:synthetics]
|
25
|
-
puts Depix.describe_brief(file)
|
26
|
+
puts Depix::Describe.new.describe_brief(file)
|
26
27
|
elsif options[:compact]
|
27
|
-
puts Depix.
|
28
|
+
puts Depix::Describe.new.describe(file, true)
|
28
29
|
else
|
29
|
-
puts Depix.
|
30
|
+
puts Depix::Describe.new.describe(file)
|
30
31
|
end
|
31
32
|
rescue Depix::InvalidHeader
|
32
33
|
puts " - Invalid header data"
|
@@ -0,0 +1,39 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require File.dirname(__FILE__) + '/../lib/depix'
|
4
|
+
require "rubygems"
|
5
|
+
require 'optparse'
|
6
|
+
require "progressbar"
|
7
|
+
require "sequencer"
|
8
|
+
|
9
|
+
options = {}
|
10
|
+
OptionParser.new do |opts|
|
11
|
+
opts.banner = "Usage: depix_fix_headers somefile.dpx anotherfile.dpx" + "\n" +
|
12
|
+
"For sequences: depix_fix_headers -s one_file_from_the_sequence.dpx"
|
13
|
+
|
14
|
+
opts.on("-s", "--sequence", "Detect a sequence instead (pass one file from the sequence)") do |v|
|
15
|
+
$sequence = true
|
16
|
+
end
|
17
|
+
end.parse!
|
18
|
+
|
19
|
+
files = if $sequence
|
20
|
+
paths = []
|
21
|
+
Sequencer.from_single_file(ARGV.shift).each_path do | p |
|
22
|
+
paths.push(p)
|
23
|
+
end
|
24
|
+
paths
|
25
|
+
else
|
26
|
+
ARGV
|
27
|
+
end
|
28
|
+
|
29
|
+
raise "No files provided" unless files.any?
|
30
|
+
|
31
|
+
header = "Fixing headers in %d files" % files.length
|
32
|
+
pbar = ProgressBar.new(header, files.length)
|
33
|
+
pbar.format = "%-#{header.length}s %3d%% %s %s"
|
34
|
+
|
35
|
+
files.each do | file |
|
36
|
+
pbar.inc
|
37
|
+
Depix::Editor.new(file).commit!
|
38
|
+
end
|
39
|
+
puts ""
|
data/depix.gemspec
ADDED
@@ -0,0 +1,93 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = "depix"
|
8
|
+
s.version = "3.0.0"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Julik Tarkhanov"]
|
12
|
+
s.date = "2011-11-29"
|
13
|
+
s.description = "Allos you to edit headers and read their contents parsed into Ruby objects"
|
14
|
+
s.email = "me@julik.nl"
|
15
|
+
s.executables = ["depix_describe", "depix_fix_headers"]
|
16
|
+
s.extra_rdoc_files = [
|
17
|
+
"DPX_HEADER_STRUCTURE.rdoc",
|
18
|
+
"README.rdoc"
|
19
|
+
]
|
20
|
+
s.files = [
|
21
|
+
".gemtest",
|
22
|
+
".travis.yml",
|
23
|
+
"DPX_HEADER_STRUCTURE.rdoc",
|
24
|
+
"Gemfile",
|
25
|
+
"History.txt",
|
26
|
+
"README.rdoc",
|
27
|
+
"Rakefile",
|
28
|
+
"bin/depix_describe",
|
29
|
+
"bin/depix_fix_headers",
|
30
|
+
"depix.gemspec",
|
31
|
+
"lib/depix.rb",
|
32
|
+
"lib/depix/binary/fields.rb",
|
33
|
+
"lib/depix/binary/rdoc_generator.rb",
|
34
|
+
"lib/depix/binary/structure.rb",
|
35
|
+
"lib/depix/compact_structs.rb",
|
36
|
+
"lib/depix/describe.rb",
|
37
|
+
"lib/depix/editor.rb",
|
38
|
+
"lib/depix/enums.rb",
|
39
|
+
"lib/depix/reader.rb",
|
40
|
+
"lib/depix/structs.rb",
|
41
|
+
"lib/depix/synthetics.rb",
|
42
|
+
"test/samples/026_FROM_HERO_TAPE_5-3-1_MOV.0029.dpx",
|
43
|
+
"test/samples/E012_P001_L000002_lin.0001.dpx",
|
44
|
+
"test/samples/E012_P001_L000002_lin.0002.dpx",
|
45
|
+
"test/samples/E012_P001_L000002_log.0001.dpx",
|
46
|
+
"test/samples/E012_P001_L000002_log.0002.dpx",
|
47
|
+
"test/samples/from_nuke_no_TC_meta.dpx",
|
48
|
+
"test/samples/gluetools_file_header.dpx",
|
49
|
+
"test/samples/little_endian.dpx",
|
50
|
+
"test/samples/northlight_tc_mode_mismatch.dpx",
|
51
|
+
"test/samples/scratch.dpx",
|
52
|
+
"test/test_binary.rb",
|
53
|
+
"test/test_depix.rb",
|
54
|
+
"test/test_describe.rb",
|
55
|
+
"test/test_fix_headers.rb"
|
56
|
+
]
|
57
|
+
s.homepage = "http://guerilla-di.org/depix"
|
58
|
+
s.licenses = ["MIT"]
|
59
|
+
s.require_paths = ["lib"]
|
60
|
+
s.rubygems_version = "1.8.11"
|
61
|
+
s.summary = "Read and write DPX file headers"
|
62
|
+
|
63
|
+
if s.respond_to? :specification_version then
|
64
|
+
s.specification_version = 3
|
65
|
+
|
66
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
67
|
+
s.add_runtime_dependency(%q<timecode>, ["~> 1.0"])
|
68
|
+
s.add_runtime_dependency(%q<progressbar>, ["~> 0.9"])
|
69
|
+
s.add_runtime_dependency(%q<sequencer>, ["~> 1.0"])
|
70
|
+
s.add_runtime_dependency(%q<term-ansicolor>, [">= 0"])
|
71
|
+
s.add_development_dependency(%q<jeweler>, [">= 0"])
|
72
|
+
s.add_development_dependency(%q<rake>, [">= 0"])
|
73
|
+
s.add_development_dependency(%q<cli_test>, ["~> 1.0"])
|
74
|
+
else
|
75
|
+
s.add_dependency(%q<timecode>, ["~> 1.0"])
|
76
|
+
s.add_dependency(%q<progressbar>, ["~> 0.9"])
|
77
|
+
s.add_dependency(%q<sequencer>, ["~> 1.0"])
|
78
|
+
s.add_dependency(%q<term-ansicolor>, [">= 0"])
|
79
|
+
s.add_dependency(%q<jeweler>, [">= 0"])
|
80
|
+
s.add_dependency(%q<rake>, [">= 0"])
|
81
|
+
s.add_dependency(%q<cli_test>, ["~> 1.0"])
|
82
|
+
end
|
83
|
+
else
|
84
|
+
s.add_dependency(%q<timecode>, ["~> 1.0"])
|
85
|
+
s.add_dependency(%q<progressbar>, ["~> 0.9"])
|
86
|
+
s.add_dependency(%q<sequencer>, ["~> 1.0"])
|
87
|
+
s.add_dependency(%q<term-ansicolor>, [">= 0"])
|
88
|
+
s.add_dependency(%q<jeweler>, [">= 0"])
|
89
|
+
s.add_dependency(%q<rake>, [">= 0"])
|
90
|
+
s.add_dependency(%q<cli_test>, ["~> 1.0"])
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
data/lib/depix.rb
CHANGED
@@ -12,9 +12,10 @@ require File.expand_path(File.dirname(__FILE__)) + '/depix/synthetics'
|
|
12
12
|
require File.expand_path(File.dirname(__FILE__)) + '/depix/reader'
|
13
13
|
require File.expand_path(File.dirname(__FILE__)) + '/depix/editor'
|
14
14
|
|
15
|
+
require File.expand_path(File.dirname(__FILE__)) + '/depix/describe'
|
15
16
|
|
16
17
|
module Depix
|
17
|
-
VERSION = '
|
18
|
+
VERSION = '3.0.0'
|
18
19
|
|
19
20
|
class InvalidHeader < RuntimeError; end
|
20
21
|
|
@@ -31,15 +32,4 @@ module Depix
|
|
31
32
|
def self.from_string(string, compact = false)
|
32
33
|
Reader.new.parse(string, compact)
|
33
34
|
end
|
34
|
-
|
35
|
-
# Retrurn a formatted description of the DPX file at path. Empty values are omitted.
|
36
|
-
def self.describe_file(path, compact = false)
|
37
|
-
Reader.new.describe_file(path, compact)
|
38
|
-
end
|
39
|
-
|
40
|
-
# Return a formatted description of the DPX file at path, showing only synthetic attributes
|
41
|
-
def self.describe_brief(path)
|
42
|
-
Reader.new.describe_synthetics_of_struct(from_file(path))
|
43
|
-
end
|
44
|
-
|
45
35
|
end
|
data/lib/depix/binary/fields.rb
CHANGED
@@ -1,15 +1,15 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
module Fields
|
1
|
+
# coding: ASCII-8BIT
|
2
|
+
module Depix; module Binary; module Fields
|
4
3
|
|
5
4
|
# Base class for a padded field in a struct
|
6
5
|
class Field
|
7
|
-
attr_accessor :name
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
6
|
+
attr_accessor :name # Field name
|
7
|
+
attr_accessor :length # Field length in bytes, including any possible padding
|
8
|
+
attr_accessor :pattern # The unpack pattern that defines the field
|
9
|
+
attr_accessor :req # Is the field required?
|
10
|
+
attr_accessor :desc # Field description
|
11
|
+
attr_accessor :rtype # To which Ruby type this has to be cast (and which type is accepted as value)
|
12
|
+
|
13
13
|
alias_method :req?, :req
|
14
14
|
|
15
15
|
# Hash init
|
@@ -53,6 +53,11 @@ module Depix
|
|
53
53
|
[value].pack(pattern)
|
54
54
|
end
|
55
55
|
end
|
56
|
+
|
57
|
+
private
|
58
|
+
def blanking?(blob)
|
59
|
+
blob.nil? || blob.empty? || blob == (0xFF.chr * length)
|
60
|
+
end
|
56
61
|
end
|
57
62
|
|
58
63
|
# unit32 field
|
@@ -84,7 +89,7 @@ module Depix
|
|
84
89
|
# uint8 field
|
85
90
|
class U8Field < Field
|
86
91
|
undef :length=, :pattern=
|
87
|
-
|
92
|
+
|
88
93
|
BLANK = 0xFF
|
89
94
|
|
90
95
|
def pattern
|
@@ -144,26 +149,36 @@ module Depix
|
|
144
149
|
end
|
145
150
|
|
146
151
|
def clean(v)
|
147
|
-
v == BLANK ? nil : v
|
152
|
+
(v == BLANK || v == -1) ? nil : v
|
148
153
|
end
|
149
154
|
|
150
155
|
def validate!(value)
|
151
156
|
super(value)
|
152
157
|
raise "#{name} value #{value} out of bounds for 16bit unsigned int" if (value < 0 || value >= BLANK)
|
153
158
|
end
|
159
|
+
|
154
160
|
end
|
155
161
|
|
156
|
-
# real32 field
|
162
|
+
# real32 field. Now, there is some lap dancing to be done here.
|
163
|
+
# The DPX files in the wild define nonexistant data as a charfield with all
|
164
|
+
# it's bits set (four times 0xFF byte). This is easy to verify with a string
|
165
|
+
# but practically useless once the charfield has been unpacked into a float.
|
166
|
+
# Therefore we first unpack the value as a charfield, then we check whether it's all
|
167
|
+
# blanking, and if it is we return nil. If it's not "all bits set" though what we will do
|
168
|
+
# is try to decode it again using the real float unpack pattern. The same dance
|
169
|
+
# happens reciprocally when repacking the data.
|
157
170
|
class R32Field < Field
|
158
171
|
undef :length=, :pattern=
|
159
|
-
BLANK =
|
172
|
+
BLANK = (0xFF.chr * 4)
|
173
|
+
PATTERN_BE = "g"
|
174
|
+
PATTERN_LE = "n"
|
160
175
|
|
161
176
|
def pattern
|
162
177
|
"g"
|
163
178
|
end
|
164
179
|
|
165
180
|
def clean(v)
|
166
|
-
v.nan? ? nil : v
|
181
|
+
(v.nil? || v.nan?) ? nil : v
|
167
182
|
end
|
168
183
|
|
169
184
|
def length
|
@@ -173,34 +188,35 @@ module Depix
|
|
173
188
|
def rtype
|
174
189
|
Float
|
175
190
|
end
|
191
|
+
|
192
|
+
# The packing of NaN
|
193
|
+
# [12] pry(main)> value = 0 / 0.0
|
194
|
+
# => NaN
|
195
|
+
# [13] pry(main)> [value].pack("g")
|
196
|
+
# => "\xFF\xC0\x00\x00"
|
197
|
+
# [14] pry(main)> [value].pack("g")
|
198
|
+
def pack(value)
|
199
|
+
(value.nil? || value.nan? ) ? BLANK : [value].pack("g")
|
200
|
+
end
|
176
201
|
end
|
177
202
|
|
178
203
|
# null-terminated string field with fixed padding
|
179
204
|
class CharField < Field
|
180
|
-
BLANK = "\0"
|
181
205
|
undef :pattern=
|
182
206
|
|
183
|
-
BLANKING_VALUES = [0x00.chr, 0xFF.chr]
|
184
|
-
BLANKING_PATTERNS = BLANKING_VALUES.inject([]) do | p, char |
|
185
|
-
p << /^([#{char}]+)/ << /([#{char}]+)$/mu
|
186
|
-
end
|
187
|
-
|
188
207
|
def initialize(opts = {})
|
189
208
|
super({:length => 1}.merge(opts))
|
190
209
|
end
|
191
210
|
|
192
211
|
def pattern
|
193
|
-
"
|
212
|
+
"Z#{length}"
|
194
213
|
end
|
195
214
|
|
196
215
|
def clean(v)
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
upto_nulb = v.split(0x00.chr).shift
|
202
|
-
(upto_nulb.nil? || upto_nulb.empty?) ? nil : upto_nulb
|
203
|
-
end
|
216
|
+
# Use the pack->unpack trick to remove null-termination
|
217
|
+
v = pack(v.to_s).unpack(pattern)[0]
|
218
|
+
# Blanked fields are 0xFF all the way
|
219
|
+
blanking?(v) ? nil : v
|
204
220
|
end
|
205
221
|
|
206
222
|
def rtype
|
@@ -213,7 +229,35 @@ module Depix
|
|
213
229
|
end
|
214
230
|
|
215
231
|
def pack(value)
|
216
|
-
|
232
|
+
unless blanking?(value)
|
233
|
+
[value].pack(pattern)
|
234
|
+
else
|
235
|
+
0xFF.chr * length
|
236
|
+
end
|
237
|
+
end
|
238
|
+
end
|
239
|
+
|
240
|
+
# For reserved fields and blanking
|
241
|
+
class BlankingField < CharField
|
242
|
+
|
243
|
+
def validate!(value)
|
244
|
+
raise "The value of this field should be nil" unless value.nil?
|
245
|
+
end
|
246
|
+
|
247
|
+
def pattern
|
248
|
+
"Z#{length}"
|
249
|
+
end
|
250
|
+
|
251
|
+
def clean(v)
|
252
|
+
nil
|
253
|
+
end
|
254
|
+
|
255
|
+
def rtype
|
256
|
+
NilClass
|
257
|
+
end
|
258
|
+
|
259
|
+
def pack(value)
|
260
|
+
0xFF.chr * length
|
217
261
|
end
|
218
262
|
end
|
219
263
|
|
@@ -297,6 +341,4 @@ module Depix
|
|
297
341
|
cast.pack(value)
|
298
342
|
end
|
299
343
|
end
|
300
|
-
end
|
301
|
-
end
|
302
|
-
end
|
344
|
+
end; end; end
|