File Coverage

blib/lib/Image/ExifTool/MakerNotes.pm
Criterion Covered Total %
statement 240 354 67.8
branch 139 254 54.7
condition 68 155 43.8
subroutine 12 15 80.0
pod 0 11 0.0
total 459 789 58.1


line stmt bran cond sub pod time code
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 113     113   892 use strict;
  113         327  
  113         5013  
12 113     113   695 use vars qw($VERSION);
  113         293  
  113         6027  
13 113     113   1216 use Image::ExifTool qw(:DataAccess);
  113         452  
  113         24639  
14 113     113   952 use Image::ExifTool::Exif;
  113         423  
  113         839888  
15              
16             sub ProcessUnknown($$$);
17             sub ProcessUnknownOrPreview($$$);
18             sub ProcessCanon($$$);
19             sub ProcessGE2($$$);
20             sub ProcessKodakPatch($$$);
21             sub WriteUnknownOrPreview($$$);
22             sub FixLeicaBase($$;$);
23              
24             $VERSION = '2.19';
25              
26             my $debug; # set to 1 to enable debugging code
27              
28             # conditional list of maker notes
29             # Notes:
30             # - This is NOT a normal tag table!
31             # - All byte orders are now specified because we can now
32             # write maker notes into a file with different byte ordering!
33             # - Put these in alphabetical order to make TagNames documentation nicer.
34             # - don't forget to set "NotIFD => 1" if the directory is not in EXIF IFD format
35             @Image::ExifTool::MakerNotes::Main = (
36             # decide which MakerNotes to use (based on makernote header and camera make/model)
37             {
38             Name => 'MakerNoteApple',
39             Condition => '$$valPt =~ /^Apple iOS\0/',
40             SubDirectory => {
41             TagTable => 'Image::ExifTool::Apple::Main',
42             Start => '$valuePtr + 14',
43             Base => '$start - 14',
44             ByteOrder => 'Unknown',
45             },
46             },
47             {
48             # this maker notes starts with a standard TIFF header at offset 0x0a
49             # (must check Nikon signature first because Nikon Capture NX can generate
50             # NEF images containing Nikon maker notes from JPEG images of any camera model)
51             Name => 'MakerNoteNikon',
52             Condition => '$$valPt=~/^Nikon\x00\x02/',
53             SubDirectory => {
54             TagTable => 'Image::ExifTool::Nikon::Main',
55             Start => '$valuePtr + 18',
56             Base => '$start - 8',
57             ByteOrder => 'Unknown',
58             },
59             },
60             {
61             Name => 'MakerNoteCanon',
62             # (starts with an IFD)
63             Condition => '$$self{Make} =~ /^Canon/',
64             SubDirectory => {
65             TagTable => 'Image::ExifTool::Canon::Main',
66             ProcessProc => \&ProcessCanon,
67             ByteOrder => 'Unknown',
68             },
69             },
70             {
71             Name => 'MakerNoteCasio',
72             # do negative lookahead assertion just to get tags
73             # in a nice order for documentation
74             # (starts with an IFD)
75             Condition => '$$self{Make}=~/^CASIO/ and $$valPt!~/^(QVC|DCI)\0/',
76             SubDirectory => {
77             TagTable => 'Image::ExifTool::Casio::Main',
78             ByteOrder => 'Unknown',
79             },
80             },
81             {
82             Name => 'MakerNoteCasio2',
83             # (starts with "QVC\0" [Casio] or "DCI\0" [Concord])
84             # (also found in AVI and MOV videos)
85             Condition => '$$valPt =~ /^(QVC|DCI)\0/',
86             SubDirectory => {
87             TagTable => 'Image::ExifTool::Casio::Type2',
88             Start => '$valuePtr + 6',
89             ByteOrder => 'Unknown',
90             FixBase => 1, # necessary for AVI and MOV videos
91             },
92             },
93             {
94             Name => 'MakerNoteDJIInfo',
95             Condition => '$$valPt =~ /^\[ae_dbg_info:/',
96             NotIFD => 1,
97             SubDirectory => { TagTable => 'Image::ExifTool::DJI::Info' },
98             },
99             {
100             Name => 'MakerNoteDJI',
101             Condition => '$$self{Make} eq "DJI" and $$valPt !~ /^(...\@AMBA|DJI)/s',
102             SubDirectory => {
103             TagTable => 'Image::ExifTool::DJI::Main',
104             Start => '$valuePtr',
105             ByteOrder => 'Unknown',
106             },
107             },
108             {
109             Name => 'MakerNoteFLIR',
110             # (starts with IFD, Make is 'FLIR Systems AB' or 'FLIR Systems')
111             Condition => '$$self{Make} =~ /^FLIR Systems/',
112             SubDirectory => {
113             TagTable => 'Image::ExifTool::FLIR::Main',
114             Start => '$valuePtr',
115             ByteOrder => 'Unknown',
116             },
117             },
118             {
119             # The Fuji maker notes use a structure similar to a self-contained
120             # TIFF file, but with "FUJIFILM" instead of the standard TIFF header
121             Name => 'MakerNoteFujiFilm',
122             # (starts with "FUJIFILM" -- also used by some Leica, Minolta and Sharp models)
123             # (GE FujiFilm models start with "GENERALE")
124             Condition => '$$valPt =~ /^(FUJIFILM|GENERALE)/',
125             SubDirectory => {
126             TagTable => 'Image::ExifTool::FujiFilm::Main',
127             # there is an 8-byte maker tag (FUJIFILM) we must skip over
128             OffsetPt => '$valuePtr+8',
129             # the pointers are relative to the subdirectory start
130             # (before adding the offsetPt) - PH
131             Base => '$start',
132             ByteOrder => 'LittleEndian',
133             },
134             },
135             {
136             Name => 'MakerNoteGE',
137             Condition => '$$valPt =~ /^GE(\0\0|NIC\0)/',
138             SubDirectory => {
139             TagTable => 'Image::ExifTool::GE::Main',
140             Start => '$valuePtr + 18',
141             FixBase => 1,
142             AutoFix => 1,
143             ByteOrder => 'Unknown',
144             },
145             },
146             {
147             Name => 'MakerNoteGE2',
148             Condition => '$$valPt =~ /^GE\x0c\0\0\0\x16\0\0\0/',
149             # Note: we will get a "Maker notes could not be parsed" warning when writing
150             # these maker notes because they aren't currently supported for writing
151             SubDirectory => {
152             TagTable => 'Image::ExifTool::FujiFilm::Main',
153             ProcessProc => \&ProcessGE2,
154             Start => '$valuePtr + 12',
155             Base => '$start - 6',
156             ByteOrder => 'LittleEndian',
157             # hard patch for crazy offsets
158             FixOffsets => '$valuePtr -= 210 if $tagID >= 0x1303',
159             },
160             },
161             {
162             Name => 'MakerNoteGoogle',
163             Condition => '$$valPt =~ /^HDRP[\x02\x03]/',
164             NotIFD => 1,
165             SubDirectory => {
166             TagTable => 'Image::ExifTool::Google::HDRPlusMakerNote',
167             },
168             },
169             {
170             Name => 'MakerNoteHasselblad',
171             Condition => '$$self{Make} eq "Hasselblad"',
172             SubDirectory => {
173             TagTable => 'Image::ExifTool::Unknown::Main',
174             ByteOrder => 'Unknown',
175             Start => '$valuePtr',
176             Base => 0, # (avoids warnings since maker notes are not self-contained)
177             },
178             # 0x0011 - sensor code (ref IB)
179             # 0x0012 - camera model id?
180             # 0x0015 - camera model name
181             # 0x0016 - coating code (ref IB)
182             },
183             # (the GE X5 has really messed up EXIF-like maker notes starting with
184             # "GENIC\x0c\0" --> currently not decoded)
185             {
186             Name => 'MakerNoteHP', # PhotoSmart 720 (also Vivitar 3705, 3705B and 3715)
187             Condition => '$$valPt =~ /^(Hewlett-Packard|Vivitar)/',
188             SubDirectory => {
189             TagTable => 'Image::ExifTool::HP::Main',
190             ProcessProc => \&ProcessUnknown,
191             ByteOrder => 'Unknown',
192             },
193             },
194             {
195             Name => 'MakerNoteHP2', # PhotoSmart E427
196             # (this type of maker note also used by BenQ, Mustek, Sanyo, Traveler and Vivitar)
197             Condition => '$$valPt =~ /^610[\0-\4]/',
198             NotIFD => 1,
199             SubDirectory => {
200             TagTable => 'Image::ExifTool::HP::Type2',
201             Start => '$valuePtr',
202             ByteOrder => 'LittleEndian',
203             },
204             },
205             {
206             Name => 'MakerNoteHP4', # PhotoSmart M627
207             Condition => '$$valPt =~ /^IIII[\x04|\x05]\0/',
208             NotIFD => 1,
209             SubDirectory => {
210             TagTable => 'Image::ExifTool::HP::Type4',
211             Start => '$valuePtr',
212             ByteOrder => 'LittleEndian',
213             },
214             },
215             {
216             Name => 'MakerNoteHP6', # PhotoSmart M425, M525 and M527
217             Condition => '$$valPt =~ /^IIII\x06\0/',
218             NotIFD => 1,
219             SubDirectory => {
220             TagTable => 'Image::ExifTool::HP::Type6',
221             Start => '$valuePtr',
222             ByteOrder => 'LittleEndian',
223             },
224             },
225             {
226             Name => 'MakerNoteISL', # (used in Samsung GX20 samples)
227             Condition => '$$valPt =~ /^ISLMAKERNOTE000\0/',
228             # this maker notes starts with a TIFF-like header at offset 0x10
229             SubDirectory => {
230             TagTable => 'Image::ExifTool::Unknown::Main',
231             Start => '$valuePtr + 24',
232             Base => '$start - 8',
233             ByteOrder => 'Unknown',
234             },
235             },
236             {
237             Name => 'MakerNoteJVC',
238             Condition => '$$valPt=~/^JVC /',
239             SubDirectory => {
240             TagTable => 'Image::ExifTool::JVC::Main',
241             Start => '$valuePtr + 4',
242             ByteOrder => 'Unknown',
243             },
244             },
245             {
246             Name => 'MakerNoteJVCText',
247             Condition => '$$self{Make}=~/^(JVC|Victor)/ and $$valPt=~/^VER:/',
248             NotIFD => 1,
249             SubDirectory => {
250             TagTable => 'Image::ExifTool::JVC::Text',
251             },
252             },
253             {
254             Name => 'MakerNoteKodak1a',
255             Condition => '$$self{Make}=~/^EASTMAN KODAK/ and $$valPt=~/^KDK INFO/',
256             NotIFD => 1,
257             SubDirectory => {
258             TagTable => 'Image::ExifTool::Kodak::Main',
259             Start => '$valuePtr + 8',
260             ByteOrder => 'BigEndian',
261             },
262             },
263             {
264             Name => 'MakerNoteKodak1b',
265             Condition => '$$self{Make}=~/^EASTMAN KODAK/ and $$valPt=~/^KDK/',
266             NotIFD => 1,
267             SubDirectory => {
268             TagTable => 'Image::ExifTool::Kodak::Main',
269             Start => '$valuePtr + 8',
270             ByteOrder => 'LittleEndian',
271             },
272             },
273             {
274             # used by various Kodak, HP, Pentax and Minolta models
275             Name => 'MakerNoteKodak2',
276             Condition => q{
277             $$valPt =~ /^.{8}Eastman Kodak/s or
278             $$valPt =~ /^\x01\0[\0\x01]\0\0\0\x04\0[a-zA-Z]{4}/
279             },
280             NotIFD => 1,
281             SubDirectory => {
282             TagTable => 'Image::ExifTool::Kodak::Type2',
283             ByteOrder => 'BigEndian',
284             },
285             },
286             {
287             # not much to key on here, but we know the
288             # upper byte of the year should be 0x07:
289             Name => 'MakerNoteKodak3',
290             Condition => q{
291             $$self{Make} =~ /^EASTMAN KODAK/ and
292             $$valPt =~ /^(?!MM|II).{12}\x07/s and
293             $$valPt !~ /^(MM|II|AOC)/
294             },
295             NotIFD => 1,
296             SubDirectory => {
297             TagTable => 'Image::ExifTool::Kodak::Type3',
298             ByteOrder => 'BigEndian',
299             },
300             },
301             {
302             Name => 'MakerNoteKodak4',
303             Condition => q{
304             $$self{Make} =~ /^Eastman Kodak/ and
305             $$valPt =~ /^.{41}JPG/s and
306             $$valPt !~ /^(MM|II|AOC)/
307             },
308             NotIFD => 1,
309             SubDirectory => {
310             TagTable => 'Image::ExifTool::Kodak::Type4',
311             ByteOrder => 'BigEndian',
312             },
313             },
314             {
315             Name => 'MakerNoteKodak5',
316             Condition => q{
317             $$self{Make}=~/^EASTMAN KODAK/ and
318             ($$self{Model}=~/CX(4200|4230|4300|4310|6200|6230)/ or
319             # try to pick up similar models we haven't tested yet
320             $$valPt=~/^\0(\x1a\x18|\x3a\x08|\x59\xf8|\x14\x80)\0/)
321             },
322             NotIFD => 1,
323             SubDirectory => {
324             TagTable => 'Image::ExifTool::Kodak::Type5',
325             ByteOrder => 'BigEndian',
326             },
327             },
328             {
329             Name => 'MakerNoteKodak6a',
330             Condition => q{
331             $$self{Make}=~/^EASTMAN KODAK/ and
332             $$self{Model}=~/DX3215/
333             },
334             NotIFD => 1,
335             SubDirectory => {
336             TagTable => 'Image::ExifTool::Kodak::Type6',
337             ByteOrder => 'BigEndian',
338             },
339             },
340             {
341             Name => 'MakerNoteKodak6b',
342             Condition => q{
343             $$self{Make}=~/^EASTMAN KODAK/ and
344             $$self{Model}=~/DX3700/
345             },
346             NotIFD => 1,
347             SubDirectory => {
348             TagTable => 'Image::ExifTool::Kodak::Type6',
349             ByteOrder => 'LittleEndian',
350             },
351             },
352             {
353             Name => 'MakerNoteKodak7',
354             # look for something that looks like a serial number
355             # (confirmed serial numbers have the format KXXXX########, but we also
356             # accept other strings from sample images that may be serial numbers)
357             Condition => q{
358             $$self{Make}=~/Kodak/i and
359             $$valPt =~ /^[CK][A-Z\d]{3} ?[A-Z\d]{1,2}\d{2}[A-Z\d]\d{4}[ \0]/
360             },
361             NotIFD => 1,
362             SubDirectory => {
363             TagTable => 'Image::ExifTool::Kodak::Type7',
364             ByteOrder => 'LittleEndian',
365             },
366             },
367             {
368             Name => 'MakerNoteKodak8a',
369             # IFD-format maker notes: look for reasonable number of
370             # entries and check format and count of first IFD entry
371             Condition => q{
372             $$self{Make}=~/Kodak/i and
373             ($$valPt =~ /^\0[\x02-\x7f]..\0[\x01-\x0c]\0\0/s or
374             $$valPt =~ /^[\x02-\x7f]\0..[\x01-\x0c]\0..\0\0/s)
375             },
376             SubDirectory => {
377             TagTable => 'Image::ExifTool::Kodak::Type8',
378             ProcessProc => \&ProcessUnknown,
379             ByteOrder => 'Unknown',
380             },
381             },
382             {
383             Name => 'MakerNoteKodak8b',
384             # these maker notes have an extra 2 bytes after the entry count
385             # (this is handled by the patch). Also, the IFD uses a Format 13,
386             # which is some 2-byte format (not Float, as decoded by ExifTool)
387             # - written by the PixPro AZ251, AZ361, AZ262, AZ521
388             Condition => q{
389             $$self{Make}=~/Kodak/i and
390             $$valPt =~ /^MM\0\x2a\0\0\0\x08\0.\0\0/
391             },
392             SubDirectory => {
393             TagTable => 'Image::ExifTool::Kodak::Type8',
394             ProcessProc => \&ProcessKodakPatch,
395             ByteOrder => 'BigEndian',
396             Start => '$valuePtr + 8',
397             Base => '$start - 8',
398             },
399             },
400             {
401             Name => 'MakerNoteKodak8c',
402             # TIFF-format maker notes
403             Condition => q{
404             $$self{Make}=~/Kodak/i and
405             $$valPt =~ /^(MM\0\x2a\0\0\0\x08|II\x2a\0\x08\0\0\0)/
406             },
407             SubDirectory => {
408             TagTable => 'Image::ExifTool::Kodak::Type8',
409             ProcessProc => \&ProcessUnknown,
410             ByteOrder => 'Unknown',
411             Start => '$valuePtr + 8',
412             Base => '$start - 8',
413             },
414             },
415             {
416             Name => 'MakerNoteKodak9',
417             # test header and Kodak:DateTimeOriginal
418             Condition => '$$valPt =~ m{^IIII[\x02\x03]\0.{14}\d{4}/\d{2}/\d{2} }s',
419             NotIFD => 1,
420             SubDirectory => {
421             TagTable => 'Image::ExifTool::Kodak::Type9',
422             ByteOrder => 'LittleEndian',
423             },
424             },
425             {
426             Name => 'MakerNoteKodak10',
427             # yet another type of Kodak IFD-format maker notes:
428             # this type begins with a byte order indicator,
429             # followed immediately by the IFD
430             Condition => q{
431             $$self{Make}=~/Kodak/i and
432             $$valPt =~ /^(MM\0[\x02-\x7f]|II[\x02-\x7f]\0)/
433             },
434             SubDirectory => {
435             TagTable => 'Image::ExifTool::Kodak::Type10',
436             ProcessProc => \&ProcessUnknown,
437             ByteOrder => 'Unknown',
438             Start => '$valuePtr + 2',
439             },
440             },
441             {
442             Name => 'MakerNoteKodak11',
443             # these maker notes have a 4-byte entry count
444             # - written by the PixPro S-1 (Note: Make is "JK Imaging, Ltd.", so check Model for "Kodak")
445             Condition => q{
446             $$self{Model}=~/(Kodak|PixPro)/i and
447             $$valPt =~ /^II\x2a\0\x08\0\0\0.\0\0\0/s
448             },
449             SubDirectory => {
450             TagTable => 'Image::ExifTool::Kodak::Type11',
451             ProcessProc => \&ProcessKodakPatch,
452             ByteOrder => 'LittleEndian',
453             Start => '$valuePtr + 8',
454             Base => '$start - 8',
455             },
456             },
457             {
458             Name => 'MakerNoteKodak12',
459             # these maker notes have a 4-byte entry count
460             # - written by the PixPro AZ901 (Note: Make is "JK Imaging, Ltd.", so check Model for "Kodak")
461             Condition => q{
462             $$self{Model}=~/(Kodak|PixPro)/i and
463             $$valPt =~ /^MM\0\x2a\0\0\0\x08\0\0\0./s
464             },
465             SubDirectory => {
466             TagTable => 'Image::ExifTool::Kodak::Type11',
467             ProcessProc => \&ProcessKodakPatch,
468             ByteOrder => 'BigEndian',
469             Start => '$valuePtr + 8',
470             Base => '$start - 8',
471             },
472             },
473             {
474             Name => 'MakerNoteKodakUnknown',
475             Condition => '$$self{Make}=~/Kodak/i and $$valPt!~/^AOC\0/',
476             NotIFD => 1,
477             SubDirectory => {
478             TagTable => 'Image::ExifTool::Kodak::Unknown',
479             ByteOrder => 'BigEndian',
480             },
481             },
482             {
483             Name => 'MakerNoteKyocera',
484             # (starts with "KYOCERA")
485             Condition => '$$valPt =~ /^KYOCERA/',
486             SubDirectory => {
487             TagTable => 'Image::ExifTool::Unknown::Main',
488             Start => '$valuePtr + 22',
489             Base => '$start + 2',
490             EntryBased => 1,
491             ByteOrder => 'Unknown',
492             },
493             },
494             {
495             Name => 'MakerNoteMinolta',
496             Condition => q{
497             $$self{Make}=~/^(Konica Minolta|Minolta)/i and
498             $$valPt !~ /^(MINOL|CAMER|MLY0|KC|\+M\+M|\xd7)/
499             },
500             SubDirectory => {
501             TagTable => 'Image::ExifTool::Minolta::Main',
502             ByteOrder => 'Unknown',
503             },
504             },
505             {
506             # the DiMAGE E323 (MINOL) and E500 (CAMER), and some models
507             # of Mustek, Pentax, Ricoh and Vivitar (CAMER).
508             Name => 'MakerNoteMinolta2',
509             Condition => '$$valPt =~ /^(MINOL|CAMER)\0/ and $$self{OlympusCAMER} = 1',
510             SubDirectory => {
511             # these models use Olympus tags in the range 0x200-0x221 plus 0xf00
512             TagTable => 'Image::ExifTool::Olympus::Main',
513             Start => '$valuePtr + 8',
514             ByteOrder => 'Unknown',
515             },
516             },
517             {
518             # /^MLY0/ - DiMAGE G400, G500, G530, G600
519             # /^KC/ - Revio KD-420Z, DiMAGE E203
520             # /^+M+M/ - DiMAGE E201
521             # /^\xd7/ - DiMAGE RD3000
522             Name => 'MakerNoteMinolta3',
523             Condition => '$$self{Make} =~ /^(Konica Minolta|Minolta)/i',
524             Binary => 1,
525             Notes => 'not EXIF-based',
526             },
527             {
528             Name => 'MakerNoteMotorola',
529             Condition => '$$valPt=~/^MOT\0/',
530             SubDirectory => {
531             TagTable => 'Image::ExifTool::Motorola::Main',
532             Start => '$valuePtr + 8',
533             Base => '$start - 8',
534             ByteOrder => 'Unknown',
535             },
536             },
537             {
538             # older Nikon maker notes
539             Name => 'MakerNoteNikon2',
540             Condition => '$$valPt=~/^Nikon\x00\x01/',
541             SubDirectory => {
542             TagTable => 'Image::ExifTool::Nikon::Type2',
543             Start => '$valuePtr + 8',
544             ByteOrder => 'LittleEndian',
545             },
546             },
547             {
548             # headerless Nikon maker notes
549             Name => 'MakerNoteNikon3',
550             Condition => '$$self{Make}=~/^NIKON/i',
551             SubDirectory => {
552             TagTable => 'Image::ExifTool::Nikon::Main',
553             ByteOrder => 'Unknown', # most are little-endian, but D1 is big
554             },
555             },
556             {
557             Name => 'MakerNoteNintendo',
558             # (starts with an IFD)
559             Condition => '$$self{Make} eq "Nintendo"',
560             SubDirectory => {
561             TagTable => 'Image::ExifTool::Nintendo::Main',
562             ByteOrder => 'Unknown',
563             },
564             },
565             {
566             Name => 'MakerNoteOlympus',
567             # (if Make is 'SEIKO EPSON CORP.', starts with "EPSON\0")
568             # (if Make is 'OLYMPUS OPTICAL CO.,LTD' or 'OLYMPUS CORPORATION',
569             # starts with "OLYMP\0")
570             Condition => '$$valPt =~ /^(OLYMP|EPSON)\0/',
571             SubDirectory => {
572             TagTable => 'Image::ExifTool::Olympus::Main',
573             Start => '$valuePtr + 8',
574             ByteOrder => 'Unknown',
575             },
576             },
577             {
578             Name => 'MakerNoteOlympus2',
579             # new Olympus maker notes start with "OLYMPUS\0"
580             Condition => '$$valPt =~ /^OLYMPUS\0/',
581             SubDirectory => {
582             TagTable => 'Image::ExifTool::Olympus::Main',
583             Start => '$valuePtr + 12',
584             Base => '$start - 12',
585             ByteOrder => 'Unknown',
586             },
587             },
588             {
589             Name => 'MakerNoteOlympus3',
590             # new Olympus maker notes start with "OLYMPUS\0"
591             Condition => '$$valPt =~ /^OM SYSTEM\0/',
592             SubDirectory => {
593             TagTable => 'Image::ExifTool::Olympus::Main',
594             Start => '$valuePtr + 16',
595             Base => '$start - 16',
596             ByteOrder => 'Unknown',
597             },
598             },
599             {
600             Name => 'MakerNoteLeica',
601             # (starts with "LEICA\0\0\0")
602             Condition => '$$self{Make} eq "LEICA"',
603             SubDirectory => {
604             # many Leica models use the same format as Panasonic
605             TagTable => 'Image::ExifTool::Panasonic::Main',
606             Start => '$valuePtr + 8',
607             ByteOrder => 'Unknown',
608             },
609             },
610             {
611             Name => 'MakerNoteLeica2', # used by the M8
612             # (starts with "LEICA\0\0\0")
613             Condition => '$$self{Make} =~ /^Leica Camera AG/ and $$valPt =~ /^LEICA\0\0\0/',
614             SubDirectory => {
615             TagTable => 'Image::ExifTool::Panasonic::Leica2',
616             # (the offset base is different in JPEG and DNG images, but we
617             # can copy makernotes from one to the other, so we need special
618             # logic to decide which base to apply)
619             ProcessProc => \&FixLeicaBase,
620             Start => '$valuePtr + 8',
621             Base => '$start', # (- 8 for DNG images!)
622             ByteOrder => 'Unknown',
623             },
624             },
625             {
626             Name => 'MakerNoteLeica3', # used by the R8 and R9
627             # (starts with IFD)
628             Condition => q{
629             $$self{Make} =~ /^Leica Camera AG/ and $$valPt !~ /^LEICA/ and
630             $$self{Model} ne "S2" and $$self{Model} ne "LEICA M (Typ 240)"
631             },
632             SubDirectory => {
633             TagTable => 'Image::ExifTool::Panasonic::Leica3',
634             Start => '$valuePtr',
635             ByteOrder => 'Unknown',
636             },
637             },
638             {
639             Name => 'MakerNoteLeica4', # used by the M9/M-Monochrom
640             # (M9 and M Monochrom start with "LEICA0\x03\0")
641             Condition => '$$self{Make} =~ /^Leica Camera AG/ and $$valPt =~ /^LEICA0/',
642             SubDirectory => {
643             TagTable => 'Image::ExifTool::Panasonic::Leica4',
644             Start => '$valuePtr + 8',
645             Base => '$start - 8', # (yay! Leica fixed the M8 problem)
646             ByteOrder => 'Unknown',
647             },
648             },
649             {
650             Name => 'MakerNoteLeica5', # used by the X1/X2/X VARIO/T/X-U
651             # (X1 starts with "LEICA\0\x01\0", Make is "LEICA CAMERA AG")
652             # (X2 starts with "LEICA\0\x05\0", Make is "LEICA CAMERA AG")
653             # (X VARIO starts with "LEICA\0\x04\0", Make is "LEICA CAMERA AG")
654             # (T (Typ 701) starts with "LEICA\0\0x6", Make is "LEICA CAMERA AG")
655             # (X (Typ 113) starts with "LEICA\0\0x7", Make is "LEICA CAMERA AG")
656             # (X-U (Typ 113) starts with "LEICA\0\x10\0", Make is "LEICA CAMERA AG")
657             Condition => '$$valPt =~ /^LEICA\0[\x01\x04\x05\x06\x07\x10\x1a]\0/',
658             SubDirectory => {
659             TagTable => 'Image::ExifTool::Panasonic::Leica5',
660             Start => '$valuePtr + 8',
661             Base => '$start - 8',
662             ByteOrder => 'Unknown',
663             },
664             },
665             {
666             Name => 'MakerNoteLeica6', # used by the S2, M (Typ 240) and S (Typ 006)
667             # (starts with "LEICA\0\x02\xff", Make is "Leica Camera AG", but test the
668             # model names separately because the maker notes data may not be loaded
669             # at the time this is tested if they are in a JPEG trailer. Also, this
670             # header is used by the M Monochrom (Type 246), with different offsets.)
671             Condition => q{
672             ($$self{Make} eq 'Leica Camera AG' and ($$self{Model} eq 'S2' or
673             $$self{Model} eq 'LEICA M (Typ 240)' or $$self{Model} eq 'LEICA S (Typ 006)'))
674             },
675             DataTag => 'LeicaTrailer', # (generates fixup name for this tag)
676             LeicaTrailer => 1, # flag to special-case this tag in the Exif code
677             SubDirectory => {
678             TagTable => 'Image::ExifTool::Panasonic::Leica6',
679             Start => '$valuePtr + 8',
680             ByteOrder => 'Unknown',
681             # NOTE: Leica uses absolute file offsets when this maker note is stored
682             # as a JPEG trailer -- this case is handled by ProcessLeicaTrailer in
683             # Panasonic.pm, and any "Base" defined here is ignored for this case.
684             # ExifTool may also create S2/M maker notes inside the APP1 segment when
685             # copying from other files, and for this the normal EXIF offsets are used,
686             # Base should not be defined!
687             },
688             },
689             {
690             Name => 'MakerNoteLeica7', # used by the M Monochrom (Typ 246)
691             # (starts with "LEICA\0\x02\xff", Make is "Leica Camera AG")
692             Condition => '$$valPt =~ /^LEICA\0\x02\xff/',
693             DataTag => 'LeicaTrailer', # (generates fixup name for this tag)
694             LeicaTrailer => 1, # flag to special-case this tag in the Exif code
695             SubDirectory => {
696             TagTable => 'Image::ExifTool::Panasonic::Leica6',
697             Start => '$valuePtr + 8',
698             ByteOrder => 'Unknown',
699             Base => '-$base', # uses absolute file offsets (not based on TIFF header offset)
700             },
701             },
702             {
703             Name => 'MakerNoteLeica8', # used by the Q (Type 116)
704             # (Q (Typ 116) starts with "LEICA\0\x08\0", Make is "LEICA CAMERA AG")
705             # (SL (Typ 601) and CL start with "LEICA\0\x09\0", Make is "LEICA CAMERA AG")
706             Condition => '$$valPt =~ /^LEICA\0[\x08\x09\x0a]\0/',
707             SubDirectory => {
708             TagTable => 'Image::ExifTool::Panasonic::Leica5',
709             Start => '$valuePtr + 8',
710             ByteOrder => 'Unknown',
711             },
712             },
713             {
714             Name => 'MakerNoteLeica9', # used by the M10/S
715             # (M10 and S start with "LEICA0\x02\0")
716             Condition => '$$self{Make} =~ /^Leica Camera AG/ and $$valPt =~ /^LEICA\0\x02\0/',
717             SubDirectory => {
718             TagTable => 'Image::ExifTool::Panasonic::Leica9',
719             Start => '$valuePtr + 8',
720             ByteOrder => 'Unknown',
721             },
722             },
723             {
724             Name => 'MakerNoteLeica10', # used by the D-Lux7
725             Condition => '$$valPt =~ /^LEICA CAMERA AG\0/',
726             SubDirectory => {
727             TagTable => 'Image::ExifTool::Panasonic::Main',
728             Start => '$valuePtr + 18',
729             ByteOrder => 'Unknown',
730             },
731             },
732             {
733             Name => 'MakerNotePanasonic',
734             # (starts with "Panasonic\0")
735             Condition => '$$valPt=~/^Panasonic/ and $$self{Model} ne "DC-FT7"',
736             SubDirectory => {
737             TagTable => 'Image::ExifTool::Panasonic::Main',
738             Start => '$valuePtr + 12',
739             ByteOrder => 'Unknown',
740             },
741             },
742             {
743             Name => 'MakerNotePanasonic2',
744             # (starts with "Panasonic\0")
745             Condition => '$$self{Make}=~/^Panasonic/ and $$valPt=~/^MKE/',
746             SubDirectory => {
747             TagTable => 'Image::ExifTool::Panasonic::Type2',
748             ByteOrder => 'LittleEndian',
749             },
750             },
751             {
752             Name => 'MakerNotePanasonic3', # (DC-FT7)
753             # (starts with "Panasonic\0")
754             Condition => '$$valPt=~/^Panasonic/',
755             SubDirectory => {
756             TagTable => 'Image::ExifTool::Panasonic::Main',
757             Start => '$valuePtr + 12',
758             Base => 12, # crazy!
759             ByteOrder => 'Unknown',
760             },
761             },
762             {
763             Name => 'MakerNotePentax',
764             # (starts with "AOC\0", but so does MakerNotePentax3)
765             # (also used by some Samsung models)
766             Condition => q{
767             $$valPt=~/^AOC\0/ and
768             $$self{Model} !~ /^PENTAX Optio ?[34]30RS\s*$/
769             },
770             SubDirectory => {
771             TagTable => 'Image::ExifTool::Pentax::Main',
772             # process as Unknown maker notes because the start offset and
773             # byte ordering are so variable
774             ProcessProc => \&ProcessUnknown,
775             # offsets can be totally whacky for Pentax maker notes,
776             # so attempt to fix the offset base if possible
777             FixBase => 1,
778             ByteOrder => 'Unknown',
779             },
780             },
781             {
782             Name => 'MakerNotePentax2',
783             # (starts with an IFD)
784             # Casio-like maker notes used only by the Optio 330 and 430
785             Condition => '$$self{Make}=~/^Asahi/ and $$valPt!~/^AOC\0/',
786             SubDirectory => {
787             TagTable => 'Image::ExifTool::Pentax::Type2',
788             ProcessProc => \&ProcessUnknown,
789             FixBase => 1,
790             ByteOrder => 'Unknown',
791             },
792             },
793             {
794             Name => 'MakerNotePentax3',
795             # (starts with "AOC\0", like the more common Pentax maker notes)
796             # Casio maker notes used only by the Optio 330RS and 430RS
797             Condition => '$$self{Make}=~/^Asahi/',
798             SubDirectory => {
799             TagTable => 'Image::ExifTool::Casio::Type2',
800             ProcessProc => \&ProcessUnknown,
801             FixBase => 1,
802             ByteOrder => 'Unknown',
803             },
804             },
805             {
806             Name => 'MakerNotePentax4',
807             # (starts with 3 or 4 digits)
808             # HP2-like text-based maker notes used by Optio E20
809             Condition => '$$self{Make}=~/^PENTAX/ and $$valPt=~/^\d{3}/',
810             NotIFD => 1,
811             SubDirectory => {
812             TagTable => 'Image::ExifTool::Pentax::Type4',
813             Start => '$valuePtr',
814             ByteOrder => 'LittleEndian',
815             },
816             },
817             {
818             Name => 'MakerNotePentax5',
819             # (starts with "PENTAX \0")
820             # used by cameras such as the Q, Optio S1, RS1500 and WG-1
821             Condition => '$$valPt=~/^PENTAX \0/',
822             SubDirectory => {
823             TagTable => 'Image::ExifTool::Pentax::Main',
824             Start => '$valuePtr + 10',
825             Base => '$start - 10',
826             ByteOrder => 'Unknown',
827             },
828             },
829             {
830             Name => 'MakerNotePentax6',
831             # (starts with "S1\0\0\0\0\0\0\x0c\0\0\0")
832             Condition => '$$valPt=~/^S1\0{6}\x0c\0{3}/',
833             SubDirectory => {
834             TagTable => 'Image::ExifTool::Pentax::S1',
835             Start => '$valuePtr + 12',
836             Base => '$start - 12',
837             ByteOrder => 'Unknown',
838             },
839             },
840             {
841             Name => 'MakerNotePhaseOne',
842             # Starts with: 'IIIITwaR' or 'IIIICwaR' (have seen both written by P25)
843             # (have also seen code which expects 'MMMMRawT')
844             Condition => q{
845             return undef unless $$valPt =~ /^(IIII.waR|MMMMRaw.)/s;
846             $self->OverrideFileType($$self{TIFF_TYPE} = 'IIQ') if $count > 1000000;
847             return 1;
848             },
849             NotIFD => 1,
850             IsPhaseOne => 1, # flag to rebuild these differently
851             SubDirectory => { TagTable => 'Image::ExifTool::PhaseOne::Main' },
852             PutFirst => 1, # place immediately after TIFF header
853             },
854             {
855             Name => 'MakerNoteReconyxHyperFire',
856             Condition => q{
857             $$valPt =~ /^\x01\xf1([\x02\x03]\x00)?/ and
858             ($1 or $$self{Make} eq "RECONYX")
859             },
860             SubDirectory => {
861             TagTable => 'Image::ExifTool::Reconyx::HyperFire',
862             ByteOrder => 'Little-endian',
863             },
864             },
865             {
866             Name => 'MakerNoteReconyxUltraFire',
867             Condition => '$$valPt =~ /^RECONYXUF\0/',
868             SubDirectory => {
869             TagTable => 'Image::ExifTool::Reconyx::UltraFire',
870             ByteOrder => 'Little-endian',
871             },
872             },
873             {
874             Name => 'MakerNoteReconyxHyperFire2',
875             Condition => '$$valPt =~ /^RECONYXH2\0/',
876             SubDirectory => {
877             TagTable => 'Image::ExifTool::Reconyx::HyperFire2',
878             ByteOrder => 'Little-endian',
879             },
880             },
881             {
882             Name => 'MakerNoteReconyxMicroFire',
883             Condition => '$$valPt =~ /^RECONYXMF\0/',
884             SubDirectory => {
885             TagTable => 'Image::ExifTool::Reconyx::MicroFire',
886             ByteOrder => 'Little-endian',
887             },
888             },
889             {
890             Name => 'MakerNoteReconyxHyperFire4K',
891             Condition => '$$valPt =~ /^RECONYXHF4K\0/',
892             SubDirectory => {
893             TagTable => 'Image::ExifTool::Reconyx::HyperFire4K',
894             ByteOrder => 'Little-endian',
895             },
896             },
897             {
898             Name => 'MakerNoteRicohPentax',
899             # used by cameras such as the Ricoh GR III
900             Condition => '$$valPt=~/^RICOH\0(II|MM)/',
901             SubDirectory => {
902             TagTable => 'Image::ExifTool::Pentax::Main',
903             Start => '$valuePtr + 8',
904             Base => '$start - 8',
905             ByteOrder => 'Unknown',
906             },
907             },
908             {
909             Name => 'MakerNoteRicoh',
910             # (my test R50 image starts with " \x02\x01" - PH)
911             Condition => q{
912             $$self{Make} =~ /^(PENTAX )?RICOH/ and
913             $$valPt =~ /^(Ricoh| |MM\0\x2a|II\x2a\0)/i and
914             $$valPt !~ /^(MM\0\x2a\0\0\0\x08\0.\0\0|II\x2a\0\x08\0\0\0.\0\0\0)/s and
915             $$self{Model} ne 'RICOH WG-M1'
916             },
917             SubDirectory => {
918             TagTable => 'Image::ExifTool::Ricoh::Main',
919             Start => '$valuePtr + 8',
920             ByteOrder => 'Unknown',
921             },
922             },
923             {
924             Name => 'MakerNoteRicoh2',
925             # (the Ricoh HZ15 starts with "MM\0\x2a" and the Pentax XG-1 starts with "II\x2a\0",
926             # but an extra 2 bytes of padding after the IFD entry count prevents these from
927             # being processed as a standard IFD. Note that the offsets for the HZ15 are all
928             # zeros, but they seem to be mostly OK for the XG-1)
929             Condition => q{
930             $$self{Make} =~ /^(PENTAX )?RICOH/ and ($$self{Model} eq 'RICOH WG-M1' or
931             $$valPt =~ /^(MM\0\x2a\0\0\0\x08\0.\0\0|II\x2a\0\x08\0\0\0.\0\0\0)/s)
932             },
933             SubDirectory => {
934             TagTable => 'Image::ExifTool::Ricoh::Type2',
935             Start => '$valuePtr + 8',
936             Base => '$start - 8',
937             ByteOrder => 'Unknown',
938             ProcessProc => \&ProcessKodakPatch,
939             },
940             },
941             {
942             Name => 'MakerNoteRicohText',
943             Condition => '$$self{Make}=~/^RICOH/',
944             NotIFD => 1,
945             SubDirectory => {
946             TagTable => 'Image::ExifTool::Ricoh::Text',
947             ByteOrder => 'Unknown',
948             },
949             },
950             {
951             Name => 'MakerNoteSamsung1a',
952             # Samsung STMN maker notes WITHOUT PreviewImage
953             Condition => '$$valPt =~ /^STMN\d{3}.\0{4}/s',
954             Binary => 1,
955             Notes => 'Samsung "STMN" maker notes without PreviewImage',
956             },
957             {
958             Name => 'MakerNoteSamsung1b',
959             # Samsung STMN maker notes WITH PreviewImage
960             Condition => '$$valPt =~ /^STMN\d{3}/',
961             SubDirectory => {
962             TagTable => 'Image::ExifTool::Samsung::Main',
963             },
964             },
965             {
966             Name => 'MakerNoteSamsung2',
967             # Samsung EXIF-format maker notes (
968             Condition => q{
969             uc $$self{Make} eq 'SAMSUNG' and ($$self{TIFF_TYPE} eq 'SRW' or
970             $$valPt=~/^(\0.\0\x01\0\x07\0{3}\x04|.\0\x01\0\x07\0\x04\0{3})0100/s)
971             },
972             SubDirectory => {
973             TagTable => 'Image::ExifTool::Samsung::Type2',
974             # Samsung is very inconsistent here, and uses absolute offsets for some
975             # models and relative offsets for others, so process as Unknown
976             ProcessProc => \&ProcessUnknown,
977             FixBase => 1,
978             ByteOrder => 'Unknown',
979             },
980             },
981             {
982             Name => 'MakerNoteSanyo',
983             # (starts with "SANYO\0")
984             Condition => '$$self{Make}=~/^SANYO/ and $$self{Model}!~/^(C4|J\d|S\d)\b/',
985             SubDirectory => {
986             TagTable => 'Image::ExifTool::Sanyo::Main',
987             Validate => '$val =~ /^SANYO/',
988             Start => '$valuePtr + 8',
989             ByteOrder => 'Unknown',
990             },
991             },
992             {
993             Name => 'MakerNoteSanyoC4',
994             # The C4 offsets are wrong by 12, so they must be fixed
995             Condition => '$$self{Make}=~/^SANYO/ and $$self{Model}=~/^C4\b/',
996             SubDirectory => {
997             TagTable => 'Image::ExifTool::Sanyo::Main',
998             Validate => '$val =~ /^SANYO/',
999             Start => '$valuePtr + 8',
1000             FixBase => 1,
1001             ByteOrder => 'Unknown',
1002             },
1003             },
1004             {
1005             Name => 'MakerNoteSanyoPatch',
1006             # The J1, J2, J4, S1, S3 and S4 offsets are completely screwy
1007             Condition => '$$self{Make}=~/^SANYO/',
1008             SubDirectory => {
1009             TagTable => 'Image::ExifTool::Sanyo::Main',
1010             Validate => '$val =~ /^SANYO/',
1011             Start => '$valuePtr + 8',
1012             ByteOrder => 'Unknown',
1013             FixOffsets => 'Image::ExifTool::Sanyo::FixOffsets($valuePtr, $valEnd, $size, $tagID, $wFlag)',
1014             },
1015             },
1016             {
1017             Name => 'MakerNoteSigma',
1018             Condition => q{
1019             return undef unless $$self{Make}=~/^(SIGMA|FOVEON)/i;
1020             # save version number in "MakerNoteSigmaVer" member variable
1021             $$self{MakerNoteSigmaVer} = $$valPt=~/^SIGMA\0\0\0.(.)/s ? ord($1) : -1;
1022             return 1;
1023             },
1024             SubDirectory => {
1025             TagTable => 'Image::ExifTool::Sigma::Main',
1026             Validate => '$val =~ /^(SIGMA|FOVEON)/',
1027             Start => '$valuePtr + 10',
1028             ByteOrder => 'Unknown',
1029             },
1030             },
1031             {
1032             Name => 'MakerNoteSony',
1033             # (starts with "SONY DSC \0" or "SONY CAM \0")
1034             # (TF1 starts with "\0\0SONY PIC\0")
1035             # (Hasselblad models start with "VHAB \0")
1036             Condition => '$$valPt=~/^(SONY (DSC|CAM|MOBILE)|\0\0SONY PIC\0|VHAB \0)/',
1037             SubDirectory => {
1038             TagTable => 'Image::ExifTool::Sony::Main',
1039             Start => '$valuePtr + 12',
1040             ByteOrder => 'Unknown',
1041             },
1042             },
1043             {
1044             Name => 'MakerNoteSony2',
1045             # (starts with "SONY PI\0" -- DSC-S650/S700/S750)
1046             Condition => '$$valPt=~/^SONY PI\0/ and $$self{OlympusCAMER}=1',
1047             SubDirectory => {
1048             TagTable => 'Image::ExifTool::Olympus::Main',
1049             Start => '$valuePtr + 12',
1050             ByteOrder => 'Unknown',
1051             },
1052             },
1053             {
1054             Name => 'MakerNoteSony3',
1055             # (starts with "PREMI\0" -- DSC-S45/S500)
1056             Condition => '$$valPt=~/^(PREMI)\0/ and $$self{OlympusCAMER}=1',
1057             SubDirectory => {
1058             TagTable => 'Image::ExifTool::Olympus::Main',
1059             Start => '$valuePtr + 8',
1060             ByteOrder => 'Unknown',
1061             },
1062             },
1063             {
1064             Name => 'MakerNoteSony4',
1065             # (starts with "SONY PIC\0" -- DSC-H200/J20/W370/W510, MHS-TS20)
1066             Condition => '$$valPt=~/^SONY PIC\0/',
1067             SubDirectory => { TagTable => 'Image::ExifTool::Sony::PIC' },
1068             },
1069             {
1070             Name => 'MakerNoteSony5', # used in SR2 and ARW images
1071             Condition => '$$self{Make}=~/^SONY/ and $$valPt!~/^\x01\x00/',
1072             Condition => q{
1073             ($$self{Make}=~/^SONY/ or ($$self{Make}=~/^HASSELBLAD/ and
1074             $$self{Model}=~/^(HV|Stellar|Lusso|Lunar)/)) and $$valPt!~/^\x01\x00/
1075             },
1076             SubDirectory => {
1077             TagTable => 'Image::ExifTool::Sony::Main',
1078             Start => '$valuePtr',
1079             ByteOrder => 'Unknown',
1080             },
1081             },
1082             {
1083             Name => 'MakerNoteSonyEricsson',
1084             Condition => '$$valPt =~ /^SEMC MS\0/',
1085             SubDirectory => {
1086             TagTable => 'Image::ExifTool::Sony::Ericsson',
1087             Start => '$valuePtr + 20',
1088             Base => '$start - 8',
1089             ByteOrder => 'Unknown',
1090             },
1091             },
1092             {
1093             Name => 'MakerNoteSonySRF',
1094             Condition => '$$self{Make}=~/^SONY/',
1095             SubDirectory => {
1096             TagTable => 'Image::ExifTool::Sony::SRF',
1097             Start => '$valuePtr',
1098             ByteOrder => 'Unknown',
1099             },
1100             },
1101             {
1102             Name => 'MakerNoteUnknownText',
1103             Condition => '$$valPt =~ /^[\x09\x0d\x0a\x20-\x7e]+\0*$/',
1104             Notes => 'unknown text-based maker notes',
1105             # show as binary if it is too long
1106             ValueConv => 'length($val) > 64 ? \$val : $val',
1107             ValueConvInv => '$val',
1108             },
1109             {
1110             Name => 'MakerNoteUnknownBinary',
1111             # "LSI1\0" - SilverFast
1112             Condition => '$$valPt =~ /^LSI1\0/',
1113             Notes => 'unknown binary maker notes',
1114             Binary => 1,
1115             },
1116             {
1117             Name => 'MakerNoteUnknown',
1118             PossiblePreview => 1,
1119             SubDirectory => {
1120             TagTable => 'Image::ExifTool::Unknown::Main',
1121             ProcessProc => \&ProcessUnknownOrPreview,
1122             WriteProc => \&WriteUnknownOrPreview,
1123             ByteOrder => 'Unknown',
1124             FixBase => 2,
1125             },
1126             },
1127             );
1128              
1129             # insert writable properties so we can write our maker notes
1130             my $tagInfo;
1131             foreach $tagInfo (@Image::ExifTool::MakerNotes::Main) {
1132             $$tagInfo{Writable} = 'undef';
1133             $$tagInfo{Format} = 'undef', # (make sure we don't convert this when reading)
1134             $$tagInfo{WriteGroup} = 'ExifIFD';
1135             $$tagInfo{Groups} = { 1 => 'MakerNotes' };
1136             next unless $$tagInfo{SubDirectory};
1137             # make all SubDirectory tags block-writable
1138             $$tagInfo{Binary} = 1,
1139             $$tagInfo{MakerNotes} = 1;
1140             }
1141              
1142             #------------------------------------------------------------------------------
1143             # Get normal offset of value data from end of maker note IFD
1144             # Inputs: 0) ExifTool object reference
1145             # Returns: Array: 0) relative flag (undef for no change)
1146             # 1) normal offset from end of IFD to first value (empty if unknown)
1147             # 2-N) other possible offsets used by some models
1148             # Notes: Directory size should be validated before calling this routine
1149             sub GetMakerNoteOffset($)
1150             {
1151 179     179 0 436 my $et = shift;
1152             # figure out where we expect the value data based on camera type
1153 179         575 my $make = $$et{Make};
1154 179         562 my $model = $$et{Model};
1155 179         426 my ($relative, @offsets);
1156              
1157             # normally value data starts 4 bytes after end of directory, so this is the default.
1158             # offsets of 0 and 4 are always allowed even if not specified,
1159             # but the first offset specified is the one used when writing
1160 179 100 100     3659 if ($make =~ /^Canon/) {
    100 66        
    100 33        
    50 33        
    50          
    100          
    50          
    100          
    100          
    50          
    100          
    50          
    100          
    100          
    100          
1161 62 100       507 push @offsets, ($model =~ /\b(20D|350D|REBEL XT|Kiss Digital N)\b/) ? 6 : 4;
1162             # some Canon models (FV-M30, Optura50, Optura60) leave 24 unused bytes
1163             # at the end of the IFD (2 spare IFD entries?)
1164 62 50       380 push @offsets, 28 if $model =~ /\b(FV\b|OPTURA)/;
1165             # some Canon PowerShot models leave 12 unused bytes
1166 62 50       454 push @offsets, 16 if $model =~ /(PowerShot|IXUS|IXY)/;
1167             } elsif ($make =~ /^CASIO/) {
1168             # Casio AVI and MOV images use no padding, and their JPEG's use 4,
1169             # except some models like the EX-S770,Z65,Z70,Z75 and Z700 which use 16,
1170             # and the EX-Z35 which uses 2 (grrrr...)
1171 5 50       41 push @offsets, $$et{FILE_TYPE} =~ /^(RIFF|MOV)$/ ? 0 : (4, 16, 2);
1172             } elsif ($make =~ /^(General Imaging Co.|GEDSC IMAGING CORP.)/i) {
1173 4         8 push @offsets, 0;
1174             } elsif ($make =~ /^KYOCERA/) {
1175 0         0 push @offsets, 12;
1176             } elsif ($make =~ /^Leica Camera AG/) {
1177 0 0       0 if ($model eq 'S2') {
    0          
    0          
    0          
1178             # lots of empty space before first value in S2 images
1179 0 0       0 push @offsets, 4, ($$et{FILE_TYPE} eq 'JPEG' ? 286 : 274);
1180             } elsif ($model eq 'LEICA M MONOCHROM (Typ 246)') {
1181 0         0 push @offsets, 4, 130;
1182             } elsif ($model eq 'LEICA M (Typ 240)') {
1183 0         0 push @offsets, 4, 118;
1184             } elsif ($model =~ /^(R8|R9|M8)\b/) {
1185 0         0 push @offsets, 6;
1186             } else {
1187 0         0 push @offsets, 4;
1188             }
1189             } elsif ($make =~ /^OLYMPUS/ and $model =~ /^E-(1|300|330)\b/) {
1190 4         12 push @offsets, 16;
1191             } elsif ($make =~ /^OLYMPUS/ and
1192             # these Olympus models are just weird
1193             $model =~ /^(C2500L|C-1Z?|C-5000Z|X-2|C720UZ|C725UZ|C150|C2Z|E-10|E-20|FerrariMODEL2003|u20D|u10D)\b/)
1194             {
1195             # no expected offset --> determine offset empirically via FixBase()
1196             } elsif ($make =~ /^(Panasonic|JVC)\b/) {
1197 13         34 push @offsets, 0;
1198             } elsif ($make =~ /^SONY/) {
1199             # earlier DSLR and "PREMI" models use an offset of 4
1200 12 50 33     97 if ($model =~ /^(DSLR-.*|SLT-A(33|35|55V)|NEX-(3|5|C3|VG10E))$/ or
1201             $$et{OlympusCAMER})
1202             {
1203 0         0 push @offsets, 4;
1204             } else {
1205 12         37 push @offsets, 0;
1206             }
1207             } elsif ($$et{TIFF_TYPE} eq 'SRW' and $make eq 'SAMSUNG' and $model eq 'EK-GN120') {
1208 0         0 push @offsets, 40; # patch to read most of the maker notes, but breaks PreviewIFD
1209             } elsif ($make eq 'FUJIFILM') {
1210             # some models have offset of 6, so allow that too (A345,A350,A360,A370)
1211 9         30 push @offsets, 4, 6;
1212             } elsif ($make =~ /^TOSHIBA/) {
1213             # similar to Canon, can also have 24 bytes of padding
1214 0         0 push @offsets, 0, 24;
1215             } elsif ($make =~ /^PENTAX/) {
1216 8         25 push @offsets, 4;
1217             # the Pentax addressing mode is determined automatically, but
1218             # sometimes the algorithm gets it wrong, but Pentax always uses
1219             # absolute addressing, so force it to be absolute
1220 8         23 $relative = 0;
1221             } elsif ($make =~ /^Konica Minolta/i) {
1222             # patch for DiMAGE X50, Xg, Z2 and Z10
1223 3         13 push @offsets, 4, -16;
1224             } elsif ($make =~ /^Minolta/) {
1225             # patch for DiMAGE 7, X20 and Z1
1226 4         13 push @offsets, 4, -8, -12;
1227             } else {
1228 55         172 push @offsets, 4; # the normal offset
1229             }
1230 179         748 return ($relative, @offsets);
1231             }
1232              
1233             #------------------------------------------------------------------------------
1234             # Get hash of value offsets / block sizes
1235             # Inputs: 0) Data pointer, 1) offset to start of directory,
1236             # 2) hash ref to return value pointers based on tag ID
1237             # Returns: 0) hash reference: keys are offsets, values are block sizes
1238             # 1) same thing, but with keys adjusted for value-based offsets
1239             # Notes: Directory size should be validated before calling this routine
1240             # - calculates MIN and MAX offsets in entry-based hash
1241             sub GetValueBlocks($$;$)
1242             {
1243 149     149 0 535 my ($dataPt, $dirStart, $tagPtr) = @_;
1244 149         550 my $numEntries = Get16u($dataPt, $dirStart);
1245 149         422 my ($index, $valPtr, %valBlock, %valBlkAdj, $end);
1246 149         706 for ($index=0; $index<$numEntries; ++$index) {
1247 3662         5746 my $entry = $dirStart + 2 + 12 * $index;
1248 3662         7349 my $format = Get16u($dataPt, $entry+2);
1249 3662 50 33     12004 last if $format < 1 or $format > 13;
1250 3662         7195 my $count = Get32u($dataPt, $entry+4);
1251 3662         6691 my $size = $count * $Image::ExifTool::Exif::formatSize[$format];
1252 3662 100       8686 next if $size <= 4;
1253 2103         4226 $valPtr = Get32u($dataPt, $entry+8);
1254 2103 50       5936 $tagPtr and $$tagPtr{Get16u($dataPt, $entry)} = $valPtr;
1255             # save location and size of longest block at this offset
1256 2103 50 66     5776 unless (defined $valBlock{$valPtr} and $valBlock{$valPtr} > $size) {
1257 2103         5414 $valBlock{$valPtr} = $size;
1258             }
1259             # adjust for case of value-based offsets
1260 2103         3288 $valPtr += 12 * $index;
1261 2103 50 33     5283 unless (defined $valBlkAdj{$valPtr} and $valBlkAdj{$valPtr} > $size) {
1262 2103         5421 $valBlkAdj{$valPtr} = $size;
1263 2103         3060 my $end = $valPtr + $size;
1264 2103 100       4239 if (defined $valBlkAdj{MIN}) {
1265             # save minimum only if it has a value of 12 or greater
1266 1957 100 66     6783 $valBlkAdj{MIN} = $valPtr if $valBlkAdj{MIN} < 12 or $valBlkAdj{MIN} > $valPtr;
1267 1957 100       5737 $valBlkAdj{MAX} = $end if $valBlkAdj{MAX} > $end;
1268             } else {
1269 146         479 $valBlkAdj{MIN} = $valPtr;
1270 146         690 $valBlkAdj{MAX} = $end;
1271             }
1272             }
1273             }
1274 149         709 return(\%valBlock, \%valBlkAdj);
1275             }
1276              
1277             #------------------------------------------------------------------------------
1278             # Fix base for value offsets in maker notes IFD (if necessary)
1279             # Inputs: 0) ExifTool object ref, 1) DirInfo hash ref
1280             # Return: amount of base shift (and $dirInfo Base and DataPos are updated,
1281             # FixedBy is set if offsets fixed, and Relative or EntryBased may be set)
1282             sub FixBase($$)
1283             {
1284 190     190 0 468 local $_;
1285 190         611 my ($et, $dirInfo) = @_;
1286             # don't fix base if fixing offsets individually or if we don't want to fix them
1287 190 100 66     1693 return 0 if $$dirInfo{FixOffsets} or $$dirInfo{NoFixBase};
1288              
1289 149         417 my $dataPt = $$dirInfo{DataPt};
1290 149         403 my $dataPos = $$dirInfo{DataPos};
1291 149   100     662 my $dirStart = $$dirInfo{DirStart} || 0;
1292 149         390 my $entryBased = $$dirInfo{EntryBased};
1293 149         427 my $dirName = $$dirInfo{DirName};
1294 149         710 my $fixBase = $et->Options('FixBase');
1295 149 50 33     757 my $setBase = (defined $fixBase and $fixBase ne '') ? 1 : 0;
1296 149         339 my ($fix, $fixedBy, %tagPtr);
1297              
1298             # get hash of value block positions
1299 149         734 my ($valBlock, $valBlkAdj) = GetValueBlocks($dataPt, $dirStart, \%tagPtr);
1300 149 100       699 return 0 unless %$valBlock;
1301             # get sorted list of value offsets
1302 146         1647 my @valPtrs = sort { $a <=> $b } keys %$valBlock;
  6212         10041  
1303             #
1304             # handle special case of Canon maker notes with TIFF footer containing original offset
1305             #
1306 146 100 66     1424 if ($$et{Make} =~ /^Canon/ and $$dirInfo{DirLen} > 8) {
1307 65         220 my $footerPos = $dirStart + $$dirInfo{DirLen} - 8;
1308 65         243 my $footer = substr($$dataPt, $footerPos, 8);
1309 65 100 66     509 if ($footer =~ /^(II\x2a\0|MM\0\x2a)/ and # check for TIFF footer
1310             substr($footer,0,2) eq GetByteOrder()) # validate byte ordering
1311             {
1312 23         91 my $oldOffset = Get32u(\$footer, 4);
1313 23         63 my $newOffset = $dirStart + $dataPos;
1314 23 50       313 if ($setBase) {
1315 0         0 $fix = $fixBase;
1316             } else {
1317 23         60 $fix = $newOffset - $oldOffset;
1318 23 50       587 return 0 unless $fix;
1319             # Picasa and ACDSee have a bug where they update other offsets without
1320             # updating the TIFF footer (PH - 2009/02/25), so test for this case:
1321             # validate Canon maker note footer fix by checking offset of last value
1322 0         0 my $maxPt = $valPtrs[-1] + $$valBlock{$valPtrs[-1]};
1323             # compare to end of maker notes, taking 8-byte footer into account
1324 0         0 my $endDiff = $dirStart + $$dirInfo{DirLen} - ($maxPt - $dataPos) - 8;
1325             # ignore footer offset only if end difference is exactly correct
1326             # (allow for possible padding byte, although I have never seen this)
1327 0 0 0     0 if (not $endDiff or $endDiff == 1) {
1328 0         0 $et->Warn('Canon maker note footer may be invalid (ignored)',1);
1329 0         0 return 0;
1330             }
1331             }
1332 0         0 $et->Warn("Adjusted $dirName base by $fix",1);
1333 0         0 $$dirInfo{FixedBy} = $fix;
1334 0         0 $$dirInfo{Base} += $fix;
1335 0         0 $$dirInfo{DataPos} -= $fix;
1336 0         0 return $fix;
1337             }
1338             }
1339             #
1340             # analyze value offsets to see if they need fixing. The first task is to determine
1341             # the minimum valid offset used (this is tricky, because we have to weed out bad
1342             # offsets written by some cameras)
1343             #
1344 123         524 my $minPt = $$dirInfo{MinOffset} = $valPtrs[0]; # if life were simple, this would be it
1345 123         550 my $ifdLen = 2 + 12 * Get16u($$dirInfo{DataPt}, $dirStart);
1346 123         337 my $ifdEnd = $dirStart + $ifdLen;
1347 123         479 my ($relative, @offsets) = GetMakerNoteOffset($et);
1348 123         259 my $makeDiff = $offsets[0];
1349 123         561 my $verbose = $et->Options('Verbose');
1350 123         350 my ($diff, $shift);
1351              
1352             # calculate expected minimum value offset
1353 123 50       455 my $expected = $dataPos + $ifdEnd + (defined $makeDiff ? $makeDiff : 4);
1354 123 50       645 $debug and print "$expected expected\n";
1355              
1356             # zero our counters
1357 123         548 my ($countNeg12, $countZero, $countOverlap) = (0, 0, 0);
1358 123         303 my ($valPtr, $last);
1359 123         470 foreach $valPtr (@valPtrs) {
1360 1639 50 0     2932 printf("%d - %d (%d)\n", $valPtr, $valPtr + $$valBlock{$valPtr},
1361             $valPtr - ($last || 0)) if $debug;
1362 1639 100       2923 if (defined $last) {
1363 1516         2152 my $gap = $valPtr - $last;
1364 1516 100 100     3450 if ($gap == 0 or $gap == 1) {
    100 66        
    50          
    100          
1365 1499         1979 ++$countZero;
1366             } elsif ($gap == -12 and not $entryBased) {
1367             # you get this when value offsets are relative to the IFD entry
1368 12         134 ++$countNeg12;
1369             } elsif ($gap < 0) {
1370             # any other negative difference indicates overlapping values
1371 0 0       0 ++$countOverlap if $valPtr; # (but ignore zero value pointers)
1372             } elsif ($gap >= $ifdLen) {
1373             # ignore previous minimum if we took a jump to near the expected value
1374             # (some values can be stored before the IFD)
1375 2 50       158 $minPt = $valPtr if abs($valPtr - $expected) <= 4;
1376             }
1377             # an offset less than 12 is surely garbage, so ignore it
1378 1516 100       2857 $minPt = $valPtr if $minPt < 12;
1379             }
1380 1639         2849 $last = $valPtr + $$valBlock{$valPtr};
1381             }
1382             # could this IFD be using entry-based offsets?
1383 123 100 66     1518 if ((($countNeg12 > $countZero and $$valBlkAdj{MIN} >= $ifdLen - 2) or
      66        
1384             ($$valBlkAdj{MIN} == $ifdLen - 2 or $$valBlkAdj{MIN} == $ifdLen + 2)
1385             ) and $$valBlkAdj{MAX} <= $$dirInfo{DirLen}-2)
1386             {
1387             # looks like these offsets are entry-based, so use the offsets
1388             # which have been correcting for individual entry position
1389 3         5 $entryBased = 1;
1390 3 50       11 $verbose and $et->Warn("$dirName offsets are entry-based",1);
1391             } else {
1392             # calculate offset difference from end of IFD to first value
1393 120         328 $diff = ($minPt - $dataPos) - $ifdEnd;
1394 120         279 $shift = 0;
1395 120 50       387 $countOverlap and $et->Warn("Overlapping $dirName values",1);
1396 120 50       371 if ($entryBased) {
1397 0         0 $et->Warn("$dirName offsets do NOT look entry-based",1);
1398 0         0 undef $entryBased;
1399 0         0 undef $relative;
1400             }
1401             # use PrintIM tag to do special check for correct absolute offsets
1402 120 100       2478 if ($tagPtr{0xe00}) {
1403 26         71 my $ptr = $tagPtr{0xe00} - $dataPos;
1404 26 50 33     726 return 0 if $ptr > 0 and $ptr <= length($$dataPt) - 8 and
      33        
1405             substr($$dataPt, $ptr, 8) eq "PrintIM\0";
1406             }
1407             # allow a range of reasonable differences for Unknown maker notes
1408 94 50 66     529 if ($$dirInfo{FixBase} and $$dirInfo{FixBase} == 2) {
1409 0 0 0     0 return 0 if $diff >=0 and $diff <= 24;
1410             }
1411             # ******** (used for testing to extract differences) ********
1412             # $et->FoundTag('Diff', $diff);
1413             # $et->FoundTag('MakeDiff',$makeDiff);
1414             }
1415             #
1416             # handle entry-based offsets
1417             #
1418 97 100       309 if ($entryBased) {
1419 3 50       9 $debug and print "--> entry-based!\n";
1420             # most of my entry-based samples have first value immediately
1421             # after last IFD entry (ie. no padding or next IFD pointer)
1422 3         9 $makeDiff = 0;
1423 3         5 push @offsets, 4; # but some do have a next IFD pointer
1424             # corrected entry-based offsets are relative to start of first entry
1425 3         10 my $expected = 12 * Get16u($$dirInfo{DataPt}, $dirStart);
1426 3         9 $diff = $$valBlkAdj{MIN} - $expected;
1427             # set up directory to read values with entry-based offsets
1428             # (ignore everything and set base to start of first entry)
1429 3         5 $shift = $dataPos + $dirStart + 2;
1430 3         7 $$dirInfo{Base} += $shift;
1431 3         6 $$dirInfo{DataPos} -= $shift;
1432 3         5 $$dirInfo{EntryBased} = 1;
1433 3         7 $$dirInfo{Relative} = 1; # entry-based offsets are relative
1434 3         7 delete $$dirInfo{FixBase}; # no automatic base fix
1435 3 50       9 undef $fixBase unless $setBase;
1436             }
1437             #
1438             # return without doing shift if offsets look OK
1439             #
1440 97 50       343 unless ($setBase) {
1441             # don't try to fix offsets for whacky cameras
1442 97 50       301 return $shift unless defined $makeDiff;
1443             # normal value data starts 4 bytes after IFD, but allow 0 or 4...
1444 97 100 100     2188 return $shift if $diff == 0 or $diff == 4;
1445             # also check for allowed make-specific differences
1446 3         6 foreach (@offsets) {
1447 3 100       18 return $shift if $diff == $_;
1448             }
1449             }
1450             #
1451             # apply the fix, or issue a warning
1452             #
1453             # use default padding of 4 bytes unless already specified
1454 2 50       4 $makeDiff = 4 unless defined $makeDiff;
1455 2         3 $fix = $makeDiff - $diff; # assume standard diff for this make
1456              
1457 2 50       5 if ($$dirInfo{FixBase}) {
    0          
1458             # set flag if offsets are relative (base is at or above directory start)
1459 2 50       4 if ($dataPos - $fix + $dirStart <= 0) {
1460 0 0       0 $$dirInfo{Relative} = (defined $relative) ? $relative : 1;
1461             }
1462 2 50       3 if ($setBase) {
1463 0         0 $fixedBy = $fixBase;
1464 0         0 $fix += $fixBase;
1465             }
1466             } elsif (defined $fixBase) {
1467 0 0       0 $fix = $fixBase if $fixBase ne '';
1468 0         0 $fixedBy = $fix;
1469             } else {
1470             # print warning unless difference looks reasonable
1471 0 0 0     0 if ($diff < 0 or $diff > 16 or ($diff & 0x01)) {
      0        
1472 0         0 $et->Warn("Possibly incorrect maker notes offsets (fix by $fix?)",1);
1473             }
1474             # don't do the fix (but we already adjusted base if entry-based)
1475 0         0 return $shift;
1476             }
1477 2 50       6 if (defined $fixedBy) {
1478 0         0 $et->Warn("Adjusted $dirName base by $fixedBy",1);
1479 0         0 $$dirInfo{FixedBy} = $fixedBy;
1480             }
1481 2         3 $$dirInfo{Base} += $fix;
1482 2         4 $$dirInfo{DataPos} -= $fix;
1483 2         20 return $fix + $shift;
1484             }
1485              
1486             #------------------------------------------------------------------------------
1487             # Find start of IFD in unknown maker notes
1488             # Inputs: 0) reference to directory information
1489             # Returns: offset to IFD on success, undefined otherwise
1490             # - dirInfo may contain TagInfo reference for tag associated with directory
1491             # - on success, updates DirStart, DirLen, Base and DataPos in dirInfo
1492             # - also sets Relative flag in dirInfo if offsets are relative to IFD
1493             # Note: Changes byte ordering!
1494             sub LocateIFD($$)
1495             {
1496 66     66 0 322 my ($et, $dirInfo) = @_;
1497 66         258 my $dataPt = $$dirInfo{DataPt};
1498 66   100     397 my $dirStart = $$dirInfo{DirStart} || 0;
1499             # (ignore MakerNotes DirLen since sometimes this is incorrect)
1500 66         231 my $size = $$dirInfo{DataLen} - $dirStart;
1501 66 50       347 my $dirLen = defined $$dirInfo{DirLen} ? $$dirInfo{DirLen} : $size;
1502 66         196 my $tagInfo = $$dirInfo{TagInfo};
1503 66         128 my $ifdOffsetPos;
1504             # the IFD should be within the first 32 bytes
1505             # (Kyocera sets the current record at 22 bytes)
1506 66         189 my ($firstTry, $lastTry) = (0, 32);
1507              
1508             # make sure Base and DataPos are defined
1509 66 100       242 $$dirInfo{Base} or $$dirInfo{Base} = 0;
1510 66 100       353 $$dirInfo{DataPos} or $$dirInfo{DataPos} = 0;
1511             #
1512             # use tag information (if provided) to determine directory location
1513             #
1514 66 50 33     473 if ($tagInfo and $$tagInfo{SubDirectory}) {
1515 66         154 my $subdir = $$tagInfo{SubDirectory};
1516 66 100 100     600 unless ($$subdir{ProcessProc} and
      100        
1517             ($$subdir{ProcessProc} eq \&ProcessUnknown or
1518             $$subdir{ProcessProc} eq \&ProcessUnknownOrPreview))
1519             {
1520             # look for the IFD at the "Start" specified in our SubDirectory information
1521 56         129 my $valuePtr = $dirStart;
1522 56         146 my $newStart = $dirStart;
1523 56 100       246 if (defined $$subdir{Start}) {
1524             #### eval Start ($valuePtr)
1525 18         3503 $newStart = eval($$subdir{Start});
1526             }
1527 56 100       300 if ($$subdir{Base}) {
1528             # calculate subdirectory start relative to $base for eval
1529 9         28 my $start = $newStart + $$dirInfo{DataPos};
1530 9   100     43 my $base = $$dirInfo{Base} || 0;
1531             #### eval Base ($start,$base)
1532 9         664 my $baseShift = eval($$subdir{Base});
1533             # shift directory base (note: we may do this again below
1534             # if an OffsetPt is defined, but that doesn't matter since
1535             # the base shift is relative to DataPos, which we set too)
1536 9         49 $$dirInfo{Base} += $baseShift;
1537 9         25 $$dirInfo{DataPos} -= $baseShift;
1538             # this is a relative directory if Base depends on $start
1539 9 50       74 if ($$subdir{Base} =~ /\$start\b/) {
1540 9         34 $$dirInfo{Relative} = 1;
1541             # hack to fix Leica quirk
1542 9 50 33     67 if ($$subdir{ProcessProc} and $$subdir{ProcessProc} eq \&FixLeicaBase) {
1543 0         0 my $oldStart = $$dirInfo{DirStart};
1544 0         0 $$dirInfo{DirStart} = $newStart;
1545 0         0 FixLeicaBase($et, $dirInfo);
1546 0         0 $$dirInfo{DirStart} = $oldStart;
1547             }
1548             }
1549             }
1550             # add offset to the start of the directory if necessary
1551 56 100       212 if ($$subdir{OffsetPt}) {
1552 6 50       35 if ($$subdir{ByteOrder} =~ /^Little/i) {
    0          
1553 6         31 SetByteOrder('II');
1554             } elsif ($$subdir{ByteOrder} =~ /^Big/i) {
1555 0         0 SetByteOrder('MM');
1556             } else {
1557 0         0 warn "Can't have variable byte ordering for SubDirectories using OffsetPt\n";
1558 0         0 return undef;
1559             }
1560             #### eval OffsetPt ($valuePtr)
1561 6         376 $ifdOffsetPos = eval($$subdir{OffsetPt}) - $dirStart;
1562             }
1563             # pinpoint position to look for this IFD
1564 56         208 $firstTry = $lastTry = $newStart - $dirStart;
1565             }
1566             }
1567             #
1568             # scan for something that looks like an IFD
1569             #
1570 66 50       310 if ($dirLen >= 14 + $firstTry) { # minimum size for an IFD
1571 66         144 my $offset;
1572 66         271 IFD_TRY: for ($offset=$firstTry; $offset<=$lastTry; $offset+=2) {
1573 133 50       385 last if $offset + 14 > $dirLen; # 14 bytes is minimum size for an IFD
1574 133         267 my $pos = $dirStart + $offset;
1575             #
1576             # look for a standard TIFF header (Nikon uses it, others may as well),
1577             #
1578 133 50 66     534 if (SetByteOrder(substr($$dataPt, $pos, 2)) and
1579             Get16u($dataPt, $pos + 2) == 0x2a)
1580             {
1581 0         0 $ifdOffsetPos = 4;
1582             }
1583 133 100       419 if (defined $ifdOffsetPos) {
1584             # get pointer to IFD
1585 6         23 my $ptr = Get32u($dataPt, $pos + $ifdOffsetPos);
1586 6 50 33     49 if ($ptr >= $ifdOffsetPos + 4 and $ptr + $offset + 14 <= $dirLen) {
1587             # shift directory start and shorten dirLen accordingly
1588 6         21 $$dirInfo{DirStart} += $ptr + $offset;
1589 6         20 $$dirInfo{DirLen} -= $ptr + $offset;
1590             # shift pointer base to the start of the TIFF header
1591 6         19 my $shift = $$dirInfo{DataPos} + $dirStart + $offset;
1592 6         15 $$dirInfo{Base} += $shift;
1593 6         15 $$dirInfo{DataPos} -= $shift;
1594 6         62 $$dirInfo{Relative} = 1; # set "relative offsets" flag
1595 6         33 return $ptr + $offset;
1596             }
1597 0         0 undef $ifdOffsetPos;
1598             }
1599             #
1600             # look for a standard IFD (starts with 2-byte entry count)
1601             #
1602 127         333 my $num = Get16u($dataPt, $pos);
1603 127 100       374 next unless $num;
1604             # number of entries in an IFD should be between 1 and 255
1605 119 100       531 if (!($num & 0xff)) {
    100          
1606             # lower byte is zero -- byte order could be wrong
1607 9         37 ToggleByteOrder();
1608 9         22 $num >>= 8;
1609             } elsif ($num & 0xff00) {
1610             # upper byte isn't zero -- not an IFD
1611 48         93 next;
1612             }
1613 71         228 my $bytesFromEnd = $size - ($offset + 2 + 12 * $num);
1614 71 50       230 if ($bytesFromEnd < 4) {
1615 0 0 0     0 next unless $bytesFromEnd == 2 or $bytesFromEnd == 0;
1616             }
1617             # do a quick validation of all format types
1618 71         144 my $index;
1619 71         325 for ($index=0; $index<$num; ++$index) {
1620 1663         2498 my $entry = $pos + 2 + 12 * $index;
1621 1663         3180 my $format = Get16u($dataPt, $entry+2);
1622 1663         3581 my $count = Get32u($dataPt, $entry+4);
1623 1663 100       3226 unless ($format) {
1624             # patch for buggy Samsung NX200 JPEG MakerNotes entry count
1625 4 0 33     16 if ($num == 23 and $index == 21 and $$et{Make} eq 'SAMSUNG') {
      33        
1626 0         0 Set16u(21, $dataPt, $pos); # really 21 IFD entries!
1627 0         0 $et->Warn('Fixed incorrect Makernote entry count', 1);
1628 0         0 last;
1629             }
1630             # allow everything to be zero if not first entry
1631             # because some manufacturers pad with null entries
1632 4 50 33     16 next unless $count or $index == 0;
1633             # patch for Canon EOS 40D firmware 1.0.4 bug: allow zero format for last entry
1634 4 50 33     13 next if $index==$num-1 and $$et{Model}=~/EOS 40D/;
1635             }
1636             # patch for Sony cameras like the DSC-P10 that have invalid MakerNote entries
1637 1663 50 66     3403 next if $num == 12 and $$et{Make} eq 'SONY' and $index >= 8;
      33        
1638             # patch for Apple ProRaw DNG which uses format 16 in the maker notes
1639 1663 50 33     3260 next if $format == 16 and $$et{Make} eq 'Apple';
1640             # (would like to verify tag ID, but some manufactures don't
1641             # sort entries in order of tag ID so we don't have much of
1642             # a handle to verify this field)
1643             # verify format
1644 1663 100 100     4935 next IFD_TRY if $format < 1 or $format > 13;
1645             # count must be reasonable (can't test for zero count because
1646             # cameras like the 1DmkIII use this value)
1647 1651 50       3274 next IFD_TRY if $count & 0xff000000;
1648             # extra tests to avoid mis-identifying Samsung makernotes (GT-I9000, etc)
1649 1651 50       4399 next unless $num == 1;
1650 0         0 my $valueSize = $count * $Image::ExifTool::Exif::formatSize[$format];
1651 0 0       0 if ($valueSize > 4) {
1652 0 0       0 next IFD_TRY if $valueSize > $size;
1653 0         0 my $valuePtr = Get32u($dataPt, $entry+8);
1654 0 0       0 next IFD_TRY if $valuePtr > 0x10000;
1655             }
1656             }
1657 59         230 $$dirInfo{DirStart} += $offset; # update directory start
1658 59         190 $$dirInfo{DirLen} -= $offset;
1659 59         355 return $offset; # success!!
1660             }
1661             }
1662 1         3 return undef;
1663             }
1664              
1665             #------------------------------------------------------------------------------
1666             # Fix base offset for Leica maker notes
1667             # Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) tag table ref
1668             # Returns: 1 on success, and updates $dirInfo if necessary for new directory
1669             sub FixLeicaBase($$;$)
1670             {
1671 0     0 0 0 my ($et, $dirInfo, $tagTablePtr) = @_;
1672 0         0 my $dataPt = $$dirInfo{DataPt};
1673 0   0     0 my $dirStart = $$dirInfo{DirStart} || 0;
1674             # get hash of value block positions
1675 0         0 my ($valBlock, $valBlkAdj) = GetValueBlocks($dataPt, $dirStart);
1676 0 0       0 if (%$valBlock) {
1677             # get sorted list of value offsets
1678 0         0 my @valPtrs = sort { $a <=> $b } keys %$valBlock;
  0         0  
1679 0         0 my $numEntries = Get16u($dataPt, $dirStart);
1680 0         0 my $diff = $valPtrs[0] - ($numEntries * 12 + 4);
1681 0 0       0 if ($diff > 8) {
1682 0         0 $$dirInfo{Base} -= 8;
1683 0         0 $$dirInfo{DataPos} += 8;
1684             }
1685             }
1686 0         0 my $success = 1;
1687 0 0       0 if ($tagTablePtr) {
1688 0         0 $success = Image::ExifTool::Exif::ProcessExif($et, $dirInfo, $tagTablePtr);
1689             }
1690 0         0 return $success;
1691             }
1692              
1693             #------------------------------------------------------------------------------
1694             # Process Canon maker notes
1695             # Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) tag table ref
1696             # Returns: 1 on success
1697             sub ProcessCanon($$$)
1698             {
1699 47     47 0 160 my ($et, $dirInfo, $tagTablePtr) = @_;
1700             # identify Canon MakerNote footer in HtmlDump
1701             # (this code moved from FixBase so it also works for Adobe MakN in DNG images)
1702 47 50 33     245 if ($$et{HTML_DUMP} and $$dirInfo{DirLen} > 8) {
1703 0         0 my $dataPos = $$dirInfo{DataPos};
1704 0   0     0 my $dirStart = $$dirInfo{DirStart} || 0;
1705 0         0 my $footerPos = $dirStart + $$dirInfo{DirLen} - 8;
1706 0         0 my $footer = substr(${$$dirInfo{DataPt}}, $footerPos, 8);
  0         0  
1707 0 0 0     0 if ($footer =~ /^(II\x2a\0|MM\0\x2a)/ and substr($footer,0,2) eq GetByteOrder()) {
1708 0         0 my $oldOffset = Get32u(\$footer, 4);
1709 0         0 my $newOffset = $dirStart + $dataPos;
1710 0         0 my $str = sprintf('Original maker note offset: 0x%.4x', $oldOffset);
1711 0 0       0 if ($oldOffset != $newOffset) {
1712 0         0 $str .= sprintf("\nCurrent maker note offset: 0x%.4x", $newOffset);
1713             }
1714 0   0     0 my $filePos = ($$dirInfo{Base} || 0) + $dataPos + $footerPos;
1715 0         0 $et->HDump($filePos, 8, '[Canon MakerNotes footer]', $str);
1716             }
1717             }
1718             # process as normal
1719 47         661 return Image::ExifTool::Exif::ProcessExif($et, $dirInfo, $tagTablePtr);
1720             }
1721              
1722             #------------------------------------------------------------------------------
1723             # Process GE type 2 maker notes
1724             # Inputs: 0) ExifTool object ref, 1) DirInfo ref, 2) tag table ref
1725             # Returns: 1 on success
1726             sub ProcessGE2($$$)
1727             {
1728 0     0 0 0 my ($et, $dirInfo, $tagTablePtr) = @_;
1729 0 0       0 my $dataPt = $$dirInfo{DataPt} or return 0;
1730 0   0     0 my $dirStart = $$dirInfo{DirStart} || 0;
1731              
1732             # these maker notes are missing the IFD entry count, but they
1733             # always have 25 entries, so write the entry count manually
1734 0         0 Set16u(25, $dataPt, $dirStart);
1735 0         0 return Image::ExifTool::Exif::ProcessExif($et, $dirInfo, $tagTablePtr);
1736             }
1737              
1738             #------------------------------------------------------------------------------
1739             # Process broken Kodak type 8b maker notes
1740             # Inputs: 0) ExifTool object ref, 1) DirInfo ref, 2) tag table ref
1741             # Returns: 1 on success
1742             sub ProcessKodakPatch($$$)
1743             {
1744 0     0 0 0 my ($et, $dirInfo, $tagTablePtr) = @_;
1745 0 0       0 my $dataPt = $$dirInfo{DataPt} or return 0;
1746 0   0     0 my $dirStart = $$dirInfo{DirStart} || 0;
1747              
1748             # these maker notes have an 2 extra null bytes either before or after the entry count,
1749             # so fix this by making a 2-byte entry count just before the first IFD entry
1750 0 0       0 return 0 unless $$dirInfo{DirLen} >= 4;
1751 0         0 my $t1 = Get16u($dataPt,$dirStart);
1752 0         0 my $t2 = Get16u($dataPt,$dirStart+2);
1753 0   0     0 Set16u($t1 || $t2, $dataPt, $dirStart+2);
1754 0         0 $$dirInfo{DirStart} += 2;
1755 0         0 return Image::ExifTool::Exif::ProcessExif($et, $dirInfo, $tagTablePtr);
1756             }
1757              
1758             #------------------------------------------------------------------------------
1759             # Process unknown maker notes or PreviewImage
1760             # Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) tag table ref
1761             # Returns: 1 on success, and updates $dirInfo if necessary for new directory
1762             sub ProcessUnknownOrPreview($$$)
1763             {
1764 3     3 0 9 my ($et, $dirInfo, $tagTablePtr) = @_;
1765 3         9 my $dataPt = $$dirInfo{DataPt};
1766 3         9 my $dirStart = $$dirInfo{DirStart};
1767 3         8 my $dirLen = $$dirInfo{DirLen};
1768             # check to see if this is a preview image
1769 3 50 33     35 if ($dirLen > 6 and substr($$dataPt, $dirStart, 3) eq "\xff\xd8\xff") {
1770 0         0 $et->VerboseDir('PreviewImage');
1771 0 0       0 if ($$et{HTML_DUMP}) {
1772 0         0 my $pos = $$dirInfo{DataPos} + $$dirInfo{Base} + $dirStart;
1773 0         0 $et->HDump($pos, $dirLen, '(MakerNotes:PreviewImage data)', "Size: $dirLen bytes")
1774             }
1775 0         0 $et->FoundTag('PreviewImage', substr($$dataPt, $dirStart, $dirLen));
1776 0         0 return 1;
1777             }
1778 3         12 return ProcessUnknown($et, $dirInfo, $tagTablePtr);
1779             }
1780              
1781             #------------------------------------------------------------------------------
1782             # Write unknown maker notes or PreviewImage
1783             # Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) tag table ref
1784             # Returns: directory data, '' to delete, or undef on error
1785             sub WriteUnknownOrPreview($$$)
1786             {
1787 1     1 0 3 my ($et, $dirInfo, $tagTablePtr) = @_;
1788 1         2 my $dataPt = $$dirInfo{DataPt};
1789 1         2 my $dirStart = $$dirInfo{DirStart};
1790 1         3 my $dirLen = $$dirInfo{DirLen};
1791 1         2 my $newVal;
1792             # check to see if this is a preview image
1793 1 50 33     7 if ($dirLen > 6 and substr($$dataPt, $dirStart, 3) eq "\xff\xd8\xff") {
1794 0 0       0 if ($$et{NEW_VALUE}{$Image::ExifTool::Extra{PreviewImage}}) {
1795             # write or delete new preview (if deleted, it can't currently be added back again)
1796 0   0     0 $newVal = $et->GetNewValue('PreviewImage') || '';
1797 0 0       0 if ($et->Options('Verbose') > 1) {
1798 0         0 $et->VerboseValue("- MakerNotes:PreviewImage", substr($$dataPt, $dirStart, $dirLen));
1799 0 0       0 $et->VerboseValue("+ MakerNotes:PreviewImage", $newVal) if $newVal;
1800             }
1801 0         0 ++$$et{CHANGED};
1802             } else {
1803 0         0 $newVal = substr($$dataPt, $dirStart, $dirLen);
1804             }
1805             } else {
1806             # rewrite MakerNote IFD
1807 1         93 $newVal = Image::ExifTool::Exif::WriteExif($et, $dirInfo, $tagTablePtr);
1808             }
1809 1         4 return $newVal;
1810             }
1811              
1812             #------------------------------------------------------------------------------
1813             # Process unknown maker notes assuming it is in EXIF IFD format
1814             # Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) tag table ref
1815             # Returns: 1 on success, and updates $dirInfo if necessary for new directory
1816             sub ProcessUnknown($$$)
1817             {
1818 7     7 0 22 my ($et, $dirInfo, $tagTablePtr) = @_;
1819 7         14 my $success = 0;
1820              
1821 7         35 my $loc = LocateIFD($et, $dirInfo);
1822 7 100       26 if (defined $loc) {
1823 6         22 $$et{UnknownByteOrder} = GetByteOrder();
1824 6 50       30 if ($et->Options('Verbose') > 1) {
1825 0         0 my $out = $et->Options('TextOut');
1826 0         0 my $indent = $$et{INDENT};
1827 0         0 $indent =~ s/\| $/ /;
1828             printf $out "${indent}Found IFD at offset 0x%.4x in maker notes:\n",
1829 0         0 $$dirInfo{DirStart} + $$dirInfo{DataPos} + $$dirInfo{Base};
1830             }
1831 6         203 $success = Image::ExifTool::Exif::ProcessExif($et, $dirInfo, $tagTablePtr);
1832             } else {
1833 1         3 $$et{UnknownByteOrder} = ''; # indicates we tried but didn't set byte order
1834 1         6 $et->Warn("Unrecognized $$dirInfo{DirName}", 1);
1835             }
1836 7         25 return $success;
1837             }
1838              
1839              
1840             1; # end
1841              
1842             __END__