source: gsdl/trunk/perllib/cpan/Image/ExifTool/MakerNotes.pm@ 16842

Last change on this file since 16842 was 16842, checked in by davidb, 16 years ago

ExifTool added to cpan area to support metadata extraction from files such as JPEG. Primarily targetted as Image files (hence the Image folder name decided upon by the ExifTool author) it also can handle video such as flash and audio such as Wav

File size: 38.8 KB
Line 
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
9package Image::ExifTool::MakerNotes;
10
11use strict;
12use vars qw($VERSION);
13use Image::ExifTool qw(:DataAccess);
14use Image::ExifTool::Exif;
15
16sub ProcessUnknown($$$);
17
18$VERSION = '1.34';
19
20my $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
561my $tagInfo;
562foreach $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
580sub 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
636sub 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)
676sub 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!
868sub 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;
931IFD_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
1007sub 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
10311; # end
1032
1033__END__
1034
1035=head1 NAME
1036
1037Image::ExifTool::MakerNotes - Read and write EXIF maker notes
1038
1039=head1 SYNOPSIS
1040
1041This module is required by Image::ExifTool.
1042
1043=head1 DESCRIPTION
1044
1045This module contains definitions required by Image::ExifTool to interpret
1046maker notes in EXIF information.
1047
1048=head1 AUTHOR
1049
1050Copyright 2003-2007, Phil Harvey (phil at owl.phy.queensu.ca)
1051
1052This library is free software; you can redistribute it and/or modify it
1053under the same terms as Perl itself.
1054
1055=head1 SEE ALSO
1056
1057L<Image::ExifTool::TagNames(3pm)|Image::ExifTool::TagNames>,
1058L<Image::ExifTool(3pm)|Image::ExifTool>
1059
1060=cut
Note: See TracBrowser for help on using the repository browser.