| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
########################################################### |
|
2
|
|
|
|
|
|
|
# A Perl package for showing/modifying JPEG (meta)data. # |
|
3
|
|
|
|
|
|
|
# Copyright (C) 2004,2005,2006 Stefano Bettelli # |
|
4
|
|
|
|
|
|
|
# See the COPYING and LICENSE files for license terms. # |
|
5
|
|
|
|
|
|
|
########################################################### |
|
6
|
|
|
|
|
|
|
package Image::MetaData::JPEG::Record; |
|
7
|
16
|
|
|
16
|
|
4078
|
use Image::MetaData::JPEG::Backtrace; |
|
|
16
|
|
|
|
|
22
|
|
|
|
16
|
|
|
|
|
476
|
|
|
8
|
|
|
|
|
|
|
use Image::MetaData::JPEG::data::Tables |
|
9
|
16
|
|
|
16
|
|
68
|
qw(:Endianness :RecordTypes :RecordProps :Lookups); |
|
|
16
|
|
|
|
|
20
|
|
|
|
16
|
|
|
|
|
3448
|
|
|
10
|
16
|
|
|
16
|
|
97
|
no integer; |
|
|
16
|
|
|
|
|
22
|
|
|
|
16
|
|
|
|
|
95
|
|
|
11
|
16
|
|
|
16
|
|
282
|
use strict; |
|
|
16
|
|
|
|
|
22
|
|
|
|
16
|
|
|
|
|
378
|
|
|
12
|
16
|
|
|
16
|
|
60
|
use warnings; |
|
|
16
|
|
|
|
|
21
|
|
|
|
16
|
|
|
|
|
34492
|
|
|
13
|
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
########################################################### |
|
15
|
|
|
|
|
|
|
# These simple methods should be used instead of standard # |
|
16
|
|
|
|
|
|
|
# "warn" and "die" in this package; they print a much # |
|
17
|
|
|
|
|
|
|
# more elaborated error message (including a stack trace).# |
|
18
|
|
|
|
|
|
|
# Warnings can be turned off altogether simply by setting # |
|
19
|
|
|
|
|
|
|
# Image::MetaData::JPEG::show_warnings to false. # |
|
20
|
|
|
|
|
|
|
########################################################### |
|
21
|
2
|
|
|
2
|
0
|
287
|
sub warn { my ($this, $message) = @_; |
|
22
|
2
|
100
|
|
|
|
12
|
warn Image::MetaData::JPEG::Backtrace::backtrace |
|
23
|
|
|
|
|
|
|
($message, "Warning" . $this->info(), $this) |
|
24
|
|
|
|
|
|
|
if $Image::MetaData::JPEG::show_warnings; } |
|
25
|
30
|
|
|
30
|
0
|
35
|
sub die { my ($this, $message) = @_; |
|
26
|
30
|
|
|
|
|
65
|
die Image::MetaData::JPEG::Backtrace::backtrace |
|
27
|
|
|
|
|
|
|
($message,"Fatal error" . $this->info(), $this);} |
|
28
|
31
|
|
|
31
|
0
|
34
|
sub info { my ($this) = @_; |
|
29
|
31
|
|
100
|
|
|
153
|
my $key = (ref $this && $this->{key}) || ''; |
|
30
|
31
|
|
100
|
|
|
117
|
my $type = (ref $this && $this->{type}) || ''; |
|
31
|
31
|
|
|
|
|
141
|
return " [key $key] [type $type]"; } |
|
32
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
########################################################### |
|
34
|
|
|
|
|
|
|
# A regular expression matching a legal endianness value. # |
|
35
|
|
|
|
|
|
|
########################################################### |
|
36
|
|
|
|
|
|
|
my $ENDIANNESS_OK = qr/$BIG_ENDIAN|$LITTLE_ENDIAN/o; |
|
37
|
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
########################################################### |
|
39
|
|
|
|
|
|
|
# Constructor for a generic key - values pair for storing # |
|
40
|
|
|
|
|
|
|
# properties to be found in JPEG segments. The key is # |
|
41
|
|
|
|
|
|
|
# either a numeric value (whose exact meaning depends on # |
|
42
|
|
|
|
|
|
|
# the segment type, and can be found by means of lookup # |
|
43
|
|
|
|
|
|
|
# tables), or a descriptive string. The values are to be # |
|
44
|
|
|
|
|
|
|
# found in the scalar pointed to by the data reference, # |
|
45
|
|
|
|
|
|
|
# and they come togheter with a value type; the meaning # |
|
46
|
|
|
|
|
|
|
# of the value type is taken by the APP1 type table, but # |
|
47
|
|
|
|
|
|
|
# this standard can be used also for the other segments # |
|
48
|
|
|
|
|
|
|
# (but it is not stored in the file on disk, exception # |
|
49
|
|
|
|
|
|
|
# made for some APP segments). The count must be given # |
|
50
|
|
|
|
|
|
|
# for fixed-length types. The enddianness must be given # |
|
51
|
|
|
|
|
|
|
# for numeric properties with more than 1 byte. # |
|
52
|
|
|
|
|
|
|
#=========================================================# |
|
53
|
|
|
|
|
|
|
# The "values" are a sequence, so this field is a list; # |
|
54
|
|
|
|
|
|
|
# it stores $count elements for numeric records, and a # |
|
55
|
|
|
|
|
|
|
# single scalar for non-numeric ones ("count", in this # |
|
56
|
|
|
|
|
|
|
# case, corresponds to the size of $$dataref; if $count # |
|
57
|
|
|
|
|
|
|
# is undefined, no length test is performed on $$dataref).# |
|
58
|
|
|
|
|
|
|
#=========================================================# |
|
59
|
|
|
|
|
|
|
# Types are as follows: # |
|
60
|
|
|
|
|
|
|
# 0 NIBBLES two 4-bit unsigned integers (private) # |
|
61
|
|
|
|
|
|
|
# 1 BYTE An 8-bit unsigned integer # |
|
62
|
|
|
|
|
|
|
# 2 ASCII A variable length ASCII string # |
|
63
|
|
|
|
|
|
|
# 3 SHORT A 16-bit unsigned integer # |
|
64
|
|
|
|
|
|
|
# 4 LONG A 32-bit unsigned integer # |
|
65
|
|
|
|
|
|
|
# 5 RATIONAL Two LONGs (numerator and denominator) # |
|
66
|
|
|
|
|
|
|
# 6 SBYTE An 8-bit signed integer # |
|
67
|
|
|
|
|
|
|
# 7 UNDEFINED A generic variable length string # |
|
68
|
|
|
|
|
|
|
# 8 SSHORT A 16-bit signed integer # |
|
69
|
|
|
|
|
|
|
# 9 SLONG A 32-bit signed integer (2's complem.) # |
|
70
|
|
|
|
|
|
|
# 10 SRATIONAL Two SLONGs (numerator and denominator) # |
|
71
|
|
|
|
|
|
|
# 11 FLOAT A 32-bit float (a single float) # |
|
72
|
|
|
|
|
|
|
# 12 DOUBLE A 64-bit float (a double float) # |
|
73
|
|
|
|
|
|
|
# 13 REFERENCE A Perl list reference (internal) # |
|
74
|
|
|
|
|
|
|
#=========================================================# |
|
75
|
|
|
|
|
|
|
# Added a new field, "extra", which can be used to store # |
|
76
|
|
|
|
|
|
|
# additional information one does not know where to put. # |
|
77
|
|
|
|
|
|
|
# (The need originated from APP13 record descriptions). # |
|
78
|
|
|
|
|
|
|
########################################################### |
|
79
|
|
|
|
|
|
|
sub new { |
|
80
|
42035
|
|
|
42035
|
0
|
65201
|
my ($pkg, $akey, $atype, $dataref, $count, $endian) = @_; |
|
81
|
|
|
|
|
|
|
# die immediately if $dataref is not a reference |
|
82
|
42035
|
100
|
|
|
|
60434
|
$pkg->die('Reference not found') unless ref $dataref; |
|
83
|
|
|
|
|
|
|
# create a Record object with some fields filled |
|
84
|
42032
|
|
|
|
|
149896
|
my $this = bless { |
|
85
|
|
|
|
|
|
|
key => $akey, |
|
86
|
|
|
|
|
|
|
type => $atype, |
|
87
|
|
|
|
|
|
|
values => [], |
|
88
|
|
|
|
|
|
|
extra => undef, |
|
89
|
|
|
|
|
|
|
}, $pkg; |
|
90
|
|
|
|
|
|
|
# use big endian as default endianness |
|
91
|
42032
|
100
|
|
|
|
65743
|
$endian = $BIG_ENDIAN unless defined $endian; |
|
92
|
|
|
|
|
|
|
# get the actual length of the $$dataref scalar |
|
93
|
42032
|
|
|
|
|
40769
|
my $current = length($$dataref); |
|
94
|
|
|
|
|
|
|
# estimate the right length of $data for numeric types |
|
95
|
|
|
|
|
|
|
# (remember that some types can return "no expectation", i.e. 0). |
|
96
|
42032
|
|
|
|
|
59583
|
my $expected = $pkg->get_size($atype, $count); |
|
97
|
|
|
|
|
|
|
# for variable-length records (those with $expected == 0), the length |
|
98
|
|
|
|
|
|
|
# test must be run against $count, so we update $expected here if |
|
99
|
|
|
|
|
|
|
# necessary (if $count was not given a value at call time, $expected |
|
100
|
|
|
|
|
|
|
# is set to $current and the length test will never fail). |
|
101
|
42031
|
100
|
|
|
|
71419
|
$expected = $count ? $count : $current if $expected == 0; |
|
|
|
100
|
|
|
|
|
|
|
102
|
|
|
|
|
|
|
# Throw an error if the supplied memory area is incorrectly sized |
|
103
|
42031
|
100
|
|
|
|
56261
|
$this->die("Incorrect size (expected $expected, found $current)") |
|
104
|
|
|
|
|
|
|
if ($current != $expected); |
|
105
|
|
|
|
|
|
|
# get a reference to the internal value list |
|
106
|
42021
|
|
|
|
|
38258
|
my $tokens = $this->{values}; |
|
107
|
|
|
|
|
|
|
# read the type length (used only for integers and rationals) |
|
108
|
42021
|
|
|
|
|
37169
|
my $tlength = $JPEG_RECORD_TYPE_LENGTH[$this->{type}]; |
|
109
|
|
|
|
|
|
|
# References, strings and undefined data can be immediately saved |
|
110
|
|
|
|
|
|
|
# (1 element). All integer types can be treated toghether, and |
|
111
|
|
|
|
|
|
|
# rationals can be treated as integer (halving the type length). |
|
112
|
42021
|
|
|
|
|
52048
|
my $cat = $this->get_category(); |
|
113
|
42021
|
50
|
|
|
|
168298
|
push @$tokens, |
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
114
|
|
|
|
|
|
|
$cat =~ /S|p/ ? $$dataref : |
|
115
|
|
|
|
|
|
|
$cat eq 'I' ? $this->decode_integers($tlength , $dataref, $endian) : |
|
116
|
|
|
|
|
|
|
$cat eq 'R' ? $this->decode_integers($tlength/2, $dataref, $endian) : |
|
117
|
|
|
|
|
|
|
$cat eq 'F' ? $this->decode_floating($tlength , $dataref, $endian) : |
|
118
|
|
|
|
|
|
|
$this->die('Unknown category'); |
|
119
|
|
|
|
|
|
|
# die if the token list is empty |
|
120
|
42019
|
100
|
|
|
|
64101
|
$this->die('Empty token list') if @$tokens == 0; |
|
121
|
|
|
|
|
|
|
# return the blessed reference |
|
122
|
42018
|
|
|
|
|
91209
|
return $this; |
|
123
|
|
|
|
|
|
|
} |
|
124
|
|
|
|
|
|
|
|
|
125
|
|
|
|
|
|
|
########################################################### |
|
126
|
|
|
|
|
|
|
# Syntactic sugar for a type test. The two arguments are # |
|
127
|
|
|
|
|
|
|
# $this and the numeric type. # |
|
128
|
|
|
|
|
|
|
########################################################### |
|
129
|
33796
|
|
|
33796
|
0
|
71033
|
sub is { return $_[1] == $_[0]{type}; } |
|
130
|
|
|
|
|
|
|
|
|
131
|
|
|
|
|
|
|
########################################################### |
|
132
|
|
|
|
|
|
|
# This method returns a character describing the category # |
|
133
|
|
|
|
|
|
|
# which the type of the current record belongs to. # |
|
134
|
|
|
|
|
|
|
# There are currently only five categories: # |
|
135
|
|
|
|
|
|
|
# references : 'p' -> Perl references (internal) # |
|
136
|
|
|
|
|
|
|
# integer : 'I' -> NIBBLES, (S)BYTE, (S)SHORT,(S)LONG # |
|
137
|
|
|
|
|
|
|
# string-like : 'S' -> ASCII, UNDEF # |
|
138
|
|
|
|
|
|
|
# fractional : 'R' -> RATIONAL, SRATIONAL # |
|
139
|
|
|
|
|
|
|
# float.-point: 'F' -> FLOAT, DOUBLE # |
|
140
|
|
|
|
|
|
|
# The method is sufficiently clear to use $_[0] instead # |
|
141
|
|
|
|
|
|
|
# of $this (is it a speedup ?) # |
|
142
|
|
|
|
|
|
|
########################################################### |
|
143
|
99448
|
|
|
99448
|
0
|
205370
|
sub get_category { return $JPEG_RECORD_TYPE_CATEGORY[$_[0]{type}]; } |
|
144
|
|
|
|
|
|
|
|
|
145
|
|
|
|
|
|
|
########################################################### |
|
146
|
|
|
|
|
|
|
# This method returns true or false depending on the # |
|
147
|
|
|
|
|
|
|
# record type being a signed integer or not (i.e. being # |
|
148
|
|
|
|
|
|
|
# SBYTE, SSHORT, SLONG or SRATIONAL). The method is # |
|
149
|
|
|
|
|
|
|
# sufficiently simple to use $_[0] instead of $this. # |
|
150
|
|
|
|
|
|
|
########################################################### |
|
151
|
32826
|
|
|
32826
|
0
|
71759
|
sub is_signed { return $JPEG_RECORD_TYPE_SIGN[$_[0]{type}] eq 'Y'; } |
|
152
|
|
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
########################################################### |
|
154
|
|
|
|
|
|
|
# This method calculates a record memory footprint; it # |
|
155
|
|
|
|
|
|
|
# needs the record type and the record count. This method # |
|
156
|
|
|
|
|
|
|
# is class static (it can be called without an underlying # |
|
157
|
|
|
|
|
|
|
# object), so it cannot use $this. $count defaults to 1. # |
|
158
|
|
|
|
|
|
|
# Remember that a type length of zero means that size # |
|
159
|
|
|
|
|
|
|
# should not be tested (this comes from TYPE_LENGHT = 0). # |
|
160
|
|
|
|
|
|
|
########################################################### |
|
161
|
|
|
|
|
|
|
sub get_size { |
|
162
|
68666
|
|
|
68666
|
0
|
63538
|
my ($this, $type, $count) = @_; |
|
163
|
|
|
|
|
|
|
# if count is unspecified, set it to 1 |
|
164
|
68666
|
100
|
|
|
|
95382
|
$count = 1 unless defined $count; |
|
165
|
|
|
|
|
|
|
# die if the type is unknown or undefined |
|
166
|
68666
|
100
|
|
|
|
85071
|
$this->die('Undefined record type') unless defined $type; |
|
167
|
68665
|
100
|
66
|
|
|
209708
|
$this->die("Unknown record type ($type)") |
|
168
|
|
|
|
|
|
|
if $type < 0 || $type > $#JPEG_RECORD_TYPE_LENGTH; |
|
169
|
|
|
|
|
|
|
# return the type length times $count |
|
170
|
68656
|
|
|
|
|
105409
|
return $JPEG_RECORD_TYPE_LENGTH[$type] * $count; |
|
171
|
|
|
|
|
|
|
} |
|
172
|
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
########################################################### |
|
174
|
|
|
|
|
|
|
# This class static method receives a number of Record # |
|
175
|
|
|
|
|
|
|
# features (key, type and count) and a list of values, # |
|
176
|
|
|
|
|
|
|
# and tries to build a Record with that type and count # |
|
177
|
|
|
|
|
|
|
# containing those values. On success, it returns the # |
|
178
|
|
|
|
|
|
|
# record reference, on failure it returns undef. # |
|
179
|
|
|
|
|
|
|
# ------------------------------------------------------- # |
|
180
|
|
|
|
|
|
|
# Floating point values are matched to six decimal digits # |
|
181
|
|
|
|
|
|
|
########################################################### |
|
182
|
|
|
|
|
|
|
sub check_consistency { |
|
183
|
1439
|
|
|
1439
|
0
|
1983
|
my ($pkg, $key, $type, $count, $tokens) = @_; |
|
184
|
|
|
|
|
|
|
# create a dummy Record, the "fix" its type and its value list |
|
185
|
1439
|
|
|
|
|
2709
|
my $record = new Image::MetaData::JPEG::Record($key, $ASCII, \ ""); |
|
186
|
1439
|
|
|
|
|
3117
|
@$record{'type', 'values'} = ($type, $tokens); |
|
187
|
|
|
|
|
|
|
# try to get back the record properties; return undef if it fails |
|
188
|
1439
|
|
|
|
|
2093
|
(undef, undef, my $new_count, my $dataref) = eval { $record->get() }; |
|
|
1439
|
|
|
|
|
2356
|
|
|
189
|
1439
|
50
|
|
|
|
2733
|
return undef unless defined $dataref; |
|
190
|
|
|
|
|
|
|
# if $count was previously undefined, listen to the Record encoder |
|
191
|
1439
|
100
|
|
|
|
2789
|
$count = $new_count unless defined $count; |
|
192
|
|
|
|
|
|
|
# if counts are already different, there is no hope (this |
|
193
|
|
|
|
|
|
|
# can happen if $count was faulty: we haven't used it sofar). |
|
194
|
1439
|
100
|
|
|
|
2417
|
return undef if $count != $new_count; |
|
195
|
|
|
|
|
|
|
# build the real record by re-parsing the data reference; in my |
|
196
|
|
|
|
|
|
|
# opinion this should never fail, so I don't check the result. |
|
197
|
|
|
|
|
|
|
# Does this provide more chances to find a bug? |
|
198
|
1431
|
|
|
|
|
2391
|
$record = new Image::MetaData::JPEG::Record($key, $type, $dataref, $count); |
|
199
|
|
|
|
|
|
|
# return undef if the number of values does not match |
|
200
|
1431
|
|
|
|
|
2969
|
my $new_tokens = $record->{values}; |
|
201
|
1431
|
50
|
|
|
|
2447
|
return undef unless scalar @$tokens == scalar @$new_tokens; |
|
202
|
|
|
|
|
|
|
# the new record can however have a value list different from |
|
203
|
|
|
|
|
|
|
# what we hope, since some data types could wrap. So we now |
|
204
|
|
|
|
|
|
|
# compare the value lists and return undef if they differ. |
|
205
|
1431
|
|
|
|
|
2434
|
for (0..$#$tokens) { |
|
206
|
12341
|
100
|
|
|
|
12394
|
return undef if ($record->get_category() eq 'F') ? |
|
|
|
100
|
|
|
|
|
|
|
207
|
|
|
|
|
|
|
# due to the nature of floating point values, the comparison |
|
208
|
|
|
|
|
|
|
# is limited to six decimal digits (the new token has a precision |
|
209
|
|
|
|
|
|
|
# of 23 or 52 binary digits, while the old one is just a string) |
|
210
|
|
|
|
|
|
|
sprintf("%.6g",$$new_tokens[$_]) ne sprintf("%.6g",$$tokens[$_]) : |
|
211
|
|
|
|
|
|
|
# for all other types, compare the plain values |
|
212
|
|
|
|
|
|
|
$$new_tokens[$_] ne $$tokens[$_]; } |
|
213
|
|
|
|
|
|
|
# if you get here, everything is ok: return the record reference |
|
214
|
1430
|
|
|
|
|
4913
|
return $record; |
|
215
|
|
|
|
|
|
|
} |
|
216
|
|
|
|
|
|
|
|
|
217
|
|
|
|
|
|
|
########################################################### |
|
218
|
|
|
|
|
|
|
# This method returns a particular value in the value # |
|
219
|
|
|
|
|
|
|
# list, its index being the only argument. If the index # |
|
220
|
|
|
|
|
|
|
# is undefined (not supplied), the sum of all values is # |
|
221
|
|
|
|
|
|
|
# returned. The index is checked for out-of-bound errors. # |
|
222
|
|
|
|
|
|
|
#=========================================================# |
|
223
|
|
|
|
|
|
|
# For string-like records, "sum" -> "concatenation". # |
|
224
|
|
|
|
|
|
|
########################################################### |
|
225
|
|
|
|
|
|
|
sub get_value { |
|
226
|
29094
|
|
|
29094
|
0
|
39122
|
my ($this, $index) = @_; |
|
227
|
|
|
|
|
|
|
# get a reference to the value list |
|
228
|
29094
|
|
|
|
|
26591
|
my $values = $this->{values}; |
|
229
|
|
|
|
|
|
|
# access a single value if an index is defined or |
|
230
|
|
|
|
|
|
|
# there is only one value (follow to sum otherwise) |
|
231
|
29094
|
100
|
100
|
|
|
103525
|
goto VALUE_INDEX if defined $index || @$values == 1; |
|
232
|
95
|
50
|
|
|
|
200
|
VALUE_SUM: |
|
233
|
|
|
|
|
|
|
return ($this->get_category() eq 'S') ? |
|
234
|
|
|
|
|
|
|
# perform concatenation for string-like values |
|
235
|
|
|
|
|
|
|
join "", @$values : |
|
236
|
|
|
|
|
|
|
# perform addition for numeric values |
|
237
|
|
|
|
|
|
|
eval (join "+", @$values); |
|
238
|
28999
|
100
|
|
|
|
40268
|
VALUE_INDEX: |
|
239
|
|
|
|
|
|
|
# $index defaults to zero |
|
240
|
|
|
|
|
|
|
$index = 0 unless defined $index; |
|
241
|
|
|
|
|
|
|
# get the last legal index |
|
242
|
28999
|
|
|
|
|
24211
|
my $last_index = $#$values; |
|
243
|
|
|
|
|
|
|
# check that $index is legal, throw an exception otherwise |
|
244
|
28999
|
100
|
|
|
|
39832
|
$this->die("Out-of-bound index ($index > $last_index)") |
|
245
|
|
|
|
|
|
|
if $index > $last_index; |
|
246
|
|
|
|
|
|
|
# return the desired value |
|
247
|
28997
|
|
|
|
|
61583
|
return $$values[$index]; |
|
248
|
|
|
|
|
|
|
} |
|
249
|
|
|
|
|
|
|
|
|
250
|
|
|
|
|
|
|
########################################################### |
|
251
|
|
|
|
|
|
|
# This method sets a particular value in the value list. # |
|
252
|
|
|
|
|
|
|
# If the index is undefined (not supplied), the first # |
|
253
|
|
|
|
|
|
|
# (0th) value is set. The index is check for out-of-bound # |
|
254
|
|
|
|
|
|
|
# errors. This method is dangerous: call only internally. # |
|
255
|
|
|
|
|
|
|
########################################################### |
|
256
|
|
|
|
|
|
|
sub set_value { |
|
257
|
148
|
|
|
148
|
0
|
203
|
my ($this, $new_value, $index) = @_; |
|
258
|
|
|
|
|
|
|
# get a reference to the value list |
|
259
|
148
|
|
|
|
|
191
|
my $values = $this->{values}; |
|
260
|
|
|
|
|
|
|
# set the first value if index is defined |
|
261
|
148
|
50
|
|
|
|
293
|
$index = 0 unless defined $index; |
|
262
|
|
|
|
|
|
|
# check out-of-bound condition |
|
263
|
148
|
|
|
|
|
193
|
my $last_index = $#$values; |
|
264
|
148
|
50
|
|
|
|
287
|
$this->die("Out-of-bound index ($index > $last_index)") |
|
265
|
|
|
|
|
|
|
if $index > $last_index; |
|
266
|
|
|
|
|
|
|
# set the value |
|
267
|
148
|
|
|
|
|
390
|
$$values[$index] = $new_value; |
|
268
|
|
|
|
|
|
|
} |
|
269
|
|
|
|
|
|
|
|
|
270
|
|
|
|
|
|
|
########################################################### |
|
271
|
|
|
|
|
|
|
# These private functions take signed/unsigned integers # |
|
272
|
|
|
|
|
|
|
# and return their unsigned/signed version; the type # |
|
273
|
|
|
|
|
|
|
# length in bytes must also be specified. $_[0] is the # |
|
274
|
|
|
|
|
|
|
# original value, $_[1] is the type length. $msb[$n] is # |
|
275
|
|
|
|
|
|
|
# an unsigned integer with the 8*$n-th bit turned up. # |
|
276
|
|
|
|
|
|
|
# There is also a function for converting binary data as # |
|
277
|
|
|
|
|
|
|
# a string into a big-endian number (iteratively) and a # |
|
278
|
|
|
|
|
|
|
# function for interchanging bytes with nibble pairs. # |
|
279
|
|
|
|
|
|
|
########################################################### |
|
280
|
|
|
|
|
|
|
{ my @msb = map { 2**(8*$_ - 1) } 0..20; |
|
281
|
308
|
100
|
|
308
|
0
|
833
|
sub to_signed { ($_[0] >= $msb[$_[1]]) ? ($_[0] - 2*$msb[$_[1]]) : $_[0] } |
|
282
|
575
|
100
|
|
575
|
0
|
1345
|
sub to_unsigned { ($_[0] < 0) ? ($_[0] + 2*$msb[$_[1]]) : $_[0] } |
|
283
|
47081
|
|
|
47081
|
0
|
34593
|
sub to_number { my $v=0; for (unpack "C*", $_[0]) { ($v<<=8) += $_; } $v } |
|
|
47081
|
|
|
|
|
61677
|
|
|
|
106371
|
|
|
|
|
101793
|
|
|
|
47081
|
|
|
|
|
70501
|
|
|
284
|
324
|
|
|
324
|
0
|
476
|
sub to_nibbles { map { chr(vec($_[0], $_, 4)) } reverse (0..1) } |
|
|
648
|
|
|
|
|
1596
|
|
|
285
|
4
|
|
|
4
|
0
|
6
|
sub to_byte { my $b="x"; vec($b,$_^1,4) = ord($_[$_]) for (0..1) ; $b } |
|
|
4
|
|
|
|
|
26
|
|
|
|
4
|
|
|
|
|
12
|
|
|
286
|
|
|
|
|
|
|
} |
|
287
|
|
|
|
|
|
|
|
|
288
|
|
|
|
|
|
|
########################################################### |
|
289
|
|
|
|
|
|
|
# This method decodes a sequence of 8$n-bit integers, and # |
|
290
|
|
|
|
|
|
|
# correctly takes into account signedness and endianness. # |
|
291
|
|
|
|
|
|
|
# The data size must be validated in advance: in this # |
|
292
|
|
|
|
|
|
|
# routine it must be a multiple of the type size ($n). # |
|
293
|
|
|
|
|
|
|
#=========================================================# |
|
294
|
|
|
|
|
|
|
# NIBBLES are treated apart. A "nibble record" is indeed # |
|
295
|
|
|
|
|
|
|
# a pair of 4-bit values, so the type length is 1, but # |
|
296
|
|
|
|
|
|
|
# each element must enter two values into @tokens. They # |
|
297
|
|
|
|
|
|
|
# are always big-endian and unsigned. # |
|
298
|
|
|
|
|
|
|
#=========================================================# |
|
299
|
|
|
|
|
|
|
# Don't use shift operators, which are a bit too tricky.. # |
|
300
|
|
|
|
|
|
|
########################################################### |
|
301
|
|
|
|
|
|
|
sub decode_integers { |
|
302
|
21037
|
|
|
21037
|
0
|
22791
|
my ($this, $n, $dataref, $endian) = @_; |
|
303
|
|
|
|
|
|
|
# safety check on endianness |
|
304
|
21037
|
100
|
|
|
|
100498
|
$this->die('Unknown endianness') unless $endian =~ $ENDIANNESS_OK; |
|
305
|
|
|
|
|
|
|
# prepare the list of raw tokens |
|
306
|
21036
|
|
|
|
|
80303
|
my @tokens = unpack "a$n" x (length($$dataref)/$n), $$dataref; |
|
307
|
|
|
|
|
|
|
# correct the tokens for endianness if necessary |
|
308
|
21036
|
100
|
|
|
|
35104
|
@tokens = map { scalar reverse } @tokens if $endian eq $LITTLE_ENDIAN; |
|
|
2701
|
|
|
|
|
5611
|
|
|
309
|
|
|
|
|
|
|
# rework the raw token list for nibbles. |
|
310
|
21036
|
100
|
|
|
|
28325
|
@tokens = map { to_nibbles($_) } @tokens if $this->is($NIBBLES); |
|
|
324
|
|
|
|
|
518
|
|
|
311
|
|
|
|
|
|
|
# convert to 1-byte digits and concatenate them (assuming big-endian) |
|
312
|
21036
|
|
|
|
|
25829
|
@tokens = map { to_number($_) } @tokens; |
|
|
47081
|
|
|
|
|
50659
|
|
|
313
|
|
|
|
|
|
|
# correction for signedness. |
|
314
|
21036
|
100
|
|
|
|
28233
|
@tokens = map { to_signed($_, $n) } @tokens if $this->is_signed(); |
|
|
308
|
|
|
|
|
612
|
|
|
315
|
|
|
|
|
|
|
# return the token list |
|
316
|
21036
|
|
|
|
|
35677
|
return @tokens; |
|
317
|
|
|
|
|
|
|
} |
|
318
|
|
|
|
|
|
|
|
|
319
|
|
|
|
|
|
|
########################################################### |
|
320
|
|
|
|
|
|
|
# This method encodes the content of $this->{values} into # |
|
321
|
|
|
|
|
|
|
# a sequence of 8$n-bit integers, correctly taking into # |
|
322
|
|
|
|
|
|
|
# account signedness and endianness. The return value is # |
|
323
|
|
|
|
|
|
|
# a reference to the encoded scalar, ready to be written # |
|
324
|
|
|
|
|
|
|
# to disk. See decode_integers() for further details. # |
|
325
|
|
|
|
|
|
|
########################################################### |
|
326
|
|
|
|
|
|
|
sub encode_integers { |
|
327
|
9352
|
|
|
9352
|
0
|
9869
|
my ($this, $n, $endian) = @_; |
|
328
|
|
|
|
|
|
|
# safety check on endianness |
|
329
|
9352
|
100
|
|
|
|
40993
|
$this->die('Unknown endianness') unless $endian =~ $ENDIANNESS_OK; |
|
330
|
|
|
|
|
|
|
# copy the value list (the original should not be touched) |
|
331
|
9351
|
|
|
|
|
7075
|
my @tokens = @{$this->{values}}; |
|
|
9351
|
|
|
|
|
23135
|
|
|
332
|
|
|
|
|
|
|
# correction for signedness |
|
333
|
9351
|
100
|
|
|
|
13532
|
@tokens = map { to_unsigned($_, $n) } @tokens if $this->is_signed(); |
|
|
575
|
|
|
|
|
861
|
|
|
334
|
|
|
|
|
|
|
# convert the number into 1-byte digits (assuming big-endian) |
|
335
|
9351
|
|
|
|
|
10648
|
@tokens = map { my $enc = ""; vec($enc, 0, 8*$n) = $_; $enc } @tokens; |
|
|
67631
|
|
|
|
|
46640
|
|
|
|
67631
|
|
|
|
|
75637
|
|
|
|
67631
|
|
|
|
|
91200
|
|
|
336
|
|
|
|
|
|
|
# reconstruct the raw token list for nibbles. |
|
337
|
9351
|
100
|
|
|
|
17387
|
@tokens = map { to_byte($tokens[2*$_], $tokens[2*$_+1]) } 0..(@tokens)/2-1 |
|
|
4
|
|
|
|
|
19
|
|
|
338
|
|
|
|
|
|
|
if $this->is($NIBBLES); |
|
339
|
|
|
|
|
|
|
# correct the tokens for endianness if necessary |
|
340
|
9351
|
100
|
|
|
|
14349
|
@tokens = map { scalar reverse } @tokens if $endian eq $LITTLE_ENDIAN; |
|
|
1868
|
|
|
|
|
2445
|
|
|
341
|
|
|
|
|
|
|
# reconstruct a string from the list of raw tokens |
|
342
|
9351
|
|
|
|
|
27792
|
my $data = pack "a$n" x (scalar @tokens), @tokens; |
|
343
|
|
|
|
|
|
|
# return a reference to the reconstructed string |
|
344
|
9351
|
|
|
|
|
14902
|
return \ $data; |
|
345
|
|
|
|
|
|
|
} |
|
346
|
|
|
|
|
|
|
|
|
347
|
|
|
|
|
|
|
########################################################### |
|
348
|
|
|
|
|
|
|
# This method decodes a data area containing a sequence # |
|
349
|
|
|
|
|
|
|
# of floating point values, correctly taking into account # |
|
350
|
|
|
|
|
|
|
# the endianness. The type size $n can therefore be only # |
|
351
|
|
|
|
|
|
|
# 4, 8 or 12 (but you will not be able to store extended # |
|
352
|
|
|
|
|
|
|
# precision numbers unless your system provides support # |
|
353
|
|
|
|
|
|
|
# for them [a Cray?]). The data size must be validated in # |
|
354
|
|
|
|
|
|
|
# advance: here it must be a multiple of the type size. # |
|
355
|
|
|
|
|
|
|
########################################################### |
|
356
|
|
|
|
|
|
|
sub decode_floating { |
|
357
|
26
|
|
|
26
|
0
|
30
|
my ($this, $n, $dataref, $endian) = @_; |
|
358
|
|
|
|
|
|
|
# safety check on endianness |
|
359
|
26
|
100
|
|
|
|
147
|
$this->die('Unknown endianness') unless $endian =~ $ENDIANNESS_OK; |
|
360
|
|
|
|
|
|
|
# prepare the list of raw tokens |
|
361
|
25
|
|
|
|
|
131
|
my @tokens = unpack "a$n" x (length($$dataref)/$n), $$dataref; |
|
362
|
|
|
|
|
|
|
# correct the tokens for endianness if necessary (to native endianness) |
|
363
|
25
|
100
|
|
|
|
53
|
@tokens = map { scalar reverse } @tokens if $endian ne $NATIVE_ENDIANNESS; |
|
|
79
|
|
|
|
|
161
|
|
|
364
|
|
|
|
|
|
|
# select the correct conversion format (single/double/extended) |
|
365
|
25
|
|
|
|
|
51
|
my $format = ('f', 'd', 'D')[$n/4 - 1]; |
|
366
|
|
|
|
|
|
|
# loop over all tokens (numbers) and extract them |
|
367
|
25
|
|
|
|
|
24
|
@tokens = map { unpack $format, $_ } @tokens; |
|
|
99
|
|
|
|
|
123
|
|
|
368
|
|
|
|
|
|
|
# return the token list |
|
369
|
25
|
|
|
|
|
60
|
return @tokens; |
|
370
|
|
|
|
|
|
|
} |
|
371
|
|
|
|
|
|
|
|
|
372
|
|
|
|
|
|
|
########################################################### |
|
373
|
|
|
|
|
|
|
# This method encodes the content of $this->{values} into # |
|
374
|
|
|
|
|
|
|
# a sequence of floating point numbers, correctly taking # |
|
375
|
|
|
|
|
|
|
# into account the endianness. The returned value is a # |
|
376
|
|
|
|
|
|
|
# reference to the encoded scalar, ready to be written to # |
|
377
|
|
|
|
|
|
|
# disk. See decode_floating() for further details. # |
|
378
|
|
|
|
|
|
|
########################################################### |
|
379
|
|
|
|
|
|
|
sub encode_floating { |
|
380
|
31
|
|
|
31
|
0
|
39
|
my ($this, $n, $endian) = @_; |
|
381
|
|
|
|
|
|
|
# safety check on endianness |
|
382
|
31
|
100
|
|
|
|
163
|
$this->die('Unknown endianness') unless $endian =~ $ENDIANNESS_OK; |
|
383
|
|
|
|
|
|
|
# get a simpler reference to the value list |
|
384
|
30
|
|
|
|
|
29
|
my @tokens = @{$this->{values}}; |
|
|
30
|
|
|
|
|
67
|
|
|
385
|
|
|
|
|
|
|
# select the correct conversion format (single/double/extended) |
|
386
|
30
|
|
|
|
|
59
|
my $format = ('f', 'd', 'D')[$n/4 - 1]; |
|
387
|
|
|
|
|
|
|
# loop over all tokens (floating point numbers) |
|
388
|
30
|
|
|
|
|
35
|
@tokens = map { pack $format, $_ } @tokens; |
|
|
135
|
|
|
|
|
208
|
|
|
389
|
|
|
|
|
|
|
# correct the tokens for endianness if necessary (from native endianness) |
|
390
|
30
|
100
|
|
|
|
79
|
@tokens = map { scalar reverse } @tokens if $endian ne $NATIVE_ENDIANNESS; |
|
|
123
|
|
|
|
|
186
|
|
|
391
|
|
|
|
|
|
|
# reconstruct a string from the list of raw tokens |
|
392
|
30
|
|
|
|
|
55
|
my $data = join '', @tokens; |
|
393
|
|
|
|
|
|
|
# return a reference to the reconstructed string |
|
394
|
30
|
|
|
|
|
51
|
return \ $data; |
|
395
|
|
|
|
|
|
|
} |
|
396
|
|
|
|
|
|
|
|
|
397
|
|
|
|
|
|
|
########################################################### |
|
398
|
|
|
|
|
|
|
# This method returns the content of the record: in list # |
|
399
|
|
|
|
|
|
|
# context it returns (key, type, count, data_reference). # |
|
400
|
|
|
|
|
|
|
# The reference points to a packed scalar, ready to be # |
|
401
|
|
|
|
|
|
|
# written to disk. In scalar context, it returns "data", # |
|
402
|
|
|
|
|
|
|
# i.e. the dereferentiated data_reference. This is tricky # |
|
403
|
|
|
|
|
|
|
# (but handy for other routines). The endianness argument # |
|
404
|
|
|
|
|
|
|
# defaults to $BIG_ENDIAN. See ctor for further details. # |
|
405
|
|
|
|
|
|
|
########################################################### |
|
406
|
|
|
|
|
|
|
sub get { |
|
407
|
15362
|
|
|
15362
|
0
|
23808
|
my ($this, $endian) = @_; |
|
408
|
|
|
|
|
|
|
# use big endian as default endianness |
|
409
|
15362
|
100
|
|
|
|
22989
|
$endian = $BIG_ENDIAN unless defined $endian; |
|
410
|
|
|
|
|
|
|
# get the record type and a reference to the internal value list |
|
411
|
15362
|
|
|
|
|
14336
|
my $type = $this->{type}; |
|
412
|
15362
|
|
|
|
|
13113
|
my $tokens = $this->{values}; |
|
413
|
15362
|
|
|
|
|
17450
|
my $category = $this->get_category(); |
|
414
|
|
|
|
|
|
|
# read the type length (only used for integers and rationals) |
|
415
|
15362
|
|
|
|
|
13954
|
my $tlength = $JPEG_RECORD_TYPE_LENGTH[$type]; |
|
416
|
|
|
|
|
|
|
# References, strings and undefined data contain a single value |
|
417
|
|
|
|
|
|
|
# (to be taken a reference at). All integer types can be treated |
|
418
|
|
|
|
|
|
|
# toghether, and rationals can be treated as integer (halving the |
|
419
|
|
|
|
|
|
|
# type length). Floating points still to be coded. |
|
420
|
15362
|
50
|
|
|
|
49613
|
my $dataref = |
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
421
|
|
|
|
|
|
|
$category =~ /S|p/ ? \ $$tokens[0] : |
|
422
|
|
|
|
|
|
|
$category eq 'I' ? $this->encode_integers($tlength , $endian) : |
|
423
|
|
|
|
|
|
|
$category eq 'R' ? $this->encode_integers($tlength/2, $endian) : |
|
424
|
|
|
|
|
|
|
$category eq 'F' ? $this->encode_floating($tlength , $endian) : |
|
425
|
|
|
|
|
|
|
$this->die('Unknown category'); |
|
426
|
|
|
|
|
|
|
# calculate the "count" (the number of elements for numeric types |
|
427
|
|
|
|
|
|
|
# and the length of $$dataref for references, strings, undefined) |
|
428
|
15360
|
100
|
|
|
|
37564
|
my $count = length($$dataref) / ( $category =~ /S|p/ ? 1 : $tlength ); |
|
429
|
|
|
|
|
|
|
# return the result, depending on the context |
|
430
|
15360
|
100
|
|
|
|
52215
|
wantarray ? ($this->{key}, $type, $count, $dataref) : $$dataref; |
|
431
|
|
|
|
|
|
|
} |
|
432
|
|
|
|
|
|
|
|
|
433
|
|
|
|
|
|
|
########################################################### |
|
434
|
|
|
|
|
|
|
# This routine reworks $ASCII and $UNDEF record values # |
|
435
|
|
|
|
|
|
|
# before displaying them. In particular, unreasonably # |
|
436
|
|
|
|
|
|
|
# long strings are trimmed and non-printing characters # |
|
437
|
|
|
|
|
|
|
# are replaced with their hexadecimal representation. # |
|
438
|
|
|
|
|
|
|
# Strings are then enclosed between delimiters, and null- # |
|
439
|
|
|
|
|
|
|
# terminated ones can have their last character chopped # |
|
440
|
|
|
|
|
|
|
# off (but a dot is added after the closing delimiter). # |
|
441
|
|
|
|
|
|
|
# Remember to copy the string to avoid side-effects! # |
|
442
|
|
|
|
|
|
|
# ------------------------------------------------------- # |
|
443
|
|
|
|
|
|
|
# $_[0] --> this contains the string to be modified. # |
|
444
|
|
|
|
|
|
|
# $_[1] --> this contains the string delimiter (" or ') # |
|
445
|
|
|
|
|
|
|
# $_[2] --> true if the last null char is to be replaced # |
|
446
|
|
|
|
|
|
|
########################################################### |
|
447
|
|
|
|
|
|
|
sub string_manipulator { |
|
448
|
|
|
|
|
|
|
# max length of the part of the string we want to display |
|
449
|
|
|
|
|
|
|
# (after conversion of non-printing chars to hex repr.) |
|
450
|
970
|
|
|
970
|
0
|
768
|
my $maxlen = 40; |
|
451
|
|
|
|
|
|
|
# running variables |
|
452
|
970
|
|
|
|
|
1108
|
my ($left, $string) = (length $_[0], ''); |
|
453
|
970
|
|
|
|
|
1022
|
my ($delim, $dropnull) = @_[1,2]; |
|
454
|
|
|
|
|
|
|
# loop over all characters in the string |
|
455
|
970
|
|
|
|
|
1388
|
for (0..(length($_[0])-1)) { |
|
456
|
|
|
|
|
|
|
# get a copy of the current character |
|
457
|
10646
|
|
|
|
|
9210
|
my $token = substr($_[0], $_, 1); |
|
458
|
|
|
|
|
|
|
# translate it to a string if it is non-printing |
|
459
|
10646
|
|
|
|
|
11853
|
$token =~ s/[\000-\037\177-\377]/sprintf "\\%02x",ord($&)/e; |
|
|
2939
|
|
|
|
|
5473
|
|
|
460
|
|
|
|
|
|
|
# stop here if the overall string becomes too long |
|
461
|
10646
|
100
|
|
|
|
15100
|
last if length($token) + length($string) > $maxlen; |
|
462
|
|
|
|
|
|
|
# update running variables |
|
463
|
10490
|
|
|
|
|
6578
|
--$left; $string .= $token; } |
|
|
10490
|
|
|
|
|
9837
|
|
|
464
|
|
|
|
|
|
|
# transform the terminating null character into a dot if the |
|
465
|
|
|
|
|
|
|
# string does not start with a slash, then put delimiters |
|
466
|
|
|
|
|
|
|
# around the string (the dot remains outside, however). |
|
467
|
970
|
|
|
|
|
1224
|
$string = "${delim}$string${delim}"; |
|
468
|
970
|
100
|
|
|
|
3724
|
$string =~ s/^(.*)\\00${delim}$/$1${delim}\./ if $dropnull; |
|
469
|
|
|
|
|
|
|
# print the reworked string (if the string was shortened, |
|
470
|
|
|
|
|
|
|
# add a notice to the end and use a fixed length field) |
|
471
|
970
|
100
|
|
|
|
3879
|
sprintf($left ? '%-'.(3+$maxlen)."s($left more chars)" : '%-s', $string); |
|
472
|
|
|
|
|
|
|
} |
|
473
|
|
|
|
|
|
|
|
|
474
|
|
|
|
|
|
|
########################################################### |
|
475
|
|
|
|
|
|
|
# This method returns a string describing the content of # |
|
476
|
|
|
|
|
|
|
# the record. The argument is a reference to an array of # |
|
477
|
|
|
|
|
|
|
# names, which are to be used as successive keys in a # |
|
478
|
|
|
|
|
|
|
# general hash keeping translations of numeric tags. # |
|
479
|
|
|
|
|
|
|
# No argument is needed if the key is already non-numeric.# |
|
480
|
|
|
|
|
|
|
########################################################### |
|
481
|
|
|
|
|
|
|
sub get_description { |
|
482
|
2439
|
|
|
2439
|
0
|
2409
|
my ($this, $names) = @_; |
|
483
|
|
|
|
|
|
|
# some internal parameters |
|
484
|
2439
|
|
|
|
|
1970
|
my $maxlen = 25; my $max_tokens = 7; |
|
|
2439
|
|
|
|
|
1682
|
|
|
485
|
|
|
|
|
|
|
# try not to die every time if $names is undefined ... |
|
486
|
2439
|
50
|
|
|
|
3491
|
$names = [] unless defined $names; |
|
487
|
|
|
|
|
|
|
# assume that the key is a string (so, it is its own |
|
488
|
|
|
|
|
|
|
# description, and no numeric value is to be shown) |
|
489
|
2439
|
|
|
|
|
3031
|
my $descriptor = $this->{key}; |
|
490
|
2439
|
|
|
|
|
1865
|
my $numerictag = undef; |
|
491
|
|
|
|
|
|
|
# however, if it is a number we need more work |
|
492
|
2439
|
100
|
|
|
|
7220
|
if ($descriptor =~ /^\d*$/) { |
|
493
|
|
|
|
|
|
|
# get the relevant hash for the description of this record |
|
494
|
1622
|
|
|
|
|
3240
|
my $section_hash = JPEG_lookup(@$names); |
|
495
|
|
|
|
|
|
|
# fix the numeric tag |
|
496
|
1622
|
|
|
|
|
1511
|
$numerictag = $descriptor; |
|
497
|
|
|
|
|
|
|
# extract a description string; if there is no entry in the |
|
498
|
|
|
|
|
|
|
# hash for this key, replace the descriptor with a sort of |
|
499
|
|
|
|
|
|
|
# error message (non-existent tags differ from undefined ones) |
|
500
|
1622
|
50
|
|
|
|
4659
|
$descriptor = |
|
|
|
100
|
|
|
|
|
|
|
501
|
|
|
|
|
|
|
! exists $$section_hash{$descriptor} ? "?? Unknown record ??" : |
|
502
|
|
|
|
|
|
|
! defined $$section_hash{$descriptor} ? "?? Nameless record ??" : |
|
503
|
|
|
|
|
|
|
$$section_hash{$descriptor} } |
|
504
|
|
|
|
|
|
|
# calculate an appropriate tabbing |
|
505
|
2439
|
|
|
|
|
2897
|
my $tabbing = " \t" x (scalar @$names); |
|
506
|
|
|
|
|
|
|
# prepare the description (don't make it exceed $maxlen characters). |
|
507
|
2439
|
100
|
|
|
|
3898
|
$descriptor = substr($descriptor, 0, $maxlen/2) |
|
508
|
|
|
|
|
|
|
. "..." . substr($descriptor, - $maxlen/2 + 3) |
|
509
|
|
|
|
|
|
|
if length($descriptor) > $maxlen; |
|
510
|
|
|
|
|
|
|
# initialise the string to be returned at the end |
|
511
|
2439
|
|
|
|
|
5029
|
my $description = sprintf "%s[%${maxlen}s]", $tabbing, $descriptor; |
|
512
|
|
|
|
|
|
|
# show also the numeric tag for this record (if present) |
|
513
|
2439
|
100
|
|
|
|
4386
|
$description .= defined $numerictag ? |
|
514
|
|
|
|
|
|
|
sprintf "<0x%04x>", $numerictag : "<......>"; |
|
515
|
|
|
|
|
|
|
# show the tag type as a string |
|
516
|
2439
|
|
|
|
|
4220
|
$description .= sprintf " = [%9s] ", $JPEG_RECORD_TYPE_NAME[$this->{type}]; |
|
517
|
|
|
|
|
|
|
# show the "extra" field if present |
|
518
|
2439
|
100
|
|
|
|
3755
|
$description .= "<$this->{extra}>" if defined $this->{extra}; |
|
519
|
|
|
|
|
|
|
# take a reference to the list of objects to process |
|
520
|
2439
|
|
|
|
|
2224
|
my $tokens = $this->{values}; |
|
521
|
|
|
|
|
|
|
# we want to write at most $max_tokens tokens in the value list |
|
522
|
2439
|
|
|
|
|
2621
|
my $extra = $#$tokens - $max_tokens; |
|
523
|
2439
|
100
|
|
|
|
3311
|
my $token_limit = $extra > 0 ? $max_tokens : $#$tokens; |
|
524
|
|
|
|
|
|
|
# some auxiliary variables (depending only on the record type) |
|
525
|
2439
|
100
|
|
|
|
3542
|
my $intfs = $this->is_signed() ? '%d' : '%u'; |
|
526
|
2439
|
100
|
|
|
|
3396
|
my $sep = $this->is($ASCII) ? '"' : "'" ; |
|
527
|
2439
|
|
|
970
|
|
6021
|
my $text = sub { string_manipulator($_[0], $sep, $this->is($ASCII)) }; |
|
|
970
|
|
|
|
|
1360
|
|
|
528
|
|
|
|
|
|
|
# integers, strings and floating points are written in sequence; |
|
529
|
|
|
|
|
|
|
# rationals must be written in pairs (use a flip-flop); |
|
530
|
|
|
|
|
|
|
# undefined values are written on a byte per byte basis. |
|
531
|
2439
|
|
|
|
|
2225
|
my $f = '/'; |
|
532
|
2439
|
|
|
|
|
3965
|
foreach (@$tokens[0..$token_limit]) { |
|
533
|
|
|
|
|
|
|
# update the flip flop |
|
534
|
3393
|
100
|
|
|
|
4363
|
$f = $f eq ' ' ? '/' : ' '; |
|
535
|
|
|
|
|
|
|
# some auxiliary variables |
|
536
|
3393
|
|
|
|
|
3858
|
my $category = $this->get_category(); |
|
537
|
|
|
|
|
|
|
# show something, depending on category and type |
|
538
|
3393
|
50
|
|
|
|
10668
|
$description .= |
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
539
|
|
|
|
|
|
|
$category eq 'p' ? sprintf ' --> 0x%06x', $_ : |
|
540
|
|
|
|
|
|
|
$category eq 'S' ? sprintf '%s' , &$text($_) : |
|
541
|
|
|
|
|
|
|
$category eq 'I' ? sprintf ' '.$intfs , $_ : |
|
542
|
|
|
|
|
|
|
$category eq 'F' ? sprintf ' %g' , $_ : |
|
543
|
|
|
|
|
|
|
$category eq 'R' ? sprintf '%s'.$intfs , $f, $_ : |
|
544
|
|
|
|
|
|
|
$this->die('Unknown error condition'); } |
|
545
|
|
|
|
|
|
|
# terminate the line; remember to put a warning note if there were |
|
546
|
|
|
|
|
|
|
# more than $max_tokens element to display, then return the description |
|
547
|
2439
|
100
|
|
|
|
3941
|
$description .= " ... ($extra more values)" if $extra > 0; |
|
548
|
2439
|
|
|
|
|
1993
|
$description .= "\n"; |
|
549
|
|
|
|
|
|
|
# return the descriptive string |
|
550
|
2439
|
|
|
|
|
8431
|
return $description; |
|
551
|
|
|
|
|
|
|
} |
|
552
|
|
|
|
|
|
|
|
|
553
|
|
|
|
|
|
|
# successful package load |
|
554
|
|
|
|
|
|
|
1; |