1 | #------------------------------------------------------------------------------
|
---|
2 | # File: MakerNotes.pm
|
---|
3 | #
|
---|
4 | # Description: Read and write EXIF maker notes
|
---|
5 | #
|
---|
6 | # Revisions: 11/11/2004 - P. Harvey Created
|
---|
7 | #------------------------------------------------------------------------------
|
---|
8 |
|
---|
9 | package Image::ExifTool::MakerNotes;
|
---|
10 |
|
---|
11 | use strict;
|
---|
12 | use vars qw($VERSION);
|
---|
13 | use Image::ExifTool qw(:DataAccess);
|
---|
14 | use Image::ExifTool::Exif;
|
---|
15 |
|
---|
16 | sub ProcessUnknown($$$);
|
---|
17 |
|
---|
18 | $VERSION = '1.34';
|
---|
19 |
|
---|
20 | my $debug; # set to 1 to enabled debugging code
|
---|
21 |
|
---|
22 | # conditional list of maker notes
|
---|
23 | # Notes:
|
---|
24 | # - This is NOT a normal tag table!
|
---|
25 | # - All byte orders are now specified because we can now
|
---|
26 | # write maker notes into a file with different byte ordering!
|
---|
27 | # - Put these in alphabetical order to make TagNames documentation nicer.
|
---|
28 | @Image::ExifTool::MakerNotes::Main = (
|
---|
29 | # decide which MakerNotes to use (based on camera make/model)
|
---|
30 | {
|
---|
31 | Name => 'MakerNoteCanon',
|
---|
32 | # (starts with an IFD)
|
---|
33 | Condition => '$self->{CameraMake} =~ /^Canon/',
|
---|
34 | SubDirectory => {
|
---|
35 | TagTable => 'Image::ExifTool::Canon::Main',
|
---|
36 | ByteOrder => 'Unknown',
|
---|
37 | },
|
---|
38 | },
|
---|
39 | {
|
---|
40 | Name => 'MakerNoteCasio',
|
---|
41 | # do negative lookahead assertion just to get tags
|
---|
42 | # in a nice order for documentation
|
---|
43 | # (starts with an IFD)
|
---|
44 | Condition => '$self->{CameraMake}=~/^CASIO(?! COMPUTER CO.,LTD)/',
|
---|
45 | SubDirectory => {
|
---|
46 | TagTable => 'Image::ExifTool::Casio::Main',
|
---|
47 | ByteOrder => 'Unknown',
|
---|
48 | },
|
---|
49 | },
|
---|
50 | {
|
---|
51 | Name => 'MakerNoteCasio2',
|
---|
52 | # (starts with "QVC\0")
|
---|
53 | Condition => '$self->{CameraMake}=~/^CASIO COMPUTER CO.,LTD/',
|
---|
54 | SubDirectory => {
|
---|
55 | TagTable => 'Image::ExifTool::Casio::Type2',
|
---|
56 | Start => '$valuePtr + 6',
|
---|
57 | ByteOrder => 'Unknown',
|
---|
58 | },
|
---|
59 | },
|
---|
60 | {
|
---|
61 | # The Fuji programmers really botched this one up,
|
---|
62 | # but with a bit of work we can still read this directory
|
---|
63 | Name => 'MakerNoteFujiFilm',
|
---|
64 | # (starts with "FUJIFILM" -- also used by some Leica, Minolta and Sharp models)
|
---|
65 | Condition => '$$valPt =~ /^FUJIFILM/',
|
---|
66 | SubDirectory => {
|
---|
67 | TagTable => 'Image::ExifTool::FujiFilm::Main',
|
---|
68 | # there is an 8-byte maker tag (FUJIFILM) we must skip over
|
---|
69 | OffsetPt => '$valuePtr+8',
|
---|
70 | # the pointers are relative to the subdirectory start
|
---|
71 | # (before adding the offsetPt) - PH
|
---|
72 | Base => '$start',
|
---|
73 | ByteOrder => 'LittleEndian',
|
---|
74 | },
|
---|
75 | },
|
---|
76 | {
|
---|
77 | Name => 'MakerNoteHP', # PhotoSmart 720 (also Vivitar 3705, 3705B and 3715)
|
---|
78 | Condition => '$$valPt =~ /^(Hewlett-Packard|Vivitar)/',
|
---|
79 | SubDirectory => {
|
---|
80 | TagTable => 'Image::ExifTool::HP::Main',
|
---|
81 | ProcessProc => \&ProcessUnknown,
|
---|
82 | ByteOrder => 'Unknown',
|
---|
83 | },
|
---|
84 | },
|
---|
85 | {
|
---|
86 | Name => 'MakerNoteHP2', # PhotoSmart E427
|
---|
87 | Condition => q{
|
---|
88 | $self->{CameraMake} =~ /^Hewlett-Packard/ and
|
---|
89 | $$valPt !~ /^.{8}Hewlett-Packard/s and
|
---|
90 | $$valPt !~ /^IIII/ and $$valPt =~ /^\d{3}.\0/s
|
---|
91 | },
|
---|
92 | NotIFD => 1,
|
---|
93 | SubDirectory => {
|
---|
94 | TagTable => 'Image::ExifTool::HP::Type2',
|
---|
95 | Start => '$valuePtr',
|
---|
96 | ByteOrder => 'LittleEndian',
|
---|
97 | },
|
---|
98 | },
|
---|
99 | {
|
---|
100 | Name => 'MakerNoteHP4', # PhotoSmart M627
|
---|
101 | Condition => '$$valPt =~ /^IIII\x04\0/',
|
---|
102 | NotIFD => 1,
|
---|
103 | SubDirectory => {
|
---|
104 | TagTable => 'Image::ExifTool::HP::Type4',
|
---|
105 | Start => '$valuePtr',
|
---|
106 | ByteOrder => 'LittleEndian',
|
---|
107 | },
|
---|
108 | },
|
---|
109 | {
|
---|
110 | Name => 'MakerNoteHP6', # PhotoSmart M425, M525 and M527
|
---|
111 | Condition => '$$valPt =~ /^IIII\x06\0/',
|
---|
112 | NotIFD => 1,
|
---|
113 | SubDirectory => {
|
---|
114 | TagTable => 'Image::ExifTool::HP::Type6',
|
---|
115 | Start => '$valuePtr',
|
---|
116 | ByteOrder => 'LittleEndian',
|
---|
117 | },
|
---|
118 | },
|
---|
119 | {
|
---|
120 | Name => 'MakerNoteJVC',
|
---|
121 | Condition => '$$valPt=~/^JVC /',
|
---|
122 | SubDirectory => {
|
---|
123 | TagTable => 'Image::ExifTool::JVC::Main',
|
---|
124 | Start => '$valuePtr + 4',
|
---|
125 | ByteOrder => 'Unknown',
|
---|
126 | },
|
---|
127 | },
|
---|
128 | {
|
---|
129 | Name => 'MakerNoteJVCText',
|
---|
130 | Condition => '$self->{CameraMake}=~/^(JVC|Victor)/ and $$valPt=~/^VER:/',
|
---|
131 | NotIFD => 1,
|
---|
132 | SubDirectory => {
|
---|
133 | TagTable => 'Image::ExifTool::JVC::Text',
|
---|
134 | },
|
---|
135 | },
|
---|
136 | {
|
---|
137 | Name => 'MakerNoteKodak1a',
|
---|
138 | Condition => '$self->{CameraMake}=~/^EASTMAN KODAK/ and $$valPt=~/^KDK INFO/',
|
---|
139 | NotIFD => 1,
|
---|
140 | SubDirectory => {
|
---|
141 | TagTable => 'Image::ExifTool::Kodak::Main',
|
---|
142 | Start => '$valuePtr + 8',
|
---|
143 | ByteOrder => 'BigEndian',
|
---|
144 | },
|
---|
145 | },
|
---|
146 | {
|
---|
147 | Name => 'MakerNoteKodak1b',
|
---|
148 | Condition => '$self->{CameraMake}=~/^EASTMAN KODAK/ and $$valPt=~/^KDK/',
|
---|
149 | NotIFD => 1,
|
---|
150 | SubDirectory => {
|
---|
151 | TagTable => 'Image::ExifTool::Kodak::Main',
|
---|
152 | Start => '$valuePtr + 8',
|
---|
153 | ByteOrder => 'LittleEndian',
|
---|
154 | },
|
---|
155 | },
|
---|
156 | {
|
---|
157 | # used by various Kodak, HP, Pentax and Minolta models
|
---|
158 | Name => 'MakerNoteKodak2',
|
---|
159 | Condition => q{
|
---|
160 | $$valPt =~ /^.{8}Eastman Kodak/s or
|
---|
161 | $$valPt =~ /^\x01\0[\0\x01]\0\0\0\x04\0[a-zA-Z]{4}/
|
---|
162 | },
|
---|
163 | NotIFD => 1,
|
---|
164 | SubDirectory => {
|
---|
165 | TagTable => 'Image::ExifTool::Kodak::Type2',
|
---|
166 | ByteOrder => 'BigEndian',
|
---|
167 | },
|
---|
168 | },
|
---|
169 | {
|
---|
170 | # not much to key on here, but we know the
|
---|
171 | # upper byte of the year should be 0x07:
|
---|
172 | Name => 'MakerNoteKodak3',
|
---|
173 | Condition => '$self->{CameraMake}=~/^EASTMAN KODAK/ and $$valPt=~/^.{12}\x07/s',
|
---|
174 | NotIFD => 1,
|
---|
175 | SubDirectory => {
|
---|
176 | TagTable => 'Image::ExifTool::Kodak::Type3',
|
---|
177 | ByteOrder => 'BigEndian',
|
---|
178 | },
|
---|
179 | },
|
---|
180 | {
|
---|
181 | Name => 'MakerNoteKodak4',
|
---|
182 | Condition => '$self->{CameraMake}=~/^Eastman Kodak/ and $$valPt=~/^.{41}JPG/s',
|
---|
183 | NotIFD => 1,
|
---|
184 | SubDirectory => {
|
---|
185 | TagTable => 'Image::ExifTool::Kodak::Type4',
|
---|
186 | ByteOrder => 'BigEndian',
|
---|
187 | },
|
---|
188 | },
|
---|
189 | {
|
---|
190 | Name => 'MakerNoteKodak5',
|
---|
191 | Condition => q{
|
---|
192 | $self->{CameraMake}=~/^EASTMAN KODAK/ and
|
---|
193 | ($self->{CameraModel}=~/CX(4200|4230|4300|4310|6200|6230)/ or
|
---|
194 | # try to pick up similar models we haven't tested yet
|
---|
195 | $$valPt=~/^\0(\x1a\x18|\x3a\x08|\x59\xf8|\x14\x80)\0/)
|
---|
196 | },
|
---|
197 | NotIFD => 1,
|
---|
198 | SubDirectory => {
|
---|
199 | TagTable => 'Image::ExifTool::Kodak::Type5',
|
---|
200 | ByteOrder => 'BigEndian',
|
---|
201 | },
|
---|
202 | },
|
---|
203 | {
|
---|
204 | Name => 'MakerNoteKodak6a',
|
---|
205 | Condition => q{
|
---|
206 | $self->{CameraMake}=~/^EASTMAN KODAK/ and
|
---|
207 | $self->{CameraModel}=~/DX3215/
|
---|
208 | },
|
---|
209 | NotIFD => 1,
|
---|
210 | SubDirectory => {
|
---|
211 | TagTable => 'Image::ExifTool::Kodak::Type6',
|
---|
212 | ByteOrder => 'BigEndian',
|
---|
213 | },
|
---|
214 | },
|
---|
215 | {
|
---|
216 | Name => 'MakerNoteKodak6b',
|
---|
217 | Condition => q{
|
---|
218 | $self->{CameraMake}=~/^EASTMAN KODAK/ and
|
---|
219 | $self->{CameraModel}=~/DX3700/
|
---|
220 | },
|
---|
221 | NotIFD => 1,
|
---|
222 | SubDirectory => {
|
---|
223 | TagTable => 'Image::ExifTool::Kodak::Type6',
|
---|
224 | ByteOrder => 'LittleEndian',
|
---|
225 | },
|
---|
226 | },
|
---|
227 | {
|
---|
228 | Name => 'MakerNoteKodak7',
|
---|
229 | # look for something that looks like a serial number
|
---|
230 | # (confirmed serial numbers have the format KXXXX########, but we also
|
---|
231 | # accept other strings from sample images that may be serial numbers)
|
---|
232 | Condition => q{
|
---|
233 | $self->{CameraMake}=~/Kodak/i and
|
---|
234 | $$valPt =~ /^[CK][A-Z\d]{3} ?[A-Z\d]{1,2}\d{2}[A-Z\d]\d{4}[ \0]/
|
---|
235 | },
|
---|
236 | NotIFD => 1,
|
---|
237 | SubDirectory => {
|
---|
238 | TagTable => 'Image::ExifTool::Kodak::Type7',
|
---|
239 | ByteOrder => 'LittleEndian',
|
---|
240 | },
|
---|
241 | },
|
---|
242 | {
|
---|
243 | Name => 'MakerNoteKodakIFD',
|
---|
244 | # look for reasonable number of entries and check
|
---|
245 | # format and count of first IFD entry
|
---|
246 | Condition => q{
|
---|
247 | $self->{CameraMake}=~/Kodak/i and
|
---|
248 | ($$valPt =~ /^\0[\x02-\x7f]..\0[\x01-\x0c]\0\0/s or
|
---|
249 | $$valPt =~ /^[\x02-\x7f]\0..[\x01-\x0c]\0..\0\0/s)
|
---|
250 | },
|
---|
251 | SubDirectory => {
|
---|
252 | TagTable => 'Image::ExifTool::Kodak::IFD',
|
---|
253 | ProcessProc => \&ProcessUnknown,
|
---|
254 | ByteOrder => 'Unknown',
|
---|
255 | },
|
---|
256 | },
|
---|
257 | {
|
---|
258 | Name => 'MakerNoteKodakUnknown',
|
---|
259 | Condition => '$self->{CameraMake}=~/Kodak/i',
|
---|
260 | NotIFD => 1,
|
---|
261 | SubDirectory => {
|
---|
262 | TagTable => 'Image::ExifTool::Kodak::Unknown',
|
---|
263 | ByteOrder => 'BigEndian',
|
---|
264 | },
|
---|
265 | },
|
---|
266 | {
|
---|
267 | Name => 'MakerNoteKyocera',
|
---|
268 | # (starts with "KYOCERA")
|
---|
269 | Condition => '$self->{CameraMake}=~/^KYOCERA/',
|
---|
270 | SubDirectory => {
|
---|
271 | TagTable => 'Image::ExifTool::Unknown::Main',
|
---|
272 | Start => '$valuePtr + 22',
|
---|
273 | Base => '$start + 2',
|
---|
274 | EntryBased => 1,
|
---|
275 | ByteOrder => 'Unknown',
|
---|
276 | },
|
---|
277 | },
|
---|
278 | {
|
---|
279 | Name => 'MakerNoteMinolta',
|
---|
280 | Condition => q{
|
---|
281 | $self->{CameraMake}=~/^(Konica Minolta|Minolta)/i and
|
---|
282 | $$valPt !~ /^(MINOL|CAMER|MLY0|KC|\+M\+M|\xd7)/
|
---|
283 | },
|
---|
284 | SubDirectory => {
|
---|
285 | TagTable => 'Image::ExifTool::Minolta::Main',
|
---|
286 | ByteOrder => 'Unknown',
|
---|
287 | },
|
---|
288 | },
|
---|
289 | {
|
---|
290 | # the DiMAGE E323 (MINOL) and E500 (CAMER), and some models
|
---|
291 | # of Mustek, Pentax, Ricoh and Vivitar (CAMER).
|
---|
292 | Name => 'MakerNoteMinolta2',
|
---|
293 | Condition => '$$valPt =~ /^(MINOL|CAMER)\0/ and $$self{OlympusCAMER} = 1',
|
---|
294 | SubDirectory => {
|
---|
295 | # these models use Olympus tags in the range 0x200-0x221 plus 0xf00
|
---|
296 | TagTable => 'Image::ExifTool::Olympus::Main',
|
---|
297 | Start => '$valuePtr + 8',
|
---|
298 | ByteOrder => 'Unknown',
|
---|
299 | },
|
---|
300 | },
|
---|
301 | {
|
---|
302 | # /^MLY0/ - DiMAGE G400, G500, G530, G600
|
---|
303 | # /^KC/ - Revio KD-420Z, DiMAGE E203
|
---|
304 | # /^+M+M/ - DiMAGE E201
|
---|
305 | # /^\xd7/ - DiMAGE RD3000
|
---|
306 | Name => 'MakerNoteMinolta3',
|
---|
307 | Condition => '$self->{CameraMake} =~ /^(Konica Minolta|Minolta)/i',
|
---|
308 | Notes => 'not EXIF-based',
|
---|
309 | Binary => 1,
|
---|
310 | NotIFD => 1,
|
---|
311 | },
|
---|
312 | {
|
---|
313 | # this maker notes starts with a standard TIFF header at offset 0x0a
|
---|
314 | Name => 'MakerNoteNikon',
|
---|
315 | Condition => '$self->{CameraMake}=~/^NIKON/i and $$valPt=~/^Nikon\x00\x02/',
|
---|
316 | SubDirectory => {
|
---|
317 | TagTable => 'Image::ExifTool::Nikon::Main',
|
---|
318 | Start => '$valuePtr + 18',
|
---|
319 | Base => '$start - 8',
|
---|
320 | ByteOrder => 'Unknown',
|
---|
321 | },
|
---|
322 | },
|
---|
323 | {
|
---|
324 | # older Nikon maker notes
|
---|
325 | Name => 'MakerNoteNikon2',
|
---|
326 | Condition => '$self->{CameraMake}=~/^NIKON/ and $$valPt=~/^Nikon\x00\x01/',
|
---|
327 | SubDirectory => {
|
---|
328 | TagTable => 'Image::ExifTool::Nikon::Type2',
|
---|
329 | Start => '$valuePtr + 8',
|
---|
330 | ByteOrder => 'LittleEndian',
|
---|
331 | },
|
---|
332 | },
|
---|
333 | {
|
---|
334 | # headerless Nikon maker notes
|
---|
335 | Name => 'MakerNoteNikon3',
|
---|
336 | Condition => '$self->{CameraMake}=~/^NIKON/i',
|
---|
337 | SubDirectory => {
|
---|
338 | TagTable => 'Image::ExifTool::Nikon::Main',
|
---|
339 | ByteOrder => 'Unknown', # most are little-endian, but D1 is big
|
---|
340 | },
|
---|
341 | },
|
---|
342 | {
|
---|
343 | Name => 'MakerNoteOlympus',
|
---|
344 | # (if Make is 'SEIKO EPSON CORP.', starts with "EPSON\0")
|
---|
345 | # (if Make is 'OLYMPUS OPTICAL CO.,LTD' or 'OLYMPUS CORPORATION',
|
---|
346 | # starts with "OLYMP\0")
|
---|
347 | Condition => '$$valPt =~ /^(OLYMP|EPSON)\0/',
|
---|
348 | SubDirectory => {
|
---|
349 | TagTable => 'Image::ExifTool::Olympus::Main',
|
---|
350 | Start => '$valuePtr + 8',
|
---|
351 | ByteOrder => 'Unknown',
|
---|
352 | },
|
---|
353 | },
|
---|
354 | {
|
---|
355 | Name => 'MakerNoteOlympus2',
|
---|
356 | # new Olympus maker notes start with "OLYMPUS\0"
|
---|
357 | Condition => '$$valPt =~ /^OLYMPUS\0/ and $$self{OlympusType2} = 1',
|
---|
358 | SubDirectory => {
|
---|
359 | TagTable => 'Image::ExifTool::Olympus::Main',
|
---|
360 | Start => '$valuePtr + 12',
|
---|
361 | Base => '$start - 12',
|
---|
362 | ByteOrder => 'Unknown',
|
---|
363 | },
|
---|
364 | },
|
---|
365 | {
|
---|
366 | Name => 'MakerNoteLeica',
|
---|
367 | # (starts with "LEICA\0")
|
---|
368 | Condition => '$self->{CameraMake} =~ /^LEICA/',
|
---|
369 | SubDirectory => {
|
---|
370 | # Leica uses the same format as Panasonic
|
---|
371 | TagTable => 'Image::ExifTool::Panasonic::Main',
|
---|
372 | Start => '$valuePtr + 8',
|
---|
373 | ByteOrder => 'Unknown',
|
---|
374 | },
|
---|
375 | },
|
---|
376 | {
|
---|
377 | Name => 'MakerNotePanasonic',
|
---|
378 | # (starts with "Panasonic\0")
|
---|
379 | Condition => '$self->{CameraMake} =~ /^Panasonic/ and $$valPt!~/^MKE/',
|
---|
380 | SubDirectory => {
|
---|
381 | TagTable => 'Image::ExifTool::Panasonic::Main',
|
---|
382 | Start => '$valuePtr + 12',
|
---|
383 | ByteOrder => 'Unknown',
|
---|
384 | },
|
---|
385 | },
|
---|
386 | {
|
---|
387 | Name => 'MakerNotePanasonic2',
|
---|
388 | # (starts with "Panasonic\0")
|
---|
389 | Condition => '$self->{CameraMake} =~ /^Panasonic/',
|
---|
390 | SubDirectory => {
|
---|
391 | TagTable => 'Image::ExifTool::Panasonic::Type2',
|
---|
392 | ByteOrder => 'LittleEndian',
|
---|
393 | },
|
---|
394 | },
|
---|
395 | {
|
---|
396 | Name => 'MakerNotePentax',
|
---|
397 | # (starts with "AOC\0", but so does MakerNotePentax3)
|
---|
398 | # (also used by some Samsung models)
|
---|
399 | Condition => q{
|
---|
400 | $$valPt=~/^AOC\0/ and
|
---|
401 | $self->{CameraModel} !~ /^PENTAX Optio ?[34]30RS\s*$/
|
---|
402 | },
|
---|
403 | SubDirectory => {
|
---|
404 | TagTable => 'Image::ExifTool::Pentax::Main',
|
---|
405 | # process as Unknown maker notes because the start offset and
|
---|
406 | # byte ordering are so variable
|
---|
407 | ProcessProc => \&ProcessUnknown,
|
---|
408 | # offsets can be totally whacky for Pentax maker notes,
|
---|
409 | # so attempt to fix the offset base if possible
|
---|
410 | FixBase => 1,
|
---|
411 | ByteOrder => 'Unknown',
|
---|
412 | },
|
---|
413 | },
|
---|
414 | {
|
---|
415 | Name => 'MakerNotePentax2',
|
---|
416 | # (starts with an IFD)
|
---|
417 | # Casio-like maker notes used only by the Optio 330 and 430
|
---|
418 | Condition => '$self->{CameraMake}=~/^Asahi/ and $$valPt!~/^AOC\0/',
|
---|
419 | SubDirectory => {
|
---|
420 | TagTable => 'Image::ExifTool::Pentax::Type2',
|
---|
421 | ProcessProc => \&ProcessUnknown,
|
---|
422 | FixBase => 1,
|
---|
423 | ByteOrder => 'Unknown',
|
---|
424 | },
|
---|
425 | },
|
---|
426 | {
|
---|
427 | Name => 'MakerNotePentax3',
|
---|
428 | # (starts with "AOC\0", like the more common Pentax maker notes)
|
---|
429 | # Casio maker notes used only by the Optio 330RS and 430RS
|
---|
430 | Condition => '$self->{CameraMake}=~/^Asahi/',
|
---|
431 | SubDirectory => {
|
---|
432 | TagTable => 'Image::ExifTool::Casio::Type2',
|
---|
433 | ProcessProc => \&ProcessUnknown,
|
---|
434 | FixBase => 1,
|
---|
435 | ByteOrder => 'Unknown',
|
---|
436 | },
|
---|
437 | },
|
---|
438 | {
|
---|
439 | Name => 'MakerNotePentax4',
|
---|
440 | # (starts with 3 or 4 digits)
|
---|
441 | # HP2-like text-based maker notes used by Optio E20
|
---|
442 | Condition => '$self->{CameraMake}=~/^PENTAX/ and $$valPt=~/^\d{3}/',
|
---|
443 | NotIFD => 1,
|
---|
444 | SubDirectory => {
|
---|
445 | TagTable => 'Image::ExifTool::Pentax::Type4',
|
---|
446 | Start => '$valuePtr',
|
---|
447 | ByteOrder => 'LittleEndian',
|
---|
448 | },
|
---|
449 | },
|
---|
450 | {
|
---|
451 | Name => 'MakerNoteRicoh',
|
---|
452 | Condition => '$self->{CameraMake}=~/^RICOH/ and $$valPt=~/^Ricoh/i',
|
---|
453 | SubDirectory => {
|
---|
454 | TagTable => 'Image::ExifTool::Ricoh::Main',
|
---|
455 | Start => '$valuePtr + 8',
|
---|
456 | ByteOrder => 'Unknown',
|
---|
457 | },
|
---|
458 | },
|
---|
459 | {
|
---|
460 | Name => 'MakerNoteRicohText',
|
---|
461 | Condition => '$self->{CameraMake}=~/^RICOH/',
|
---|
462 | NotIFD => 1,
|
---|
463 | SubDirectory => {
|
---|
464 | TagTable => 'Image::ExifTool::Ricoh::Text',
|
---|
465 | ByteOrder => 'Unknown',
|
---|
466 | },
|
---|
467 | },
|
---|
468 | {
|
---|
469 | # PreviewImage (Samsung Digimax plus some other types of cameras)
|
---|
470 | %Image::ExifTool::previewImageTagInfo,
|
---|
471 | Condition => '$$valPt =~ /^\xff\xd8\xff\xdb/',
|
---|
472 | Notes => 'Samsung preview image',
|
---|
473 | },
|
---|
474 | {
|
---|
475 | Name => 'MakerNoteSanyo',
|
---|
476 | # (starts with "SANYO\0")
|
---|
477 | Condition => '$self->{CameraMake}=~/^SANYO/ and $self->{CameraModel} !~ /^(C4|J\d|S\d)\b/',
|
---|
478 | SubDirectory => {
|
---|
479 | TagTable => 'Image::ExifTool::Sanyo::Main',
|
---|
480 | Validate => '$val =~ /^SANYO/',
|
---|
481 | Start => '$valuePtr + 8',
|
---|
482 | ByteOrder => 'Unknown',
|
---|
483 | },
|
---|
484 | },
|
---|
485 | {
|
---|
486 | Name => 'MakerNoteSanyoC4',
|
---|
487 | # The C4 offsets are wrong by 12, so they must be fixed
|
---|
488 | Condition => '$self->{CameraMake}=~/^SANYO/ and $self->{CameraModel} =~ /^C4\b/',
|
---|
489 | SubDirectory => {
|
---|
490 | TagTable => 'Image::ExifTool::Sanyo::Main',
|
---|
491 | Validate => '$val =~ /^SANYO/',
|
---|
492 | Start => '$valuePtr + 8',
|
---|
493 | FixBase => 1,
|
---|
494 | ByteOrder => 'Unknown',
|
---|
495 | },
|
---|
496 | },
|
---|
497 | {
|
---|
498 | Name => 'MakerNoteSanyoPatch',
|
---|
499 | # The J1, J2, J4, S1, S3 and S4 offsets are completely screwy
|
---|
500 | Condition => '$self->{CameraMake}=~/^SANYO/',
|
---|
501 | SubDirectory => {
|
---|
502 | TagTable => 'Image::ExifTool::Sanyo::Main',
|
---|
503 | Validate => '$val =~ /^SANYO/',
|
---|
504 | Start => '$valuePtr + 8',
|
---|
505 | ByteOrder => 'Unknown',
|
---|
506 | FixOffsets => 'Image::ExifTool::Sanyo::FixOffsets($valuePtr, $valEnd, $size, $tagID, $wFlag)',
|
---|
507 | },
|
---|
508 | },
|
---|
509 | {
|
---|
510 | Name => 'MakerNoteSigma',
|
---|
511 | # (starts with "SIGMA\0")
|
---|
512 | Condition => '$self->{CameraMake}=~/^(SIGMA|FOVEON)/',
|
---|
513 | SubDirectory => {
|
---|
514 | TagTable => 'Image::ExifTool::Sigma::Main',
|
---|
515 | Validate => '$val =~ /^(SIGMA|FOVEON)/',
|
---|
516 | Start => '$valuePtr + 10',
|
---|
517 | ByteOrder => 'Unknown',
|
---|
518 | },
|
---|
519 | },
|
---|
520 | {
|
---|
521 | Name => 'MakerNoteSony',
|
---|
522 | # (starts with "SONY DSC \0" or "SONY CAM \0")
|
---|
523 | Condition => '$self->{CameraMake}=~/^SONY/ and $self->{TIFF_TYPE}!~/^(SRF|SR2|DNG)$/',
|
---|
524 | SubDirectory => {
|
---|
525 | TagTable => 'Image::ExifTool::Sony::Main',
|
---|
526 | # validate the maker note because this is sometimes garbage
|
---|
527 | Validate => 'defined($val) and $val =~ /^SONY (DSC|CAM)/',
|
---|
528 | Start => '$valuePtr + 12',
|
---|
529 | ByteOrder => 'Unknown',
|
---|
530 | },
|
---|
531 | },
|
---|
532 | {
|
---|
533 | Name => 'MakerNoteSonySRF',
|
---|
534 | Condition => '$self->{CameraMake}=~/^SONY/ and $$valPt =~ /^\x01\x00/',
|
---|
535 | SubDirectory => {
|
---|
536 | TagTable => 'Image::ExifTool::Sony::SRF',
|
---|
537 | Start => '$valuePtr',
|
---|
538 | ByteOrder => 'Unknown',
|
---|
539 | },
|
---|
540 | },
|
---|
541 | {
|
---|
542 | Name => 'MakerNoteSonySR2',
|
---|
543 | Condition => '$self->{CameraMake}=~/^SONY/',
|
---|
544 | SubDirectory => {
|
---|
545 | TagTable => 'Image::ExifTool::Sony::Main',
|
---|
546 | Start => '$valuePtr',
|
---|
547 | ByteOrder => 'Unknown',
|
---|
548 | },
|
---|
549 | },
|
---|
550 | {
|
---|
551 | Name => 'MakerNoteUnknown',
|
---|
552 | SubDirectory => {
|
---|
553 | TagTable => 'Image::ExifTool::Unknown::Main',
|
---|
554 | ProcessProc => \&ProcessUnknown,
|
---|
555 | ByteOrder => 'Unknown',
|
---|
556 | },
|
---|
557 | },
|
---|
558 | );
|
---|
559 |
|
---|
560 | # insert writable properties so we can write our maker notes
|
---|
561 | my $tagInfo;
|
---|
562 | foreach $tagInfo (@Image::ExifTool::MakerNotes::Main) {
|
---|
563 | $$tagInfo{Writable} = 'undef';
|
---|
564 | $$tagInfo{WriteGroup} = 'ExifIFD';
|
---|
565 | $$tagInfo{Groups} = { 1 => 'MakerNotes' };
|
---|
566 | next unless $$tagInfo{SubDirectory};
|
---|
567 | # set up this tag so we can write it
|
---|
568 | $$tagInfo{ValueConv} = '\$val';
|
---|
569 | $$tagInfo{ValueConvInv} = '$val';
|
---|
570 | $$tagInfo{MakerNotes} = 1;
|
---|
571 | }
|
---|
572 |
|
---|
573 | #------------------------------------------------------------------------------
|
---|
574 | # Get normal offset of value data from end of maker note IFD
|
---|
575 | # Inputs: 0) ExifTool object reference
|
---|
576 | # Returns: Array: 0) relative flag (undef for no change)
|
---|
577 | # 1) normal offset from end of IFD to first value (empty if unknown)
|
---|
578 | # 2-N) other possible offsets used by some models
|
---|
579 | # Notes: Directory size should be validated before calling this routine
|
---|
580 | sub GetMakerNoteOffset($)
|
---|
581 | {
|
---|
582 | my $exifTool = shift;
|
---|
583 | # figure out where we expect the value data based on camera type
|
---|
584 | my $make = $exifTool->{CameraMake};
|
---|
585 | my $model = $exifTool->{CameraModel};
|
---|
586 | my ($relative, @offsets);
|
---|
587 |
|
---|
588 | # normally value data starts 4 bytes after end of directory, so this is the default
|
---|
589 | if ($make =~ /^Canon/) {
|
---|
590 | push @offsets, ($model =~ /\b(20D|350D|REBEL XT|Kiss Digital N)\b/) ? 6 : 4;
|
---|
591 | # some Canon models (FV-M30, Optura50, Optura60) leave 24 unused bytes
|
---|
592 | # at the end of the IFD (2 spare IFD entries?)
|
---|
593 | push @offsets, 28 if $model =~ /\b(FV\b|OPTURA)/;
|
---|
594 | } elsif ($make =~ /^KYOCERA/) {
|
---|
595 | push @offsets, 12;
|
---|
596 | } elsif ($make =~ /^OLYMPUS/ and $model =~ /^E-(1|300|330)\b/) {
|
---|
597 | push @offsets, 16;
|
---|
598 | } elsif ($make =~ /^OLYMPUS/ and
|
---|
599 | # these Olympus models are just weird
|
---|
600 | $model =~ /^(C2500L|C-1Z?|C-5000Z|X-2|C720UZ|C725UZ|C150|C2Z|E-10|E-20|FerrariMODEL2003|u20D|u10D)\b/)
|
---|
601 | {
|
---|
602 | # no expected offset --> determine offset empirically via FixBase()
|
---|
603 | } elsif ($make =~ /^(Panasonic|SONY|JVC)\b/) {
|
---|
604 | push @offsets, 0;
|
---|
605 | } elsif ($make eq 'FUJIFILM') {
|
---|
606 | # some models have offset of 6, so allow that too (A345,A350,A360,A370)
|
---|
607 | push @offsets, 4, 6;
|
---|
608 | } elsif ($make =~ /^TOSHIBA/) {
|
---|
609 | # similar to Canon, can also have 24 bytes of padding
|
---|
610 | push @offsets, 0, 24;
|
---|
611 | } elsif ($make =~ /^PENTAX/) {
|
---|
612 | push @offsets, 4;
|
---|
613 | # the Pentax addressing mode is determined automatically, but
|
---|
614 | # sometimes the algorithm gets it wrong, but Pentax always uses
|
---|
615 | # absolute addressing, so force it to be absolute
|
---|
616 | $relative = 0;
|
---|
617 | } elsif ($make =~ /^Konica Minolta/i) {
|
---|
618 | # patch for DiMAGE X50, Xg, Z2 and Z10
|
---|
619 | push @offsets, 4, -16;
|
---|
620 | } elsif ($make =~ /^Minolta/) {
|
---|
621 | # patch for DiMAGE 7, X20 and Z1
|
---|
622 | push @offsets, 4, -8, -12;
|
---|
623 | } else {
|
---|
624 | push @offsets, 4; # the normal offset
|
---|
625 | }
|
---|
626 | return ($relative, @offsets);
|
---|
627 | }
|
---|
628 |
|
---|
629 | #------------------------------------------------------------------------------
|
---|
630 | # Get hash of value offsets / block sizes
|
---|
631 | # Inputs: 0) Data pointer, 1) offset to start of directory
|
---|
632 | # Returns: 0) hash reference: keys are offsets, values are block sizes
|
---|
633 | # 1) same thing, but with keys adjusted for value-based offsets
|
---|
634 | # Notes: Directory size should be validated before calling this routine
|
---|
635 | # - calculates MIN and MAX offsets in entry-based hash
|
---|
636 | sub GetValueBlocks($$)
|
---|
637 | {
|
---|
638 | my ($dataPt, $dirStart) = @_;
|
---|
639 | my $numEntries = Get16u($dataPt, $dirStart);
|
---|
640 | my ($index, $valPtr, %valBlock, %valBlkAdj, $end);
|
---|
641 | for ($index=0; $index<$numEntries; ++$index) {
|
---|
642 | my $entry = $dirStart + 2 + 12 * $index;
|
---|
643 | my $format = Get16u($dataPt, $entry+2);
|
---|
644 | last if $format < 1 or $format > 13;
|
---|
645 | my $count = Get32u($dataPt, $entry+4);
|
---|
646 | my $size = $count * $Image::ExifTool::Exif::formatSize[$format];
|
---|
647 | next if $size <= 4;
|
---|
648 | $valPtr = Get32u($dataPt, $entry+8);
|
---|
649 | # save location and size of longest block at this offset
|
---|
650 | unless (defined $valBlock{$valPtr} and $valBlock{$valPtr} > $size) {
|
---|
651 | $valBlock{$valPtr} = $size;
|
---|
652 | }
|
---|
653 | # adjust for case of value-based offsets
|
---|
654 | $valPtr += 12 * $index;
|
---|
655 | unless (defined $valBlkAdj{$valPtr} and $valBlkAdj{$valPtr} > $size) {
|
---|
656 | $valBlkAdj{$valPtr} = $size;
|
---|
657 | my $end = $valPtr + $size;
|
---|
658 | if (defined $valBlkAdj{MIN}) {
|
---|
659 | # save minimum only if it has a value of 12 or greater
|
---|
660 | $valBlkAdj{MIN} = $valPtr if $valBlkAdj{MIN} < 12 or $valBlkAdj{MIN} > $valPtr;
|
---|
661 | $valBlkAdj{MAX} = $end if $valBlkAdj{MAX} > $end;
|
---|
662 | } else {
|
---|
663 | $valBlkAdj{MIN} = $valPtr;
|
---|
664 | $valBlkAdj{MAX} = $end;
|
---|
665 | }
|
---|
666 | }
|
---|
667 | }
|
---|
668 | return(\%valBlock, \%valBlkAdj);
|
---|
669 | }
|
---|
670 |
|
---|
671 | #------------------------------------------------------------------------------
|
---|
672 | # Fix base for value offsets in maker notes IFD (if necessary)
|
---|
673 | # Inputs: 0) ExifTool object ref, 1) DirInfo hash ref
|
---|
674 | # Return: amount of base shift (and $dirInfo Base and DataPos are updated,
|
---|
675 | # FixedBy is set if offsets fixed, and Relative or EntryBased may be set)
|
---|
676 | sub FixBase($$)
|
---|
677 | {
|
---|
678 | local $_;
|
---|
679 | my ($exifTool, $dirInfo) = @_;
|
---|
680 | # don't fix base if fixing offsets individually or if we don't want to fix them
|
---|
681 | return 0 if $$dirInfo{FixOffsets} or $$dirInfo{NoFixBase};
|
---|
682 |
|
---|
683 | my $dataPt = $$dirInfo{DataPt};
|
---|
684 | my $dataPos = $$dirInfo{DataPos};
|
---|
685 | my $dirStart = $$dirInfo{DirStart} || 0;
|
---|
686 | my $entryBased = $$dirInfo{EntryBased};
|
---|
687 | my $dirName = $$dirInfo{DirName};
|
---|
688 | my $fixBase = $exifTool->Options('FixBase');
|
---|
689 | my $setBase = (defined $fixBase and $fixBase ne '') ? 1 : 0;
|
---|
690 | my ($fix, $fixedBy);
|
---|
691 | #
|
---|
692 | # handle special case of Canon maker notes with TIFF trailer containing original offset
|
---|
693 | #
|
---|
694 | if ($$exifTool{CameraMake} =~ /^Canon/ and $$dirInfo{DirLen} > 8) {
|
---|
695 | my $trailerPos = $dirStart + $$dirInfo{DirLen} - 8;
|
---|
696 | my $trailer = substr($$dataPt, $trailerPos, 8);
|
---|
697 | if ($trailer =~ /^(II\x2a\0|MM\0\x2a)/ and # check for TIFF trailer
|
---|
698 | substr($trailer,0,2) eq GetByteOrder()) # validate byte ordering
|
---|
699 | {
|
---|
700 | if ($$exifTool{HTML_DUMP}) {
|
---|
701 | my $filePos = ($$dirInfo{Base} || 0) + $dataPos + $trailerPos;
|
---|
702 | $exifTool->HtmlDump($filePos, 8, '[Canon MakerNote trailer]')
|
---|
703 | }
|
---|
704 | if ($setBase) {
|
---|
705 | $fix = $fixBase;
|
---|
706 | } else {
|
---|
707 | my $oldOffset = Get32u(\$trailer, 4);
|
---|
708 | my $newOffset = $dirStart + $dataPos;
|
---|
709 | $fix = $newOffset - $oldOffset;
|
---|
710 | return 0 unless $fix;
|
---|
711 | }
|
---|
712 | $exifTool->Warn("Adjusted $dirName base by $fix", 1);
|
---|
713 | $$dirInfo{FixedBy} = $fix;
|
---|
714 | $$dirInfo{Base} += $fix;
|
---|
715 | $$dirInfo{DataPos} -= $fix;
|
---|
716 | return $fix;
|
---|
717 | }
|
---|
718 | }
|
---|
719 | #
|
---|
720 | # analyze value offsets to see if they need fixing. The first task is to
|
---|
721 | # determine the minimum valid offset used (this is tricky, because we have
|
---|
722 | # to weed out bad offsets written by some cameras)
|
---|
723 | #
|
---|
724 | # get hash of value block positions
|
---|
725 | my ($valBlock, $valBlkAdj) = GetValueBlocks($dataPt, $dirStart);
|
---|
726 | return 0 unless %$valBlock;
|
---|
727 |
|
---|
728 | my $ifdLen = 2 + 12 * Get16u($$dirInfo{DataPt}, $dirStart);
|
---|
729 | my $ifdEnd = $dirStart + $ifdLen;
|
---|
730 | my ($relative, @offsets) = GetMakerNoteOffset($exifTool);
|
---|
731 | my $makeDiff = $offsets[0];
|
---|
732 | my $verbose = $exifTool->Options('Verbose');
|
---|
733 | my ($diff, $shift);
|
---|
734 |
|
---|
735 | # calculate expected minimum value offset
|
---|
736 | my $expected = $dataPos + $ifdEnd + (defined $makeDiff ? $makeDiff : 4);
|
---|
737 | $debug and print "$expected expected\n";
|
---|
738 |
|
---|
739 | # get sorted list of value offsets
|
---|
740 | my @valPtrs = sort { $a <=> $b } keys %$valBlock;
|
---|
741 | my $minPt = $valPtrs[0]; # if life were simple, this would be it
|
---|
742 |
|
---|
743 | # zero our counters
|
---|
744 | my ($countNeg12, $countZero, $countOverlap) = (0, 0, 0);
|
---|
745 | my ($valPtr, $last);
|
---|
746 | foreach $valPtr (@valPtrs) {
|
---|
747 | printf("%d - %d (%d)\n", $valPtr, $valPtr + $$valBlock{$valPtr},
|
---|
748 | $valPtr - ($last || 0)) if $debug;
|
---|
749 | if (defined $last) {
|
---|
750 | my $diff = $valPtr - $last;
|
---|
751 | if ($diff == 0 or $diff == 1) {
|
---|
752 | ++$countZero;
|
---|
753 | } elsif ($diff == -12 and not $entryBased) {
|
---|
754 | # you get this when value offsets are relative to the IFD entry
|
---|
755 | ++$countNeg12;
|
---|
756 | } elsif ($diff < 0) {
|
---|
757 | # any other negative difference indicates overlapping values
|
---|
758 | ++$countOverlap if $valPtr; # (but ignore zero value pointers)
|
---|
759 | } elsif ($diff >= $ifdLen) {
|
---|
760 | # ignore previous minimum if we took a jump to near the expected value
|
---|
761 | # (some values can be stored before the IFD)
|
---|
762 | $minPt = $valPtr if abs($valPtr - $expected) <= 4;
|
---|
763 | }
|
---|
764 | # an offset less than 12 is surely garbage, so ignore it
|
---|
765 | $minPt = $valPtr if $minPt < 12;
|
---|
766 | }
|
---|
767 | $last = $valPtr + $$valBlock{$valPtr};
|
---|
768 | }
|
---|
769 | # could this IFD be using entry-based offsets?
|
---|
770 | if ((($countNeg12 > $countZero and $$valBlkAdj{MIN} >= $ifdLen - 2) or
|
---|
771 | ($$valBlkAdj{MIN} == $ifdLen - 2 or $$valBlkAdj{MIN} == $ifdLen + 2)
|
---|
772 | ) and $$valBlkAdj{MAX} <= $$dirInfo{DirLen}-2)
|
---|
773 | {
|
---|
774 | # looks like these offsets are entry-based, so use the offsets
|
---|
775 | # which have been correcting for individual entry position
|
---|
776 | $entryBased = 1;
|
---|
777 | $verbose and $exifTool->Warn("$dirName offsets are entry-based");
|
---|
778 | } else {
|
---|
779 | # calculate difference from normal
|
---|
780 | $diff = ($minPt - $dataPos) - $ifdEnd;
|
---|
781 | $shift = 0;
|
---|
782 | $countOverlap and $exifTool->Warn("Overlapping $dirName values",1);
|
---|
783 | if ($entryBased) {
|
---|
784 | $exifTool->Warn("$dirName offsets do NOT look entry-based");
|
---|
785 | undef $entryBased;
|
---|
786 | undef $relative;
|
---|
787 | }
|
---|
788 | }
|
---|
789 | #
|
---|
790 | # handle entry-based offsets
|
---|
791 | #
|
---|
792 | if ($entryBased) {
|
---|
793 | $debug and print "--> entry-based!\n";
|
---|
794 | # most of my entry-based samples have first value immediately
|
---|
795 | # after last IFD entry (ie. no padding or next IFD pointer)
|
---|
796 | $makeDiff = 0;
|
---|
797 | push @offsets, 4; # but some do have a next IFD pointer
|
---|
798 | # corrected entry-based offsets are relative to start of first entry
|
---|
799 | my $expected = 12 * Get16u($$dirInfo{DataPt}, $dirStart);
|
---|
800 | $diff = $$valBlkAdj{MIN} - $expected;
|
---|
801 | # set up directory to read values with entry-based offsets
|
---|
802 | # (ignore everything and set base to start of first entry)
|
---|
803 | $shift = $dataPos + $dirStart + 2;
|
---|
804 | $$dirInfo{Base} += $shift;
|
---|
805 | $$dirInfo{DataPos} -= $shift;
|
---|
806 | $$dirInfo{EntryBased} = 1;
|
---|
807 | $$dirInfo{Relative} = 1; # entry-based offsets are relative
|
---|
808 | delete $$dirInfo{FixBase}; # no automatic base fix
|
---|
809 | undef $fixBase unless $setBase;
|
---|
810 | }
|
---|
811 | #
|
---|
812 | # return without doing shift if offsets look OK
|
---|
813 | #
|
---|
814 | unless ($setBase) {
|
---|
815 | # don't try to fix offsets for whacky cameras
|
---|
816 | return $shift unless defined $makeDiff;
|
---|
817 | # normal value data starts 4 bytes after IFD, but allow 0 or 4...
|
---|
818 | return $shift if $diff == 0 or $diff == 4;
|
---|
819 | # also check for allowed make-specific differences
|
---|
820 | foreach (@offsets) {
|
---|
821 | return $shift if $diff == $_;
|
---|
822 | }
|
---|
823 | }
|
---|
824 | #
|
---|
825 | # apply the fix, or issue a warning
|
---|
826 | #
|
---|
827 | # use default padding of 4 bytes unless already specified
|
---|
828 | $makeDiff = 4 unless defined $makeDiff;
|
---|
829 | $fix = $makeDiff - $diff; # assume standard diff for this make
|
---|
830 |
|
---|
831 | if ($$dirInfo{FixBase}) {
|
---|
832 | # set flag if offsets are relative (base is at or above directory start)
|
---|
833 | if ($dataPos - $fix + $dirStart <= 0) {
|
---|
834 | $$dirInfo{Relative} = (defined $relative) ? $relative : 1;
|
---|
835 | }
|
---|
836 | if ($setBase) {
|
---|
837 | $fixedBy = $fixBase;
|
---|
838 | $fix += $fixBase;
|
---|
839 | }
|
---|
840 | } elsif (defined $fixBase) {
|
---|
841 | $fix = $fixBase if $fixBase ne '';
|
---|
842 | $fixedBy = $fix;
|
---|
843 | } else {
|
---|
844 | # print warning unless difference looks reasonable
|
---|
845 | if ($diff < 0 or $diff > 16 or ($diff & 0x01)) {
|
---|
846 | $exifTool->Warn("Possibly incorrect maker notes offsets (fix by $fix?)",1);
|
---|
847 | }
|
---|
848 | # don't do the fix (but we already adjusted base if entry-based)
|
---|
849 | return $shift;
|
---|
850 | }
|
---|
851 | if (defined $fixedBy) {
|
---|
852 | $exifTool->Warn("Adjusted $dirName base by $fixedBy",1);
|
---|
853 | $$dirInfo{FixedBy} = $fixedBy;
|
---|
854 | }
|
---|
855 | $$dirInfo{Base} += $fix;
|
---|
856 | $$dirInfo{DataPos} -= $fix;
|
---|
857 | return $fix + $shift;
|
---|
858 | }
|
---|
859 |
|
---|
860 | #------------------------------------------------------------------------------
|
---|
861 | # Find start of IFD in unknown maker notes
|
---|
862 | # Inputs: 0) reference to directory information
|
---|
863 | # Returns: offset to IFD on success, undefined otherwise
|
---|
864 | # - dirInfo may contain TagInfo reference for tag associated with directory
|
---|
865 | # - on success, updates DirStart, DirLen, Base and DataPos in dirInfo
|
---|
866 | # - also sets Relative flag in dirInfo if offsets are relative to IFD
|
---|
867 | # Note: Changes byte ordering!
|
---|
868 | sub LocateIFD($$)
|
---|
869 | {
|
---|
870 | my ($exifTool, $dirInfo) = @_;
|
---|
871 | my $dataPt = $$dirInfo{DataPt};
|
---|
872 | my $dirStart = $$dirInfo{DirStart} || 0;
|
---|
873 | my $size = $$dirInfo{DirLen} || ($$dirInfo{DataLen} - $dirStart);
|
---|
874 | my $tagInfo = $$dirInfo{TagInfo};
|
---|
875 | my $ifdOffsetPos;
|
---|
876 | # the IFD should be within the first 32 bytes
|
---|
877 | # (Kyocera sets the current record at 22 bytes)
|
---|
878 | my ($firstTry, $lastTry) = (0, 32);
|
---|
879 |
|
---|
880 | # make sure Base and DataPos are defined
|
---|
881 | $$dirInfo{Base} or $$dirInfo{Base} = 0;
|
---|
882 | $$dirInfo{DataPos} or $$dirInfo{DataPos} = 0;
|
---|
883 | #
|
---|
884 | # use tag information (if provided) to determine directory location
|
---|
885 | #
|
---|
886 | if ($tagInfo and $$tagInfo{SubDirectory}) {
|
---|
887 | my $subdir = $$tagInfo{SubDirectory};
|
---|
888 | unless ($$subdir{ProcessProc} and $$subdir{ProcessProc} eq \&ProcessUnknown) {
|
---|
889 | # look for the IFD at the "Start" specified in our SubDirectory information
|
---|
890 | my $valuePtr = $dirStart;
|
---|
891 | my $newStart = $dirStart;
|
---|
892 | if (defined $$subdir{Start}) {
|
---|
893 | #### eval Start ($valuePtr)
|
---|
894 | $newStart = eval($$subdir{Start});
|
---|
895 | }
|
---|
896 | if ($$subdir{Base}) {
|
---|
897 | # calculate subdirectory start relative to $base for eval
|
---|
898 | my $start = $newStart + $$dirInfo{DataPos};
|
---|
899 | #### eval Base ($start)
|
---|
900 | my $baseShift = eval($$subdir{Base});
|
---|
901 | # shift directory base (note: we may do this again below
|
---|
902 | # if an OffsetPt is defined, but that doesn't matter since
|
---|
903 | # the base shift is relative to DataPos, which we set too)
|
---|
904 | $$dirInfo{Base} += $baseShift;
|
---|
905 | $$dirInfo{DataPos} -= $baseShift;
|
---|
906 | # this is a relative directory if Base depends on $start
|
---|
907 | $$dirInfo{Relative} = 1 if $$subdir{Base} =~ /\$start\b/;
|
---|
908 | }
|
---|
909 | # add offset to the start of the directory if necessary
|
---|
910 | if ($$subdir{OffsetPt}) {
|
---|
911 | if ($$subdir{ByteOrder} =~ /^Little/i) {
|
---|
912 | SetByteOrder('II');
|
---|
913 | } elsif ($$subdir{ByteOrder} =~ /^Big/i) {
|
---|
914 | SetByteOrder('MM');
|
---|
915 | } else {
|
---|
916 | warn "Can't have variable byte ordering for SubDirectories using OffsetPt\n";
|
---|
917 | return undef;
|
---|
918 | }
|
---|
919 | #### eval OffsetPt ($valuePtr)
|
---|
920 | $ifdOffsetPos = eval($$subdir{OffsetPt}) - $dirStart;
|
---|
921 | }
|
---|
922 | # pinpoint position to look for this IFD
|
---|
923 | $firstTry = $lastTry = $newStart - $dirStart;
|
---|
924 | }
|
---|
925 | }
|
---|
926 | #
|
---|
927 | # scan for something that looks like an IFD
|
---|
928 | #
|
---|
929 | if ($size >= 14 + $firstTry) { # minimum size for an IFD
|
---|
930 | my $offset;
|
---|
931 | IFD_TRY: for ($offset=$firstTry; $offset<=$lastTry; $offset+=2) {
|
---|
932 | last if $offset + 14 > $size; # 14 bytes is minimum size for an IFD
|
---|
933 | my $pos = $dirStart + $offset;
|
---|
934 | #
|
---|
935 | # look for a standard TIFF header (Nikon uses it, others may as well),
|
---|
936 | #
|
---|
937 | if (SetByteOrder(substr($$dataPt, $pos, 2)) and
|
---|
938 | Get16u($dataPt, $pos + 2) == 0x2a)
|
---|
939 | {
|
---|
940 | $ifdOffsetPos = 4;
|
---|
941 | }
|
---|
942 | if (defined $ifdOffsetPos) {
|
---|
943 | # get pointer to IFD
|
---|
944 | my $ptr = Get32u($dataPt, $pos + $ifdOffsetPos);
|
---|
945 | if ($ptr >= $ifdOffsetPos + 4 and $ptr + $offset + 14 <= $size) {
|
---|
946 | # shift directory start and shorten dirLen accordingly
|
---|
947 | $$dirInfo{DirStart} += $ptr + $offset;
|
---|
948 | $$dirInfo{DirLen} -= $ptr + $offset;
|
---|
949 | # shift pointer base to the start of the TIFF header
|
---|
950 | my $shift = $$dirInfo{DataPos} + $dirStart + $offset;
|
---|
951 | $$dirInfo{Base} += $shift;
|
---|
952 | $$dirInfo{DataPos} -= $shift;
|
---|
953 | $$dirInfo{Relative} = 1; # set "relative offsets" flag
|
---|
954 | return $ptr + $offset;
|
---|
955 | }
|
---|
956 | undef $ifdOffsetPos;
|
---|
957 | }
|
---|
958 | #
|
---|
959 | # look for a standard IFD (starts with 2-byte entry count)
|
---|
960 | #
|
---|
961 | my $num = Get16u($dataPt, $pos);
|
---|
962 | next unless $num;
|
---|
963 | # number of entries in an IFD should be between 1 and 255
|
---|
964 | if (!($num & 0xff)) {
|
---|
965 | # lower byte is zero -- byte order could be wrong
|
---|
966 | ToggleByteOrder();
|
---|
967 | $num >>= 8;
|
---|
968 | } elsif ($num & 0xff00) {
|
---|
969 | # upper byte isn't zero -- not an IFD
|
---|
970 | next;
|
---|
971 | }
|
---|
972 | my $bytesFromEnd = $size - ($offset + 2 + 12 * $num);
|
---|
973 | if ($bytesFromEnd < 4) {
|
---|
974 | next unless $bytesFromEnd == 2 or $bytesFromEnd == 0;
|
---|
975 | }
|
---|
976 | # do a quick validation of all format types
|
---|
977 | my $index;
|
---|
978 | for ($index=0; $index<$num; ++$index) {
|
---|
979 | my $entry = $pos + 2 + 12 * $index;
|
---|
980 | my $format = Get16u($dataPt, $entry+2);
|
---|
981 | my $count = Get32u($dataPt, $entry+4);
|
---|
982 | # allow everything to be zero if not first entry
|
---|
983 | # because some manufacturers pad with null entries
|
---|
984 | next unless $format or $count or $index == 0;
|
---|
985 | # (would like to verify tag ID, but some manufactures don't
|
---|
986 | # sort entries in order of tag ID so we don't have much of
|
---|
987 | # a handle to verify this field)
|
---|
988 | # verify format
|
---|
989 | next IFD_TRY if $format < 1 or $format > 13;
|
---|
990 | # count must be reasonable (can't test for zero count because
|
---|
991 | # cameras like the 1DmkIII use this value)
|
---|
992 | next IFD_TRY if $count & 0xff000000;
|
---|
993 | }
|
---|
994 | $$dirInfo{DirStart} += $offset; # update directory start
|
---|
995 | $$dirInfo{DirLen} -= $offset;
|
---|
996 | return $offset; # success!!
|
---|
997 | }
|
---|
998 | }
|
---|
999 | return undef;
|
---|
1000 | }
|
---|
1001 |
|
---|
1002 | #------------------------------------------------------------------------------
|
---|
1003 | # Process unknown maker notes assuming it is in EXIF IFD format
|
---|
1004 | # Inputs: 0) ExifTool object reference, 1) reference to directory information
|
---|
1005 | # 2) pointer to tag table
|
---|
1006 | # Returns: 1 on success, and updates $dirInfo if necessary for new directory
|
---|
1007 | sub ProcessUnknown($$$)
|
---|
1008 | {
|
---|
1009 | my ($exifTool, $dirInfo, $tagTablePtr) = @_;
|
---|
1010 | my $success = 0;
|
---|
1011 |
|
---|
1012 | my $loc = LocateIFD($exifTool, $dirInfo);
|
---|
1013 | if (defined $loc) {
|
---|
1014 | $exifTool->{UnknownByteOrder} = GetByteOrder();
|
---|
1015 | if ($exifTool->Options('Verbose') > 1) {
|
---|
1016 | my $out = $exifTool->Options('TextOut');
|
---|
1017 | my $indent = $exifTool->{INDENT};
|
---|
1018 | $indent =~ s/\| $/ /;
|
---|
1019 | printf $out "${indent}Found IFD at offset 0x%.4x in maker notes:\n",
|
---|
1020 | $$dirInfo{DirStart} + $$dirInfo{DataPos} + $$dirInfo{Base};
|
---|
1021 | }
|
---|
1022 | $success = Image::ExifTool::Exif::ProcessExif($exifTool, $dirInfo, $tagTablePtr);
|
---|
1023 | } else {
|
---|
1024 | $exifTool->{UnknownByteOrder} = ''; # indicates we tried but didn't set byte order
|
---|
1025 | $exifTool->Warn("Unrecognized $$dirInfo{DirName}");
|
---|
1026 | }
|
---|
1027 | return $success;
|
---|
1028 | }
|
---|
1029 |
|
---|
1030 |
|
---|
1031 | 1; # end
|
---|
1032 |
|
---|
1033 | __END__
|
---|
1034 |
|
---|
1035 | =head1 NAME
|
---|
1036 |
|
---|
1037 | Image::ExifTool::MakerNotes - Read and write EXIF maker notes
|
---|
1038 |
|
---|
1039 | =head1 SYNOPSIS
|
---|
1040 |
|
---|
1041 | This module is required by Image::ExifTool.
|
---|
1042 |
|
---|
1043 | =head1 DESCRIPTION
|
---|
1044 |
|
---|
1045 | This module contains definitions required by Image::ExifTool to interpret
|
---|
1046 | maker notes in EXIF information.
|
---|
1047 |
|
---|
1048 | =head1 AUTHOR
|
---|
1049 |
|
---|
1050 | Copyright 2003-2007, Phil Harvey (phil at owl.phy.queensu.ca)
|
---|
1051 |
|
---|
1052 | This library is free software; you can redistribute it and/or modify it
|
---|
1053 | under the same terms as Perl itself.
|
---|
1054 |
|
---|
1055 | =head1 SEE ALSO
|
---|
1056 |
|
---|
1057 | L<Image::ExifTool::TagNames(3pm)|Image::ExifTool::TagNames>,
|
---|
1058 | L<Image::ExifTool(3pm)|Image::ExifTool>
|
---|
1059 |
|
---|
1060 | =cut
|
---|