| 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
|
|
|
|
|
|
|
#use 5.008; |
|
7
|
|
|
|
|
|
|
package Image::MetaData::JPEG; |
|
8
|
14
|
|
|
14
|
|
124961
|
use Image::MetaData::JPEG::data::Tables qw(:JPEGgrammar); |
|
|
14
|
|
|
|
|
32
|
|
|
|
14
|
|
|
|
|
2698
|
|
|
9
|
14
|
|
|
14
|
|
5483
|
use Image::MetaData::JPEG::Backtrace; |
|
|
14
|
|
|
|
|
21
|
|
|
|
14
|
|
|
|
|
371
|
|
|
10
|
14
|
|
|
14
|
|
5974
|
use Image::MetaData::JPEG::Segment; |
|
|
14
|
|
|
|
|
36
|
|
|
|
14
|
|
|
|
|
422
|
|
|
11
|
14
|
|
|
14
|
|
65
|
no integer; |
|
|
14
|
|
|
|
|
13
|
|
|
|
14
|
|
|
|
|
44
|
|
|
12
|
14
|
|
|
14
|
|
214
|
use strict; |
|
|
14
|
|
|
|
|
18
|
|
|
|
14
|
|
|
|
|
276
|
|
|
13
|
14
|
|
|
14
|
|
44
|
use warnings; |
|
|
14
|
|
|
|
|
16
|
|
|
|
14
|
|
|
|
|
25698
|
|
|
14
|
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
our $VERSION = '0.159'; |
|
16
|
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
########################################################### |
|
18
|
|
|
|
|
|
|
# These simple methods should be used instead of standard # |
|
19
|
|
|
|
|
|
|
# "warn" and "die" in this package; they print a much # |
|
20
|
|
|
|
|
|
|
# more elaborated error message (including a stack trace).# |
|
21
|
|
|
|
|
|
|
# Warnings can be turned off altogether simply by setting # |
|
22
|
|
|
|
|
|
|
# Image::MetaData::JPEG::show_warnings to false. # |
|
23
|
|
|
|
|
|
|
########################################################### |
|
24
|
5
|
|
|
5
|
0
|
7
|
sub warn { my ($this, $message) = @_; |
|
25
|
5
|
100
|
|
|
|
20
|
warn Image::MetaData::JPEG::Backtrace::backtrace |
|
26
|
|
|
|
|
|
|
($message, "Warning" . $this->info(), $this) |
|
27
|
|
|
|
|
|
|
if $Image::MetaData::JPEG::show_warnings; } |
|
28
|
17
|
|
|
17
|
0
|
22
|
sub die { my ($this, $message) = @_; |
|
29
|
17
|
|
|
|
|
41
|
die Image::MetaData::JPEG::Backtrace::backtrace |
|
30
|
|
|
|
|
|
|
($message, "Fatal error" . $this->info(), $this); } |
|
31
|
21
|
|
|
21
|
0
|
23
|
sub info { my ($this) = @_; |
|
32
|
21
|
|
100
|
|
|
50
|
my $filename = $this->{filename} || ''; |
|
33
|
21
|
|
|
|
|
105
|
return " [file $filename]"; } |
|
34
|
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
########################################################### |
|
36
|
|
|
|
|
|
|
# Constructor for a JPEG file structure object, accepting # |
|
37
|
|
|
|
|
|
|
# a "JPEG stream". It parses the file stream and stores # |
|
38
|
|
|
|
|
|
|
# its sections internally. An optional parameter can ex- # |
|
39
|
|
|
|
|
|
|
# clude parsing and even storing for some segments. The # |
|
40
|
|
|
|
|
|
|
# stream can be specified in two ways: # |
|
41
|
|
|
|
|
|
|
# - [a scalar] interpreted as a file name to be opened; # |
|
42
|
|
|
|
|
|
|
# - [a scalar reference] interpreted as a pointer to an # |
|
43
|
|
|
|
|
|
|
# in-memory buffer containing a JPEG stream; # |
|
44
|
|
|
|
|
|
|
# ------------------------------------------------------- # |
|
45
|
|
|
|
|
|
|
# There is now a second argument, $regex. This string is # |
|
46
|
|
|
|
|
|
|
# matched against segment names, and only those segments # |
|
47
|
|
|
|
|
|
|
# with a positive match are parsed. This allows for some # |
|
48
|
|
|
|
|
|
|
# speed-up if you just need partial information. For # |
|
49
|
|
|
|
|
|
|
# instance, if you just want to manipulate the comments, # |
|
50
|
|
|
|
|
|
|
# you could use $regex equal to 'COM'. If $regex is unde- # |
|
51
|
|
|
|
|
|
|
# fined, all segments are matched. # |
|
52
|
|
|
|
|
|
|
# ------------------------------------------------------- # |
|
53
|
|
|
|
|
|
|
# There is now a third optional argument, $options. If it # |
|
54
|
|
|
|
|
|
|
# matches the string 'FASTREADONLY', only those segments # |
|
55
|
|
|
|
|
|
|
# matching $regex are actually stored; also, everything # |
|
56
|
|
|
|
|
|
|
# which is found after a Start Of Scan is completely # |
|
57
|
|
|
|
|
|
|
# neglected. This allows for very large speed-ups, but, # |
|
58
|
|
|
|
|
|
|
# obviously, you cannot rebuild the file afterwards, so # |
|
59
|
|
|
|
|
|
|
# this is only for getting information fast (e.g., when # |
|
60
|
|
|
|
|
|
|
# doing a directory scan). # |
|
61
|
|
|
|
|
|
|
# ------------------------------------------------------- # |
|
62
|
|
|
|
|
|
|
# If an unrecoverable error occurs during the execution # |
|
63
|
|
|
|
|
|
|
# of the constructor, the undefined value is returned # |
|
64
|
|
|
|
|
|
|
# instead of the object reference, and a meaningful error # |
|
65
|
|
|
|
|
|
|
# message is set up (read it with Error()). # |
|
66
|
|
|
|
|
|
|
########################################################### |
|
67
|
|
|
|
|
|
|
sub new { |
|
68
|
71
|
|
|
71
|
1
|
117493
|
my ($pkg, $file_input, $regex, $options) = @_; |
|
69
|
71
|
|
|
|
|
477
|
my $this = bless { |
|
70
|
|
|
|
|
|
|
filename => undef, # private |
|
71
|
|
|
|
|
|
|
handle => undef, # private |
|
72
|
|
|
|
|
|
|
read_only => undef, # private |
|
73
|
|
|
|
|
|
|
segments => [], |
|
74
|
|
|
|
|
|
|
}, $pkg; |
|
75
|
|
|
|
|
|
|
# remember to unset the ctor error message |
|
76
|
71
|
|
|
|
|
237
|
$pkg->SetError(undef); |
|
77
|
|
|
|
|
|
|
# set the read-only flag if $options matches FASTREADONLY |
|
78
|
71
|
100
|
|
|
|
215
|
$this->{read_only} = $options =~ m/FASTREADONLY/ if $options; |
|
79
|
|
|
|
|
|
|
# execute the following subroutines in an eval block so that |
|
80
|
|
|
|
|
|
|
# errors can be treated without shutting down the caller. |
|
81
|
71
|
|
|
|
|
120
|
my $status = eval { $this->open_input($file_input); |
|
|
71
|
|
|
|
|
235
|
|
|
82
|
69
|
|
|
|
|
309
|
$this->parse_segments($regex) ; }; |
|
83
|
|
|
|
|
|
|
# close the file handle, if open |
|
84
|
71
|
|
|
|
|
372
|
$this->close_input(); |
|
85
|
|
|
|
|
|
|
# If an error was found (and it triggered a die call) |
|
86
|
|
|
|
|
|
|
# we must set the appropriate error variable here |
|
87
|
71
|
50
|
|
|
|
621
|
$pkg->SetError($@) unless $status; |
|
88
|
|
|
|
|
|
|
# return the object reference (undef if an error occurred) |
|
89
|
71
|
100
|
|
|
|
219
|
return $this->Error() ? undef : $this; |
|
90
|
|
|
|
|
|
|
} |
|
91
|
|
|
|
|
|
|
|
|
92
|
|
|
|
|
|
|
########################################################### |
|
93
|
|
|
|
|
|
|
# This block declares a private variable containing a # |
|
94
|
|
|
|
|
|
|
# meaningful error message for problems during the class # |
|
95
|
|
|
|
|
|
|
# constructor. The two following methods allow reading # |
|
96
|
|
|
|
|
|
|
# and setting the value of this variable. # |
|
97
|
|
|
|
|
|
|
########################################################### |
|
98
|
|
|
|
|
|
|
{ my $ctor_error_message = undef; |
|
99
|
75
|
|
100
|
75
|
1
|
72789
|
sub Error { return $ctor_error_message || undef; } |
|
100
|
142
|
|
|
142
|
0
|
299
|
sub SetError { $ctor_error_message = $_[1]; } |
|
101
|
|
|
|
|
|
|
} |
|
102
|
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
########################################################### |
|
104
|
|
|
|
|
|
|
# This method writes the data area of each segment in the # |
|
105
|
|
|
|
|
|
|
# current object to a disk file or a variable in memory. # |
|
106
|
|
|
|
|
|
|
# A disk file is written if $filename is a scalar with a # |
|
107
|
|
|
|
|
|
|
# valid file name; memory is instead used if $filename is # |
|
108
|
|
|
|
|
|
|
# a scalar reference. If $filename is undef, it defaults # |
|
109
|
|
|
|
|
|
|
# to the file originally used to create the current JPEG # |
|
110
|
|
|
|
|
|
|
# structure object. This method returns "true" (1) if it # |
|
111
|
|
|
|
|
|
|
# works, "false" (undef) otherwise. This call fails if # |
|
112
|
|
|
|
|
|
|
# the "read_only" member is set. # |
|
113
|
|
|
|
|
|
|
# ------------------------------------------------------- # |
|
114
|
|
|
|
|
|
|
# Remember that if you make changes to any segment, you # |
|
115
|
|
|
|
|
|
|
# should call update() for that particular segment before # |
|
116
|
|
|
|
|
|
|
# calling this method, otherwise the changes remain confi-# |
|
117
|
|
|
|
|
|
|
# ned to the internal structures of the segment (update() # |
|
118
|
|
|
|
|
|
|
# dumps them into the data area). Note that "high level" # |
|
119
|
|
|
|
|
|
|
# methods, like those in the JPEG_.pl files,# |
|
120
|
|
|
|
|
|
|
# are supposed to call update() on their own. # |
|
121
|
|
|
|
|
|
|
########################################################### |
|
122
|
|
|
|
|
|
|
sub save { |
|
123
|
26
|
|
|
26
|
1
|
7112
|
my ($this, $filename) = @_; |
|
124
|
|
|
|
|
|
|
# fail immediately if "read_only" is set |
|
125
|
26
|
100
|
|
|
|
129
|
return undef if $this->{read_only}; |
|
126
|
|
|
|
|
|
|
# if $filename is undefined, it defaults to the original name |
|
127
|
25
|
50
|
|
|
|
73
|
$filename = $this->{filename} unless defined $filename; |
|
128
|
|
|
|
|
|
|
# Open an IO handler for output on a file named $filename |
|
129
|
|
|
|
|
|
|
# or on an in-memory variable pointed to by $filename. |
|
130
|
|
|
|
|
|
|
# Use an indirect handler, which is closed authomatically |
|
131
|
|
|
|
|
|
|
# when it goes out of scope (so, no need to call close()). |
|
132
|
|
|
|
|
|
|
# If open fails, it returns false and sets the special |
|
133
|
|
|
|
|
|
|
# variable $! to reflect the system error. |
|
134
|
9
|
50
|
|
9
|
|
83
|
open(my $out, '>', $filename) || return undef; |
|
|
9
|
|
|
|
|
13
|
|
|
|
9
|
|
|
|
|
59
|
|
|
|
25
|
|
|
|
|
1782
|
|
|
135
|
|
|
|
|
|
|
# Legacy systems might need an explicit binary open. |
|
136
|
25
|
|
|
|
|
9148
|
binmode($out); |
|
137
|
|
|
|
|
|
|
# For each segment in the segment list, write the content of |
|
138
|
|
|
|
|
|
|
# the data area (including the preamble when needed) to the |
|
139
|
|
|
|
|
|
|
# IO handler. Save the results of each output for later testing. |
|
140
|
25
|
|
|
|
|
44
|
my @results = map { $_->output_segment_data($out) } @{$this->{segments}}; |
|
|
276
|
|
|
|
|
576
|
|
|
|
25
|
|
|
|
|
133
|
|
|
141
|
|
|
|
|
|
|
# return undef if any print failed, true otherwise |
|
142
|
25
|
50
|
|
|
|
66
|
return (scalar grep { ! $_ } @results) ? undef : 1; |
|
|
276
|
|
|
|
|
1043
|
|
|
143
|
|
|
|
|
|
|
} |
|
144
|
|
|
|
|
|
|
|
|
145
|
|
|
|
|
|
|
########################################################### |
|
146
|
|
|
|
|
|
|
# This method takes care to open a file handle pointing # |
|
147
|
|
|
|
|
|
|
# to the JPEG object specified by $file_input. If the # |
|
148
|
|
|
|
|
|
|
# "file name" is a scalar reference instead, it is saved # |
|
149
|
|
|
|
|
|
|
# in the "handle" member (and it must be treated accor- # |
|
150
|
|
|
|
|
|
|
# dingly in the following). Nothing is actually read now; # |
|
151
|
|
|
|
|
|
|
# if opening fails, the routine dies with a message. # |
|
152
|
|
|
|
|
|
|
########################################################### |
|
153
|
|
|
|
|
|
|
sub open_input { |
|
154
|
71
|
|
|
71
|
0
|
119
|
my ($this, $file_input) = @_; |
|
155
|
|
|
|
|
|
|
# protect against undefined values |
|
156
|
71
|
100
|
|
|
|
239
|
$this->die('Undefined input') unless defined $file_input; |
|
157
|
|
|
|
|
|
|
# scalar references: save the reference in $this->{handle} |
|
158
|
|
|
|
|
|
|
# and save a self-explicatory string as file name |
|
159
|
70
|
100
|
|
|
|
234
|
if (ref $file_input eq 'SCALAR') { |
|
160
|
26
|
|
|
|
|
57
|
$this->{handle} = $file_input; |
|
161
|
26
|
|
|
|
|
61
|
$this->{filename} = '[in-memory JPEG stream]'; } |
|
162
|
|
|
|
|
|
|
# real file: we need to open the file and complain if this is |
|
163
|
|
|
|
|
|
|
# not possible (legacy systems might need an explicity binary |
|
164
|
|
|
|
|
|
|
# open); then, the file name of the original file is saved. |
|
165
|
|
|
|
|
|
|
else { |
|
166
|
44
|
100
|
|
|
|
2324
|
open($this->{handle}, '<', $file_input) || |
|
167
|
|
|
|
|
|
|
$this->die("Open error on $file_input: $!"); |
|
168
|
43
|
|
|
|
|
153
|
binmode($this->{handle}); |
|
169
|
43
|
|
|
|
|
187
|
$this->{filename} = $file_input; } |
|
170
|
|
|
|
|
|
|
} |
|
171
|
|
|
|
|
|
|
|
|
172
|
|
|
|
|
|
|
########################################################### |
|
173
|
|
|
|
|
|
|
# This method is the counterpart of "open". Actually, it # |
|
174
|
|
|
|
|
|
|
# does something only for real files (because we do not # |
|
175
|
|
|
|
|
|
|
# want to close in-memory scalars ....). # |
|
176
|
|
|
|
|
|
|
########################################################### |
|
177
|
|
|
|
|
|
|
sub close_input { |
|
178
|
71
|
|
|
71
|
0
|
121
|
my ($this) = @_; |
|
179
|
|
|
|
|
|
|
# $this->{handle} should really be a reference to something |
|
180
|
71
|
100
|
|
|
|
247
|
return unless ref $this->{handle}; |
|
181
|
|
|
|
|
|
|
# a ref to a scalar: we do not want to close in-memory scalars |
|
182
|
70
|
100
|
|
|
|
252
|
return if ref $this->{handle} eq 'SCALAR'; |
|
183
|
|
|
|
|
|
|
# the default action corresponds to closing the filehandle |
|
184
|
44
|
|
|
|
|
2507
|
close $this->{handle}; |
|
185
|
|
|
|
|
|
|
} |
|
186
|
|
|
|
|
|
|
|
|
187
|
|
|
|
|
|
|
########################################################### |
|
188
|
|
|
|
|
|
|
# This method returns a portion of the input file (speci- # |
|
189
|
|
|
|
|
|
|
# fied by $offset and $length). It is necessary to mask # |
|
190
|
|
|
|
|
|
|
# how data reading is actually implemented. As usual, it # |
|
191
|
|
|
|
|
|
|
# dies on errors (but this is trapped in the constructor).# |
|
192
|
|
|
|
|
|
|
# This method returns a scalar reference; if $offset is # |
|
193
|
|
|
|
|
|
|
# just "LENGTH", the input length is returned instead. # |
|
194
|
|
|
|
|
|
|
# A length <= 0 is ignored (ref to empty string). # |
|
195
|
|
|
|
|
|
|
########################################################### |
|
196
|
|
|
|
|
|
|
sub get_data { |
|
197
|
4229
|
|
|
4229
|
0
|
3763
|
my ($this, $offset, $length) = @_; |
|
198
|
|
|
|
|
|
|
# a shorter name for the file handle |
|
199
|
4229
|
|
|
|
|
3814
|
my $handle = $this->{handle}; |
|
200
|
|
|
|
|
|
|
# understand if this is a file or a scalar reference |
|
201
|
4229
|
|
|
|
|
4205
|
my $is_file = ref $handle eq 'GLOB'; |
|
202
|
|
|
|
|
|
|
# if the first argument is just the string 'LENGTH', |
|
203
|
|
|
|
|
|
|
# return the input length instead |
|
204
|
4229
|
100
|
|
|
|
11345
|
return ($is_file ? -s $handle : length $$handle) if $offset eq 'LENGTH'; |
|
|
|
100
|
|
|
|
|
|
|
205
|
|
|
|
|
|
|
# this is the buffer to be returned at the end |
|
206
|
3401
|
|
|
|
|
3046
|
my $data = ''; |
|
207
|
|
|
|
|
|
|
# if length is <= zero return a reference to an empty string |
|
208
|
3401
|
100
|
|
|
|
5242
|
return \ $data if $length <= 0; |
|
209
|
|
|
|
|
|
|
# if we are dealing with a real file, we need to seek to the |
|
210
|
|
|
|
|
|
|
# requested position, then read the appropriate amount of data |
|
211
|
|
|
|
|
|
|
# (and throw an error if reading failed). |
|
212
|
3281
|
100
|
|
|
|
3425
|
if ($is_file) { |
|
213
|
2184
|
50
|
|
|
|
5420
|
seek($handle, $offset, 0) || |
|
214
|
|
|
|
|
|
|
$this->die("Error while seeking in $this->{filename}"); |
|
215
|
2184
|
|
|
|
|
10090
|
my $read = read $handle, $data, $length; |
|
216
|
2184
|
50
|
33
|
|
|
7449
|
$this->die("Read error in $this->{filename}") |
|
217
|
|
|
|
|
|
|
if ! defined $read || $read < $length; } |
|
218
|
|
|
|
|
|
|
# otherwise, we are dealing with a scalar reference, and |
|
219
|
|
|
|
|
|
|
# everything is much simpler (this can't fail, right?) |
|
220
|
1097
|
|
|
|
|
1978
|
else { $data = substr $$handle, $offset, $length; } |
|
221
|
|
|
|
|
|
|
# return a reference to read data |
|
222
|
3281
|
|
|
|
|
8200
|
return \ $data; |
|
223
|
|
|
|
|
|
|
} |
|
224
|
|
|
|
|
|
|
|
|
225
|
|
|
|
|
|
|
########################################################### |
|
226
|
|
|
|
|
|
|
# This method searches for segments in the input JPEG. # |
|
227
|
|
|
|
|
|
|
# When a segment is found, the corresponding data area is # |
|
228
|
|
|
|
|
|
|
# read and used to create a segment object (the ctor of # |
|
229
|
|
|
|
|
|
|
# this object takes care to decode the relevant data). # |
|
230
|
|
|
|
|
|
|
# The object is then inserted into the "segments" hash, # |
|
231
|
|
|
|
|
|
|
# with a code-related key. Raw (compressed) image data # |
|
232
|
|
|
|
|
|
|
# are stored in "fake" segments, just for simplicity. # |
|
233
|
|
|
|
|
|
|
# ------------------------------------------------------- # |
|
234
|
|
|
|
|
|
|
# There is now an argument, set equal to the second argu- # |
|
235
|
|
|
|
|
|
|
# ment of the constructor. If it is defined, only match- # |
|
236
|
|
|
|
|
|
|
# ing segments are parsed. Also, if read_only is set, # |
|
237
|
|
|
|
|
|
|
# only "interesting" segments are saved and everything # |
|
238
|
|
|
|
|
|
|
# after the Start Of Scan is neglected. # |
|
239
|
|
|
|
|
|
|
#=========================================================# |
|
240
|
|
|
|
|
|
|
# Structure of a generic segment: # |
|
241
|
|
|
|
|
|
|
# 2 bytes segment marker (the first byte is always 0xff) # |
|
242
|
|
|
|
|
|
|
# 2 bytes segment_length (it doesn't include the marker) # |
|
243
|
|
|
|
|
|
|
# .... data (segment_length - 2 bytes) # |
|
244
|
|
|
|
|
|
|
#=========================================================# |
|
245
|
|
|
|
|
|
|
# The segment length (2 bytes) has a "Motorola" (big end- # |
|
246
|
|
|
|
|
|
|
# ian) endianness (byte alignement), that is it starts # |
|
247
|
|
|
|
|
|
|
# with the most significant digit. Note that the segment # |
|
248
|
|
|
|
|
|
|
# length marker counts its own length (i.e., after it # |
|
249
|
|
|
|
|
|
|
# there are only segment_length-2 bytes). # |
|
250
|
|
|
|
|
|
|
#=========================================================# |
|
251
|
|
|
|
|
|
|
# Some segments do not have data after them (not even the # |
|
252
|
|
|
|
|
|
|
# length field, they are pure markers): SOI, EOI and the # |
|
253
|
|
|
|
|
|
|
# RST? restart segments. Scans (started by a SOS segment) # |
|
254
|
|
|
|
|
|
|
# are followed by compressed data, with possibly inter- # |
|
255
|
|
|
|
|
|
|
# leaved RST segments: raw data must be searched with a # |
|
256
|
|
|
|
|
|
|
# dedicated routine because they are not envelopped. # |
|
257
|
|
|
|
|
|
|
#=========================================================# |
|
258
|
|
|
|
|
|
|
# Ref: "Digital compression and coding of continuous-tone # |
|
259
|
|
|
|
|
|
|
# still images: requirements and guidelines", # |
|
260
|
|
|
|
|
|
|
# CCITT, 09/1992, sec. B.1.1.4, pag. 33. # |
|
261
|
|
|
|
|
|
|
########################################################### |
|
262
|
|
|
|
|
|
|
sub parse_segments { |
|
263
|
69
|
|
|
69
|
0
|
122
|
my ($this, $regex) = @_; |
|
264
|
|
|
|
|
|
|
# prepare another hash to reverse the JPEG markers lookup |
|
265
|
69
|
|
|
|
|
12324
|
my %JPEG_MARKER_BY_CODE = reverse %JPEG_MARKER; |
|
266
|
|
|
|
|
|
|
# an offset in the input object, and a variable with its size |
|
267
|
69
|
|
|
|
|
613
|
my $offset = 0; |
|
268
|
69
|
|
|
|
|
230
|
my $isize = $this->get_data('LENGTH'); |
|
269
|
|
|
|
|
|
|
# don't claim empty files are valid JPEG pictures |
|
270
|
69
|
100
|
|
|
|
184
|
$this->die('Empty file') unless $isize; |
|
271
|
|
|
|
|
|
|
# loop on input data and find all of its segment |
|
272
|
68
|
|
|
|
|
237
|
while ($offset < $isize) { |
|
273
|
|
|
|
|
|
|
# search for the next JPEG marker, giving the segment type |
|
274
|
696
|
|
|
|
|
1429
|
(my $marker, $offset) = $this->get_next_marker($offset); |
|
275
|
|
|
|
|
|
|
# Die on unknown markers |
|
276
|
693
|
50
|
|
|
|
1560
|
$this->die(sprintf 'Unknown marker found: 0x%02x (offset $offset)', |
|
277
|
|
|
|
|
|
|
$marker) unless exists $JPEG_MARKER_BY_CODE{$marker}; |
|
278
|
|
|
|
|
|
|
# save the current offset (beginning of data) |
|
279
|
693
|
|
|
|
|
682
|
my $start = $offset; |
|
280
|
|
|
|
|
|
|
# calculate the name of the marker |
|
281
|
693
|
|
|
|
|
841
|
my $name = $JPEG_MARKER_BY_CODE{$marker}; |
|
282
|
|
|
|
|
|
|
# determine the parse flag |
|
283
|
693
|
100
|
100
|
|
|
2465
|
my $flag = ($regex && $name !~ /$regex/) ? 'NOPARSE' : undef; |
|
284
|
|
|
|
|
|
|
# SOI, EOI and ReSTart are dataless segments |
|
285
|
693
|
100
|
|
|
|
592
|
my $length = 0; goto DECODE_LENGTH_END if $name =~ /^RST|EOI|SOI/; |
|
|
693
|
|
|
|
|
2798
|
|
|
286
|
568
|
50
|
|
|
|
1051
|
DECODE_LENGTH_START: |
|
287
|
|
|
|
|
|
|
# we need at least two bytes here |
|
288
|
|
|
|
|
|
|
$this->die('Segment size not found') unless $isize > $offset + 2; |
|
289
|
|
|
|
|
|
|
# decode the length of this application block (2 bytes). |
|
290
|
|
|
|
|
|
|
# This is always in big endian ("Motorola") style, that |
|
291
|
|
|
|
|
|
|
# is the first byte is the most significant one. |
|
292
|
568
|
|
|
|
|
507
|
$length = unpack 'n', ${$this->get_data($offset, 2)}; |
|
|
568
|
|
|
|
|
818
|
|
|
293
|
|
|
|
|
|
|
# the segment length includes the two aforementioned |
|
294
|
|
|
|
|
|
|
# bytes, so the length must be at least two |
|
295
|
568
|
50
|
|
|
|
1113
|
$this->die('JPEG segment too small') if $length < 2; |
|
296
|
693
|
100
|
|
|
|
1228
|
DECODE_LENGTH_END: |
|
297
|
|
|
|
|
|
|
# we need at least $length bytes here |
|
298
|
|
|
|
|
|
|
$this->die('Segment data not found') unless $isize >= $offset+$length; |
|
299
|
|
|
|
|
|
|
# pass the data to a segment object and store it, unless |
|
300
|
|
|
|
|
|
|
# the "read_only" member is set and $flag is "NOPARSE". |
|
301
|
|
|
|
|
|
|
# (don't pass $flag to dataless segments, it is just silly). |
|
302
|
692
|
100
|
100
|
|
|
1685
|
push @{$this->{segments}}, new Image::MetaData::JPEG::Segment |
|
|
633
|
100
|
|
|
|
1598
|
|
|
303
|
|
|
|
|
|
|
($name, $this->get_data($start + 2, $length - 2), |
|
304
|
|
|
|
|
|
|
$length ? $flag : undef) unless $this->{read_only} && $flag; |
|
305
|
|
|
|
|
|
|
# update offset |
|
306
|
692
|
|
|
|
|
920
|
$offset += $length; |
|
307
|
|
|
|
|
|
|
# When you find a SOS marker or a RST marker there is a special |
|
308
|
|
|
|
|
|
|
# treatement; if "read_only" is set, we neglect the rest of the |
|
309
|
|
|
|
|
|
|
# input. Otherwise, we need a special routine |
|
310
|
692
|
100
|
|
|
|
2283
|
if ($name =~ /SOS|^RST/) { |
|
311
|
69
|
100
|
|
|
|
661
|
$offset = $isize, next if $this->{read_only}; |
|
312
|
63
|
|
|
|
|
189
|
$offset = $this->parse_ecs($offset); } |
|
313
|
|
|
|
|
|
|
DECODE_PAST_EOI_GARBAGE: |
|
314
|
|
|
|
|
|
|
# Try to intercept underground data stored after the EOI segment; |
|
315
|
|
|
|
|
|
|
# I have found images which store multiple reduced versions of |
|
316
|
|
|
|
|
|
|
# itself after the EOI segment, as well as undocumented binary |
|
317
|
|
|
|
|
|
|
# and ascii data. Save them in a pseudo-segment, so that they |
|
318
|
|
|
|
|
|
|
# can be restored (take "read_only" into account). |
|
319
|
686
|
100
|
100
|
|
|
4135
|
if ($name eq 'EOI' && $offset < $isize) { |
|
320
|
38
|
|
|
|
|
69
|
my $len = $isize - $offset; |
|
321
|
38
|
50
|
|
|
|
110
|
push @{$this->{segments}}, new Image::MetaData::JPEG::Segment |
|
|
38
|
|
|
|
|
112
|
|
|
322
|
|
|
|
|
|
|
('Post-EOI', $this->get_data($offset, $len), 'NOPARSE') |
|
323
|
|
|
|
|
|
|
unless $this->{read_only}; |
|
324
|
38
|
|
|
|
|
3055
|
$offset += $len; |
|
325
|
|
|
|
|
|
|
} |
|
326
|
|
|
|
|
|
|
} |
|
327
|
|
|
|
|
|
|
} |
|
328
|
|
|
|
|
|
|
|
|
329
|
|
|
|
|
|
|
########################################################### |
|
330
|
|
|
|
|
|
|
# This method searches for the next JPEG marker in the # |
|
331
|
|
|
|
|
|
|
# stream being parsed. A marker is always assigned a two # |
|
332
|
|
|
|
|
|
|
# byte code: an 0xff byte followed by a byte which is not # |
|
333
|
|
|
|
|
|
|
# 0x00 nor 0xff. Any marker may optionally be preceeded # |
|
334
|
|
|
|
|
|
|
# by any number of fill bytes (padding of the previous # |
|
335
|
|
|
|
|
|
|
# segment, I suppose), set to 0xff. Most markers start # |
|
336
|
|
|
|
|
|
|
# marker segments containing a related group of parame- # |
|
337
|
|
|
|
|
|
|
# ters; some markers stand alone. The return value is a # |
|
338
|
|
|
|
|
|
|
# list containing the numeric value of the second marker # |
|
339
|
|
|
|
|
|
|
# byte and an offset pointing just after it. # |
|
340
|
|
|
|
|
|
|
# ------------------------------------------------------- # |
|
341
|
|
|
|
|
|
|
# An old version of "Arles Image Web Page Creator" had a # |
|
342
|
|
|
|
|
|
|
# bug which caused the application to generate JPEG's # |
|
343
|
|
|
|
|
|
|
# with illegal comment segments, reportedly due to a bug # |
|
344
|
|
|
|
|
|
|
# in the Intel JPEG library the developers used at that # |
|
345
|
|
|
|
|
|
|
# time (these segments had to 0x00 bytes appended). It is # |
|
346
|
|
|
|
|
|
|
# true that a JPEG file with garbage between segments is # |
|
347
|
|
|
|
|
|
|
# to be considered invalid, but some libraries like IJG's # |
|
348
|
|
|
|
|
|
|
# try to forgive, so we try to forgive too, if the amount # |
|
349
|
|
|
|
|
|
|
# of garbage is not too large ... # |
|
350
|
|
|
|
|
|
|
#=========================================================# |
|
351
|
|
|
|
|
|
|
# Ref: "Digital compression and coding of continuous-tone # |
|
352
|
|
|
|
|
|
|
# still images: requirements and guidelines", # |
|
353
|
|
|
|
|
|
|
# CCITT, 09/1992, sec. B.1.1.2, pag. 31. # |
|
354
|
|
|
|
|
|
|
#=========================================================# |
|
355
|
|
|
|
|
|
|
sub get_next_marker { |
|
356
|
696
|
|
|
696
|
0
|
748
|
my ($this, $offset) = @_; |
|
357
|
696
|
|
|
|
|
981
|
my $punctuation = chr $JPEG_PUNCTUATION; my $garbage = 0; |
|
|
696
|
|
|
|
|
646
|
|
|
358
|
|
|
|
|
|
|
# this is the upper limit to $offset |
|
359
|
696
|
|
|
|
|
1139
|
my $length = $this->get_data('LENGTH'); |
|
360
|
|
|
|
|
|
|
# $offset should point at the beginning of a new segment, |
|
361
|
|
|
|
|
|
|
# so the next byte should be 0xff. However, sometimes garbage |
|
362
|
|
|
|
|
|
|
# slips in ... Forgive this bug if garbage is not too much |
|
363
|
|
|
|
|
|
|
$offset < $length && ${$this->get_data($offset, 1)} eq $punctuation |
|
364
|
696
|
100
|
100
|
|
|
1934
|
? last : (++$garbage, ++$offset) for (0..10); |
|
365
|
696
|
100
|
|
|
|
1573
|
$this->die('Next marker not found') unless $length - $offset > 1; |
|
366
|
|
|
|
|
|
|
# it is assumed that we are now at the beginning of |
|
367
|
|
|
|
|
|
|
# a new segment, so the next byte must be 0xff. |
|
368
|
694
|
|
|
|
|
588
|
my $marker_byte = ${$this->get_data($offset++, 1)}; |
|
|
694
|
|
|
|
|
1190
|
|
|
369
|
694
|
100
|
|
|
|
1284
|
$this->die(sprintf 'Unknown punctuation (0x%02x) at offset 0x%x', |
|
370
|
|
|
|
|
|
|
ord($marker_byte), $offset) if $marker_byte ne $punctuation; |
|
371
|
|
|
|
|
|
|
# report about garbage, unless we died |
|
372
|
693
|
100
|
|
|
|
1065
|
$this->warn("Skipping $garbage garbage bytes") if $garbage; |
|
373
|
|
|
|
|
|
|
# next byte can be either the marker type or a padding |
|
374
|
|
|
|
|
|
|
# byte equal to 0xff (skip it if it's a padding byte) |
|
375
|
693
|
|
|
|
|
1184
|
$marker_byte = ${$this->get_data($offset++, 1)} |
|
|
693
|
|
|
|
|
1061
|
|
|
376
|
|
|
|
|
|
|
while $marker_byte eq $punctuation; |
|
377
|
|
|
|
|
|
|
# return the marker we have found (no check on its validity), |
|
378
|
|
|
|
|
|
|
# as well as the offset to the next byte in the JPEG stream |
|
379
|
693
|
|
|
|
|
1163
|
return (ord($marker_byte), $offset); |
|
380
|
|
|
|
|
|
|
} |
|
381
|
|
|
|
|
|
|
|
|
382
|
|
|
|
|
|
|
########################################################### |
|
383
|
|
|
|
|
|
|
# This method reads in a compressed (entropy coded) data # |
|
384
|
|
|
|
|
|
|
# segment (ECS) and saves it as a "pseudo" segment. The # |
|
385
|
|
|
|
|
|
|
# argument is the current offset in the in-memory JPEG # |
|
386
|
|
|
|
|
|
|
# stream, the result is the updated offset. These pseudo # |
|
387
|
|
|
|
|
|
|
# segments can be found after a Start-Of-Scan segment, # |
|
388
|
|
|
|
|
|
|
# and, if restart is enabled, they can be interleaved # |
|
389
|
|
|
|
|
|
|
# with restart segments (RST). Indeed, an ECS is not a # |
|
390
|
|
|
|
|
|
|
# real segment, because it does not start with a marker # |
|
391
|
|
|
|
|
|
|
# and its length is not known a priori. However, it is # |
|
392
|
|
|
|
|
|
|
# easy to detect its end since a regular marker cannot # |
|
393
|
|
|
|
|
|
|
# appear inside it. In practice, data in an ECS are coded # |
|
394
|
|
|
|
|
|
|
# in such a way that a 0xff byte can only be followed by # |
|
395
|
|
|
|
|
|
|
# 0x00 (invalid marker) or 0xff (padding). # |
|
396
|
|
|
|
|
|
|
#=========================================================# |
|
397
|
|
|
|
|
|
|
# WARNING: when restart is enabled, usually the file con- # |
|
398
|
|
|
|
|
|
|
# tains a lot of ECS and RST. In order not to be too slow # |
|
399
|
|
|
|
|
|
|
# we keep the restart marker embedded in row data here. # |
|
400
|
|
|
|
|
|
|
#=========================================================# |
|
401
|
|
|
|
|
|
|
# Ref: "Digital compression and coding of continuous-tone # |
|
402
|
|
|
|
|
|
|
# still images: requirements and guidelines", # |
|
403
|
|
|
|
|
|
|
# CCITT, 09/1992, sec. B.1.1.5, pag. 33. # |
|
404
|
|
|
|
|
|
|
########################################################### |
|
405
|
|
|
|
|
|
|
sub parse_ecs { |
|
406
|
63
|
|
|
63
|
0
|
95
|
my ($this, $offset) = @_; |
|
407
|
|
|
|
|
|
|
# A title for a raw data block ('ECS' must be there) |
|
408
|
63
|
|
|
|
|
94
|
my $ecs_name = 'ECS (Raw data)'; |
|
409
|
|
|
|
|
|
|
# transform the JPEG punctuation value into a string |
|
410
|
63
|
|
|
|
|
112
|
my $punctuation = chr $JPEG_PUNCTUATION; |
|
411
|
|
|
|
|
|
|
# create a string containing the character which can follow a |
|
412
|
|
|
|
|
|
|
# punctuations mark without causing the ECS to be considered |
|
413
|
|
|
|
|
|
|
# terminated. This string must contain at least the null byte and |
|
414
|
|
|
|
|
|
|
# the punctuation mark itself. But, for efficiency reasons, we are |
|
415
|
|
|
|
|
|
|
# going to include also the restart markers here. |
|
416
|
63
|
|
|
|
|
105
|
my $skipstring = $punctuation . chr 0x00; |
|
417
|
63
|
|
|
|
|
369
|
$skipstring .= chr $_ for ($JPEG_MARKER{RST0} .. $JPEG_MARKER{RST7}); |
|
418
|
|
|
|
|
|
|
# read in everything till the end of the input |
|
419
|
63
|
|
|
|
|
153
|
my $length = $this->get_data('LENGTH'); |
|
420
|
63
|
|
|
|
|
164
|
my $buffer = $this->get_data($offset, $length - $offset); |
|
421
|
|
|
|
|
|
|
# find the next 0xff byte not followed by a character of $skipstring |
|
422
|
|
|
|
|
|
|
# from $offset on. It is better to use pos() instead of taking a |
|
423
|
|
|
|
|
|
|
# substring of $$buffer, because this copy takes a lot of space. In |
|
424
|
|
|
|
|
|
|
# order to honour the position set by pos(), it is necessary to use |
|
425
|
|
|
|
|
|
|
# "g" in scalar context. My benchmarks say this is almost as fast as C. |
|
426
|
63
|
|
|
|
|
297
|
pos($$buffer) = 0; scalar $$buffer =~ /$punctuation[^$skipstring]/g; |
|
|
63
|
|
|
|
|
1762
|
|
|
427
|
|
|
|
|
|
|
# trim the $buffer at the byte before the punctuation mark; the |
|
428
|
|
|
|
|
|
|
# position of the last match can be accessed through pos(); if no |
|
429
|
|
|
|
|
|
|
# match is found, complain but do not fail (similar behaviour to that |
|
430
|
|
|
|
|
|
|
# of the 'xv' program); the file is however corrupt and unusable. |
|
431
|
63
|
50
|
|
|
|
1011
|
pos($$buffer) ? substr($$buffer, pos($$buffer) - 2) = '' |
|
432
|
|
|
|
|
|
|
: $this->warn('Premature end of JPEG stream'); |
|
433
|
|
|
|
|
|
|
# push a pseudo segment among the regular ones (do not parse it) |
|
434
|
63
|
|
|
|
|
94
|
push @{$this->{segments}}, new Image::MetaData::JPEG::Segment |
|
|
63
|
|
|
|
|
290
|
|
|
435
|
|
|
|
|
|
|
($ecs_name, $buffer, 'NOPARSE'); |
|
436
|
|
|
|
|
|
|
# return the updated offset |
|
437
|
63
|
|
|
|
|
172
|
return $offset + length $$buffer; |
|
438
|
|
|
|
|
|
|
} |
|
439
|
|
|
|
|
|
|
|
|
440
|
|
|
|
|
|
|
########################################################### |
|
441
|
|
|
|
|
|
|
# This method creates a list containing the references # |
|
442
|
|
|
|
|
|
|
# (or their indexes in the segment references list, if # |
|
443
|
|
|
|
|
|
|
# the second argument is 'INDEXES') of those segments # |
|
444
|
|
|
|
|
|
|
# whose name matches a given regular expression. # |
|
445
|
|
|
|
|
|
|
# The output can be invalid after adding/removing any # |
|
446
|
|
|
|
|
|
|
# segment. If $regex is undefined or evaluates to the # |
|
447
|
|
|
|
|
|
|
# empty string, this method returns all indexes. # |
|
448
|
|
|
|
|
|
|
########################################################### |
|
449
|
|
|
|
|
|
|
sub get_segments { |
|
450
|
678
|
|
|
678
|
1
|
15512
|
my ($this, $regex, $do_indexes) = @_; |
|
451
|
|
|
|
|
|
|
# fix the regular expression to '.' if undefined or set to the |
|
452
|
|
|
|
|
|
|
# empty string. I do this because I want to avoid the stupid |
|
453
|
|
|
|
|
|
|
# behaviour of m//; from `man perlop`: if the pattern evaluates |
|
454
|
|
|
|
|
|
|
# to the empty string, the last successfully matched regular |
|
455
|
|
|
|
|
|
|
# expression is used instead; if no match has previously succeeded, |
|
456
|
|
|
|
|
|
|
# this will (silently) act instead as a genuine empty pattern |
|
457
|
678
|
100
|
100
|
|
|
2741
|
$regex = '.' unless defined $regex && length $regex > 0; |
|
458
|
|
|
|
|
|
|
# get the list of segment references in this file |
|
459
|
678
|
|
|
|
|
993
|
my $segments = $this->{segments}; |
|
460
|
|
|
|
|
|
|
# return the list of matched segments |
|
461
|
1539
|
|
|
|
|
3125
|
return (defined $do_indexes && $do_indexes eq 'INDEXES') ? |
|
462
|
6580
|
|
|
|
|
14590
|
grep { $$segments[$_]->{name} =~ /$regex/ } 0..$#$segments : |
|
463
|
678
|
100
|
66
|
|
|
2370
|
grep { $_->{name} =~ /$regex/ } @$segments; |
|
464
|
|
|
|
|
|
|
} |
|
465
|
|
|
|
|
|
|
|
|
466
|
|
|
|
|
|
|
########################################################### |
|
467
|
|
|
|
|
|
|
# This method erases from the internal segment list all # |
|
468
|
|
|
|
|
|
|
# segments matching the $regex regular expression. If # |
|
469
|
|
|
|
|
|
|
# $regex is undefined or evaluates to the empty string, # |
|
470
|
|
|
|
|
|
|
# this method throws an exception, because I don't want # |
|
471
|
|
|
|
|
|
|
# the user to erase the whole file just because he/she # |
|
472
|
|
|
|
|
|
|
# did not understand what he was doing. The apocalyptic # |
|
473
|
|
|
|
|
|
|
# behaviour can be forced by setting $regex = '.'. One # |
|
474
|
|
|
|
|
|
|
# must remember that it is not wise to drop non-metadata # |
|
475
|
|
|
|
|
|
|
# segments, because this in general invalidates the file. # |
|
476
|
|
|
|
|
|
|
# As a special case, if $regex == 'METADATA', all APP* # |
|
477
|
|
|
|
|
|
|
# and COM segments are erased. # |
|
478
|
|
|
|
|
|
|
########################################################### |
|
479
|
|
|
|
|
|
|
sub drop_segments { |
|
480
|
30
|
|
|
30
|
1
|
3427
|
my ($this, $regex) = @_; |
|
481
|
|
|
|
|
|
|
# refuse to work with empty or undefined regular expressions |
|
482
|
30
|
100
|
100
|
|
|
179
|
$this->die('regular expression not specified') |
|
483
|
|
|
|
|
|
|
unless defined $regex && length $regex > 0; |
|
484
|
|
|
|
|
|
|
# if $regex is 'METADATA', convert it |
|
485
|
26
|
100
|
|
|
|
79
|
$regex = '^(APP\d{1,2}|COM)$' if $regex eq 'METADATA'; |
|
486
|
|
|
|
|
|
|
# rewrite the segment list keeping only segments not matching |
|
487
|
|
|
|
|
|
|
# $regex (see get_segments for further considerations). |
|
488
|
26
|
|
|
|
|
706
|
@{$this->{segments}} = |
|
|
354
|
|
|
|
|
764
|
|
|
489
|
26
|
|
|
|
|
43
|
grep { $_->{name} !~ /$regex/ } @{$this->{segments}}; |
|
|
26
|
|
|
|
|
103
|
|
|
490
|
|
|
|
|
|
|
} |
|
491
|
|
|
|
|
|
|
|
|
492
|
|
|
|
|
|
|
########################################################### |
|
493
|
|
|
|
|
|
|
# This method inserts the segments referenced by $segref # |
|
494
|
|
|
|
|
|
|
# into the current list of segments at position $pos. If # |
|
495
|
|
|
|
|
|
|
# $segref is undefined, the method fails silently. If # |
|
496
|
|
|
|
|
|
|
# $pos is undefined, the position is chosen automatically # |
|
497
|
|
|
|
|
|
|
# (using find_new_app_segment_position); if $pos is out # |
|
498
|
|
|
|
|
|
|
# of bound, an exception is thrown; this happens also if # |
|
499
|
|
|
|
|
|
|
# $pos points to the first segment, and it is SOI. # |
|
500
|
|
|
|
|
|
|
# $segref may be a reference to a single segment or a # |
|
501
|
|
|
|
|
|
|
# reference to a list of segment references; everything # |
|
502
|
|
|
|
|
|
|
# else throws an exception. If overwrite is defined, it # |
|
503
|
|
|
|
|
|
|
# must be the number of segs to overwrite during splice. # |
|
504
|
|
|
|
|
|
|
########################################################### |
|
505
|
|
|
|
|
|
|
sub insert_segments { |
|
506
|
56
|
|
|
56
|
1
|
5076
|
my ($this, $segref, $pos, $overwrite) = @_; |
|
507
|
|
|
|
|
|
|
# do nothing if $segref is undefined or is not a reference |
|
508
|
56
|
100
|
|
|
|
141
|
return unless ref $segref; |
|
509
|
|
|
|
|
|
|
# segref may be a reference to a segment or a reference |
|
510
|
|
|
|
|
|
|
# to a list; we must turn it into a reference to a list |
|
511
|
55
|
100
|
|
|
|
179
|
$segref = [ $segref ] unless ref $segref eq 'ARRAY'; |
|
512
|
|
|
|
|
|
|
# check that all elements in the list are segment references |
|
513
|
|
|
|
|
|
|
ref $_ eq 'Image::MetaData::JPEG::Segment' || |
|
514
|
55
|
|
33
|
|
|
188
|
$this->die('$segref is not a reference') for @$segref; |
|
515
|
|
|
|
|
|
|
# calculate a convenient position if the user neglects to; |
|
516
|
|
|
|
|
|
|
# remember to pass the new segment name as an argument |
|
517
|
55
|
50
|
|
|
|
166
|
$pos = $this->find_new_app_segment_position |
|
|
|
100
|
|
|
|
|
|
|
518
|
|
|
|
|
|
|
(exists $$segref[0] ? $$segref[0]->{name} : undef) unless defined $pos; |
|
519
|
55
|
|
|
|
|
100
|
my $max_pos = -1 + $this->get_segments(); |
|
520
|
|
|
|
|
|
|
# fail if $pos is negative or out-of-bound; |
|
521
|
55
|
100
|
66
|
|
|
296
|
$this->die("out-of-bound position $pos [0, $max_pos]") |
|
522
|
|
|
|
|
|
|
if $pos < 0 || $pos > $max_pos; |
|
523
|
|
|
|
|
|
|
# fail if $pos points to the first segment and it is SOI |
|
524
|
54
|
100
|
100
|
|
|
162
|
$this->die('inserting on start-of-image is forbidden') |
|
525
|
|
|
|
|
|
|
if $pos == 0 && $this->{segments}->[0]->{name} eq 'SOI'; |
|
526
|
|
|
|
|
|
|
# do the actual insertion (one or multiple segments); |
|
527
|
|
|
|
|
|
|
# if overwrite is defined, it must be the number of |
|
528
|
|
|
|
|
|
|
# segments to overwrite during the splice. |
|
529
|
53
|
100
|
|
|
|
105
|
$overwrite = 0 unless defined $overwrite; |
|
530
|
53
|
|
|
|
|
63
|
splice @{$this->{segments}}, $pos, $overwrite, @$segref; |
|
|
53
|
|
|
|
|
234
|
|
|
531
|
|
|
|
|
|
|
} |
|
532
|
|
|
|
|
|
|
|
|
533
|
|
|
|
|
|
|
########################################################### |
|
534
|
|
|
|
|
|
|
# This method finds a position for a new application or # |
|
535
|
|
|
|
|
|
|
# comment segment to be placed in the file. The algorithm # |
|
536
|
|
|
|
|
|
|
# is the following: the position is chosen immediately # |
|
537
|
|
|
|
|
|
|
# before the first (or after the last) element of some # |
|
538
|
|
|
|
|
|
|
# list, provided that the list is not empty, otherwise # |
|
539
|
|
|
|
|
|
|
# the next list is taken into account: # |
|
540
|
|
|
|
|
|
|
# -) [for COM segments only] try after 'COM' segments; # |
|
541
|
|
|
|
|
|
|
# otherwise try after all APP segments; # |
|
542
|
|
|
|
|
|
|
# -) [for APPx segments only] try after the last element # |
|
543
|
|
|
|
|
|
|
# of the list of APPy's (with y = x..0, in sequence); # |
|
544
|
|
|
|
|
|
|
# otherwise try before the first element of the list # |
|
545
|
|
|
|
|
|
|
# of APPy's (with y = x+1..15, in sequence); # |
|
546
|
|
|
|
|
|
|
# -) try before the first DHP segment # |
|
547
|
|
|
|
|
|
|
# -) try before the first SOF segment # |
|
548
|
|
|
|
|
|
|
# If all these approaches fail, this method returns the # |
|
549
|
|
|
|
|
|
|
# position immediately after the SOI segment (i.e., 1). # |
|
550
|
|
|
|
|
|
|
# ------------------------------------------------------- # |
|
551
|
|
|
|
|
|
|
# The argument must be the name of the segment to be # |
|
552
|
|
|
|
|
|
|
# inserted (it defaults to 'COM', producing a warning). # |
|
553
|
|
|
|
|
|
|
########################################################### |
|
554
|
|
|
|
|
|
|
sub find_new_app_segment_position { |
|
555
|
32
|
|
|
32
|
1
|
2263
|
my ($this, $name) = @_; |
|
556
|
|
|
|
|
|
|
# if name is not specified, issue a warning and set 'COM' |
|
557
|
32
|
100
|
|
|
|
79
|
$this->warn('Segment name not specified: using COM'), $name = 'COM' |
|
558
|
|
|
|
|
|
|
unless $name; |
|
559
|
|
|
|
|
|
|
# setting $name to something else than 'COM' or 'APPx' is an error |
|
560
|
32
|
50
|
|
|
|
176
|
$this->die("Unknown segment name ($name)") |
|
561
|
|
|
|
|
|
|
unless $name =~ /^(COM|APP([0-9]|1[0-5]))$/; |
|
562
|
|
|
|
|
|
|
# just in order to avoid a warning for half-read files |
|
563
|
|
|
|
|
|
|
# with an incomplete set of segments, let us make sure |
|
564
|
|
|
|
|
|
|
# that no position is past the segment array end |
|
565
|
32
|
|
|
|
|
72
|
my $last_segment = -1 + $this->get_segments(); |
|
566
|
32
|
100
|
|
32
|
|
124
|
my $safe = sub { ($last_segment < $_[0]) ? $last_segment : $_[0] }; |
|
|
32
|
|
|
|
|
249
|
|
|
567
|
|
|
|
|
|
|
# this private function returns a list containing the |
|
568
|
|
|
|
|
|
|
# indexes of the segments whose name matches the argument |
|
569
|
32
|
|
|
105
|
|
109
|
my $list = sub { $this->get_segments('^'.$_[0].'$', 'INDEXES') }; |
|
|
105
|
|
|
|
|
214
|
|
|
570
|
|
|
|
|
|
|
# if there are already some 'COM' segments, let us put the new COM |
|
571
|
|
|
|
|
|
|
# segment immediately after them; otherwise try after all APP segments |
|
572
|
32
|
100
|
|
|
|
108
|
if ($name =~ /^COM/) { |
|
573
|
12
|
|
|
|
|
21
|
return &$safe(1+$_) for reverse &$list('COM'); |
|
574
|
7
|
|
|
|
|
18
|
return &$safe(1+$_) for reverse &$list('APP.*'); } |
|
575
|
|
|
|
|
|
|
# if $name is APPx, try after the last element of the list of APPy's |
|
576
|
|
|
|
|
|
|
# (with y = x .. 0, in sequence); if all these fail, try before the |
|
577
|
|
|
|
|
|
|
# first element of the list of APPy's (with y = x+1..15, in sequence) |
|
578
|
22
|
100
|
|
|
|
143
|
if ($name =~ /^APP(.*)$/) { |
|
579
|
20
|
|
|
|
|
133
|
for (reverse 0..$1) {return &$safe(1+$_) for reverse &$list("APP$_");}; |
|
|
76
|
|
|
|
|
158
|
|
|
580
|
2
|
|
|
|
|
9
|
for (1+$1..15) { return &$safe($_) for &$list("APP$_"); }; } |
|
|
4
|
|
|
|
|
9
|
|
|
581
|
|
|
|
|
|
|
# if all specific tests failed, try with the |
|
582
|
|
|
|
|
|
|
# first DHP segment or the first SOF segment |
|
583
|
3
|
|
|
|
|
14
|
return &$safe($_) for &$list('DHP'); |
|
584
|
3
|
|
|
|
|
8
|
return &$safe($_) for &$list('SOF'); |
|
585
|
|
|
|
|
|
|
# if even this fails, try after start-of-image (just in order |
|
586
|
|
|
|
|
|
|
# to avoid a warning for half-read files with not even two |
|
587
|
|
|
|
|
|
|
# segments (they cannot be saved), return 0 if necessary) |
|
588
|
3
|
|
|
|
|
9
|
return &$safe(1); |
|
589
|
|
|
|
|
|
|
} |
|
590
|
|
|
|
|
|
|
|
|
591
|
|
|
|
|
|
|
########################################################### |
|
592
|
|
|
|
|
|
|
# Load other parts for this package. In order to avoid # |
|
593
|
|
|
|
|
|
|
# that this file becomes too large, only general interest # |
|
594
|
|
|
|
|
|
|
# methods are written here. # |
|
595
|
|
|
|
|
|
|
########################################################### |
|
596
|
|
|
|
|
|
|
require 'Image/MetaData/JPEG/access/various.pl'; |
|
597
|
|
|
|
|
|
|
require 'Image/MetaData/JPEG/access/comments.pl'; |
|
598
|
|
|
|
|
|
|
require 'Image/MetaData/JPEG/access/app1_exif.pl'; |
|
599
|
|
|
|
|
|
|
require 'Image/MetaData/JPEG/access/app13.pl'; |
|
600
|
|
|
|
|
|
|
|
|
601
|
|
|
|
|
|
|
# successful package load |
|
602
|
|
|
|
|
|
|
1; |